Contract Name:
MainchainGatewayManager
Contract Source Code:
File 1 of 1 : MainchainGatewayManager
// File: @axie/contract-library/contracts/cryptography/ECVerify.sol
pragma solidity ^0.5.2;
library ECVerify {
enum SignatureMode {
EIP712,
GETH,
TREZOR
}
function recover(bytes32 _hash, bytes memory _signature) internal pure returns (address _signer) {
return recover(_hash, _signature, 0);
}
// solium-disable-next-line security/no-assign-params
function recover(bytes32 _hash, bytes memory _signature, uint256 _index) internal pure returns (address _signer) {
require(_signature.length >= _index + 66);
SignatureMode _mode = SignatureMode(uint8(_signature[_index]));
bytes32 _r;
bytes32 _s;
uint8 _v;
// solium-disable-next-line security/no-inline-assembly
assembly {
_r := mload(add(_signature, add(_index, 33)))
_s := mload(add(_signature, add(_index, 65)))
_v := and(255, mload(add(_signature, add(_index, 66))))
}
if (_v < 27) {
_v += 27;
}
require(_v == 27 || _v == 28);
if (_mode == SignatureMode.GETH) {
_hash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash));
} else if (_mode == SignatureMode.TREZOR) {
_hash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n\x20", _hash));
}
return ecrecover(_hash, _v, _r, _s);
}
function ecverify(bytes32 _hash, bytes memory _signature, address _signer) internal pure returns (bool _valid) {
return _signer == recover(_hash, _signature);
}
}
// File: @axie/contract-library/contracts/math/SafeMath.sol
pragma solidity ^0.5.2;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = a + b;
require(c >= a);
}
function sub(uint256 a, uint256 b) internal pure returns (uint256 c) {
require(b <= a);
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
if (a == 0) {
return 0;
}
c = a * b;
require(c / a == b);
}
function div(uint256 a, uint256 b) internal pure returns (uint256 c) {
// Since Solidity automatically asserts when dividing by 0,
// but we only need it to revert.
require(b > 0);
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256 c) {
// Same reason as `div`.
require(b > 0);
return a % b;
}
function ceilingDiv(uint256 a, uint256 b) internal pure returns (uint256 c) {
return add(div(a, b), mod(a, b) > 0 ? 1 : 0);
}
function subU64(uint64 a, uint64 b) internal pure returns (uint64 c) {
require(b <= a);
return a - b;
}
function addU8(uint8 a, uint8 b) internal pure returns (uint8 c) {
c = a + b;
require(c >= a);
}
}
// File: @axie/contract-library/contracts/token/erc20/IERC20.sol
pragma solidity ^0.5.2;
interface IERC20 {
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
function totalSupply() external view returns (uint256 _supply);
function balanceOf(address _owner) external view returns (uint256 _balance);
function approve(address _spender, uint256 _value) external returns (bool _success);
function allowance(address _owner, address _spender) external view returns (uint256 _value);
function transfer(address _to, uint256 _value) external returns (bool _success);
function transferFrom(address _from, address _to, uint256 _value) external returns (bool _success);
}
// File: @axie/contract-library/contracts/token/erc20/IERC20Mintable.sol
pragma solidity ^0.5.2;
interface IERC20Mintable {
function mint(address _to, uint256 _value) external returns (bool _success);
}
// File: @axie/contract-library/contracts/token/erc721/IERC721.sol
pragma solidity ^0.5.2;
interface IERC721 {
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
function balanceOf(address _owner) external view returns (uint256 _balance);
function ownerOf(uint256 _tokenId) external view returns (address _owner);
function approve(address _to, uint256 _tokenId) external;
function getApproved(uint256 _tokenId) external view returns (address _operator);
function setApprovalForAll(address _operator, bool _approved) external;
function isApprovedForAll(address _owner, address _operator) external view returns (bool _approved);
function transferFrom(address _from, address _to, uint256 _tokenId) external;
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external;
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata _data) external;
}
// File: @axie/contract-library/contracts/token/erc721/IERC721Mintable.sol
pragma solidity ^0.5.2;
interface IERC721Mintable {
function mint(address _to, uint256 _tokenId) external returns (bool);
function mintNew(address _to) external returns (uint256 _tokenId);
}
// File: @axie/contract-library/contracts/util/AddressUtils.sol
pragma solidity ^0.5.2;
library AddressUtils {
function toPayable(address _address) internal pure returns (address payable _payable) {
return address(uint160(_address));
}
function isContract(address _address) internal view returns (bool _correct) {
uint256 _size;
// solium-disable-next-line security/no-inline-assembly
assembly { _size := extcodesize(_address) }
return _size > 0;
}
}
// File: @axie/contract-library/contracts/token/erc20/ERC20.sol
pragma solidity ^0.5.2;
contract ERC20 is IERC20 {
using SafeMath for uint256;
uint256 public totalSupply;
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) public allowance;
function approve(address _spender, uint256 _value) public returns (bool _success) {
allowance[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function transfer(address _to, uint256 _value) public returns (bool _success) {
require(_to != address(0));
balanceOf[msg.sender] = balanceOf[msg.sender].sub(_value);
balanceOf[_to] = balanceOf[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool _success) {
require(_to != address(0));
balanceOf[_from] = balanceOf[_from].sub(_value);
balanceOf[_to] = balanceOf[_to].add(_value);
allowance[_from][msg.sender] = allowance[_from][msg.sender].sub(_value);
emit Transfer(_from, _to, _value);
return true;
}
}
// File: @axie/contract-library/contracts/token/erc20/IERC20Detailed.sol
pragma solidity ^0.5.2;
interface IERC20Detailed {
function name() external view returns (string memory _name);
function symbol() external view returns (string memory _symbol);
function decimals() external view returns (uint8 _decimals);
}
// File: @axie/contract-library/contracts/token/erc20/ERC20Detailed.sol
pragma solidity ^0.5.2;
contract ERC20Detailed is ERC20, IERC20Detailed {
string public name;
string public symbol;
uint8 public decimals;
constructor(string memory _name, string memory _symbol, uint8 _decimals) public {
name = _name;
symbol = _symbol;
decimals = _decimals;
}
}
// File: @axie/contract-library/contracts/access/HasAdmin.sol
pragma solidity ^0.5.2;
contract HasAdmin {
event AdminChanged(address indexed _oldAdmin, address indexed _newAdmin);
event AdminRemoved(address indexed _oldAdmin);
address public admin;
modifier onlyAdmin {
require(msg.sender == admin);
_;
}
constructor() internal {
admin = msg.sender;
emit AdminChanged(address(0), admin);
}
function changeAdmin(address _newAdmin) external onlyAdmin {
require(_newAdmin != address(0));
emit AdminChanged(admin, _newAdmin);
admin = _newAdmin;
}
function removeAdmin() external onlyAdmin {
emit AdminRemoved(admin);
admin = address(0);
}
}
// File: @axie/contract-library/contracts/access/HasMinters.sol
pragma solidity ^0.5.2;
contract HasMinters is HasAdmin {
event MinterAdded(address indexed _minter);
event MinterRemoved(address indexed _minter);
address[] public minters;
mapping (address => bool) public minter;
modifier onlyMinter {
require(minter[msg.sender]);
_;
}
function addMinters(address[] memory _addedMinters) public onlyAdmin {
address _minter;
for (uint256 i = 0; i < _addedMinters.length; i++) {
_minter = _addedMinters[i];
if (!minter[_minter]) {
minters.push(_minter);
minter[_minter] = true;
emit MinterAdded(_minter);
}
}
}
function removeMinters(address[] memory _removedMinters) public onlyAdmin {
address _minter;
for (uint256 i = 0; i < _removedMinters.length; i++) {
_minter = _removedMinters[i];
if (minter[_minter]) {
minter[_minter] = false;
emit MinterRemoved(_minter);
}
}
uint256 i = 0;
while (i < minters.length) {
_minter = minters[i];
if (!minter[_minter]) {
minters[i] = minters[minters.length - 1];
delete minters[minters.length - 1];
minters.length--;
} else {
i++;
}
}
}
function isMinter(address _addr) public view returns (bool) {
return minter[_addr];
}
}
// File: @axie/contract-library/contracts/token/erc20/ERC20Mintable.sol
pragma solidity ^0.5.2;
contract ERC20Mintable is HasMinters, ERC20 {
function mint(address _to, uint256 _value) public onlyMinter returns (bool _success) {
return _mint(_to, _value);
}
function _mint(address _to, uint256 _value) internal returns (bool success) {
totalSupply = totalSupply.add(_value);
balanceOf[_to] = balanceOf[_to].add(_value);
emit Transfer(address(0), _to, _value);
return true;
}
}
// File: contracts/chain/mainchain/WETH.sol
pragma solidity ^0.5.17;
contract WETH is ERC20Detailed {
event Deposit(
address _sender,
uint256 _value
);
event Withdrawal(
address _sender,
uint256 _value
);
constructor () ERC20Detailed("Wrapped Ether", "WETH", 18)
public
{}
function deposit()
external
payable
{
balanceOf[msg.sender] += msg.value;
emit Deposit(msg.sender, msg.value);
}
function withdraw(uint256 _wad)
external
{
require(balanceOf[msg.sender] >= _wad);
balanceOf[msg.sender] -= _wad;
msg.sender.transfer(_wad);
emit Withdrawal(msg.sender, _wad);
}
}
// File: @axie/contract-library/contracts/proxy/ProxyStorage.sol
pragma solidity ^0.5.2;
/**
* @title ProxyStorage
* @dev Store the address of logic contact that the proxy should forward to.
*/
contract ProxyStorage is HasAdmin {
address internal _proxyTo;
}
// File: @axie/contract-library/contracts/lifecycle/Pausable.sol
pragma solidity ^0.5.2;
contract Pausable is HasAdmin {
event Paused();
event Unpaused();
bool public paused;
modifier whenNotPaused() {
require(!paused);
_;
}
modifier whenPaused() {
require(paused);
_;
}
function pause() public onlyAdmin whenNotPaused {
paused = true;
emit Paused();
}
function unpause() public onlyAdmin whenPaused {
paused = false;
emit Unpaused();
}
}
// File: contracts/chain/common/IValidator.sol
pragma solidity ^0.5.17;
contract IValidator {
event ValidatorAdded(uint256 indexed _id, address indexed _validator);
event ValidatorRemoved(uint256 indexed _id, address indexed _validator);
event ThresholdUpdated(
uint256 indexed _id,
uint256 indexed _numerator,
uint256 indexed _denominator,
uint256 _previousNumerator,
uint256 _previousDenominator
);
function isValidator(address _addr) public view returns (bool);
function getValidators() public view returns (address[] memory _validators);
function checkThreshold(uint256 _voteCount) public view returns (bool);
}
// File: contracts/chain/common/Validator.sol
pragma solidity ^0.5.17;
contract Validator is IValidator {
using SafeMath for uint256;
mapping(address => bool) validatorMap;
address[] public validators;
uint256 public validatorCount;
uint256 public num;
uint256 public denom;
constructor(address[] memory _validators, uint256 _num, uint256 _denom)
public
{
validators = _validators;
validatorCount = _validators.length;
for (uint256 _i = 0; _i < validatorCount; _i++) {
address _validator = _validators[_i];
validatorMap[_validator] = true;
}
num = _num;
denom = _denom;
}
function isValidator(address _addr)
public
view
returns (bool)
{
return validatorMap[_addr];
}
function getValidators()
public
view
returns (address[] memory _validators)
{
_validators = validators;
}
function checkThreshold(uint256 _voteCount)
public
view
returns (bool)
{
return _voteCount.mul(denom) >= num.mul(validatorCount);
}
function _addValidator(uint256 _id, address _validator)
internal
{
require(!validatorMap[_validator]);
validators.push(_validator);
validatorMap[_validator] = true;
validatorCount++;
emit ValidatorAdded(_id, _validator);
}
function _removeValidator(uint256 _id, address _validator)
internal
{
require(isValidator(_validator));
uint256 _index;
for (uint256 _i = 0; _i < validatorCount; _i++) {
if (validators[_i] == _validator) {
_index = _i;
break;
}
}
validatorMap[_validator] = false;
validators[_index] = validators[validatorCount - 1];
validators.pop();
validatorCount--;
emit ValidatorRemoved(_id, _validator);
}
function _updateQuorum(uint256 _id, uint256 _numerator, uint256 _denominator)
internal
{
require(_numerator <= _denominator);
uint256 _previousNumerator = num;
uint256 _previousDenominator = denom;
num = _numerator;
denom = _denominator;
emit ThresholdUpdated(
_id,
_numerator,
_denominator,
_previousNumerator,
_previousDenominator
);
}
}
// File: contracts/chain/mainchain/MainchainValidator.sol
pragma solidity ^0.5.17;
/**
* @title Validator
* @dev Simple validator contract
*/
contract MainchainValidator is Validator, HasAdmin {
uint256 nonce;
constructor(
address[] memory _validators,
uint256 _num,
uint256 _denom
) Validator(_validators, _num, _denom) public {
}
function addValidators(address[] calldata _validators) external onlyAdmin {
for (uint256 _i; _i < _validators.length; ++_i) {
_addValidator(nonce++, _validators[_i]);
}
}
function removeValidator(address _validator) external onlyAdmin {
_removeValidator(nonce++, _validator);
}
function updateQuorum(uint256 _numerator, uint256 _denominator) external onlyAdmin {
_updateQuorum(nonce++, _numerator, _denominator);
}
}
// File: contracts/chain/common/Registry.sol
pragma solidity ^0.5.17;
contract Registry is HasAdmin {
event ContractAddressUpdated(
string indexed _name,
bytes32 indexed _code,
address indexed _newAddress
);
event TokenMapped(
address indexed _mainchainToken,
address indexed _sidechainToken,
uint32 _standard
);
string public constant GATEWAY = "GATEWAY";
string public constant WETH_TOKEN = "WETH_TOKEN";
string public constant VALIDATOR = "VALIDATOR";
string public constant ACKNOWLEDGEMENT = "ACKNOWLEDGEMENT";
struct TokenMapping {
address mainchainToken;
address sidechainToken;
uint32 standard; // 20, 721 or any other standards
}
mapping(bytes32 => address) public contractAddresses;
mapping(address => TokenMapping) public mainchainMap;
mapping(address => TokenMapping) public sidechainMap;
function getContract(string calldata _name)
external
view
returns (address _address)
{
bytes32 _code = getCode(_name);
_address = contractAddresses[_code];
require(_address != address(0));
}
function isTokenMapped(address _token, uint32 _standard, bool _isMainchain)
external
view
returns (bool)
{
TokenMapping memory _mapping = _getTokenMapping(_token, _isMainchain);
return _mapping.mainchainToken != address(0) &&
_mapping.sidechainToken != address(0) &&
_mapping.standard == _standard;
}
function updateContract(string calldata _name, address _newAddress)
external
onlyAdmin
{
bytes32 _code = getCode(_name);
contractAddresses[_code] = _newAddress;
emit ContractAddressUpdated(_name, _code, _newAddress);
}
function mapToken(address _mainchainToken, address _sidechainToken, uint32 _standard)
external
onlyAdmin
{
TokenMapping memory _map = TokenMapping(
_mainchainToken,
_sidechainToken,
_standard
);
mainchainMap[_mainchainToken] = _map;
sidechainMap[_sidechainToken] = _map;
emit TokenMapped(
_mainchainToken,
_sidechainToken,
_standard
);
}
function clearMapToken(address _mainchainToken, address _sidechainToken)
external
onlyAdmin
{
TokenMapping storage _mainchainMap = mainchainMap[_mainchainToken];
_clearMapEntry(_mainchainMap);
TokenMapping storage _sidechainMap = sidechainMap[_sidechainToken];
_clearMapEntry(_sidechainMap);
}
function getMappedToken(
address _token,
bool _isMainchain
)
external
view
returns (
address _mainchainToken,
address _sidechainToken,
uint32 _standard
)
{
TokenMapping memory _mapping = _getTokenMapping(_token, _isMainchain);
_mainchainToken = _mapping.mainchainToken;
_sidechainToken = _mapping.sidechainToken;
_standard = _mapping.standard;
}
function getCode(string memory _name)
public
pure
returns (bytes32)
{
return keccak256(abi.encodePacked(_name));
}
function _getTokenMapping(
address _token,
bool isMainchain
)
internal
view
returns (TokenMapping memory _mapping)
{
if (isMainchain) {
_mapping = mainchainMap[_token];
} else {
_mapping = sidechainMap[_token];
}
}
function _clearMapEntry(TokenMapping storage _entry)
internal
{
_entry.mainchainToken = address(0);
_entry.sidechainToken = address(0);
_entry.standard = 0;
}
}
// File: contracts/chain/mainchain/MainchainGatewayStorage.sol
pragma solidity ^0.5.17;
/**
* @title GatewayStorage
* @dev Storage of deposit and withdraw information.
*/
contract MainchainGatewayStorage is ProxyStorage, Pausable {
event TokenDeposited(
uint256 indexed _depositId,
address indexed _owner,
address indexed _tokenAddress,
address _sidechainAddress,
uint32 _standard,
uint256 _tokenNumber // ERC-20 amount or ERC721 tokenId
);
event TokenWithdrew(
uint256 indexed _withdrawId,
address indexed _owner,
address indexed _tokenAddress,
uint256 _tokenNumber
);
struct DepositEntry {
address owner;
address tokenAddress;
address sidechainAddress;
uint32 standard;
uint256 tokenNumber;
}
struct WithdrawalEntry {
address owner;
address tokenAddress;
uint256 tokenNumber;
}
Registry public registry;
uint256 public depositCount;
DepositEntry[] public deposits;
mapping(uint256 => WithdrawalEntry) public withdrawals;
function updateRegistry(address _registry) external onlyAdmin {
registry = Registry(_registry);
}
}
// File: contracts/chain/mainchain/MainchainGatewayManager.sol
pragma solidity ^0.5.17;
/**
* @title MainchainGatewayManager
* @dev Logic to handle deposits and withdrawl on Mainchain.
*/
contract MainchainGatewayManager is MainchainGatewayStorage {
using AddressUtils for address;
using SafeMath for uint256;
using ECVerify for bytes32;
modifier onlyMappedToken(address _token, uint32 _standard) {
require(
registry.isTokenMapped(_token, _standard, true),
"MainchainGatewayManager: Token is not mapped"
);
_;
}
modifier onlyNewWithdrawal(uint256 _withdrawalId) {
WithdrawalEntry storage _entry = withdrawals[_withdrawalId];
require(_entry.owner == address(0) && _entry.tokenAddress == address(0));
_;
}
// Should be able to withdraw from WETH
function()
external
payable
{}
function depositEth()
external
whenNotPaused
payable
returns (uint256)
{
return depositEthFor(msg.sender);
}
function depositERC20(address _token, uint256 _amount)
external
whenNotPaused
returns (uint256)
{
return depositERC20For(msg.sender, _token, _amount);
}
function depositERC721(address _token, uint256 _tokenId)
external
whenNotPaused
returns (uint256)
{
return depositERC721For(msg.sender, _token, _tokenId);
}
function depositEthFor(address _owner)
public
whenNotPaused
payable
returns (uint256)
{
address _weth = registry.getContract(registry.WETH_TOKEN());
WETH(_weth).deposit.value(msg.value)();
return _createDepositEntry(_owner, _weth, 20, msg.value);
}
function depositERC20For(address _user, address _token, uint256 _amount)
public
whenNotPaused
returns (uint256)
{
require(
IERC20(_token).transferFrom(msg.sender, address(this), _amount),
"MainchainGatewayManager: ERC-20 token transfer failed"
);
return _createDepositEntry(_user, _token, 20, _amount);
}
function depositERC721For(address _user, address _token, uint256 _tokenId)
public
whenNotPaused
returns (uint256)
{
IERC721(_token).transferFrom(msg.sender, address(this), _tokenId);
return _createDepositEntry(_user, _token, 721, _tokenId);
}
function depositBulkFor(
address _user,
address[] memory _tokens,
uint256[] memory _tokenNumbers
)
public
whenNotPaused
{
require(_tokens.length == _tokenNumbers.length);
for (uint256 _i = 0; _i < _tokens.length; _i++) {
address _token = _tokens[_i];
uint256 _tokenNumber = _tokenNumbers[_i];
(,, uint32 _standard) = registry.getMappedToken(_token, true);
if (_standard == 20) {
depositERC20For(_user, _token, _tokenNumber);
} else if (_standard == 721) {
depositERC721For(_user, _token, _tokenNumber);
} else {
revert("Token is not mapped or token type not supported");
}
}
}
function withdrawToken(
uint256 _withdrawalId,
address _token,
uint256 _amount,
bytes memory _signatures
)
public
whenNotPaused
{
withdrawTokenFor(
_withdrawalId,
msg.sender,
_token,
_amount,
_signatures
);
}
function withdrawTokenFor(
uint256 _withdrawalId,
address _user,
address _token,
uint256 _amount,
bytes memory _signatures
)
public
whenNotPaused
{
(,, uint32 _tokenType) = registry.getMappedToken(_token, true);
if (_tokenType == 20) {
withdrawERC20For(
_withdrawalId,
_user,
_token,
_amount,
_signatures
);
} else if (_tokenType == 721) {
withdrawERC721For(
_withdrawalId,
_user,
_token,
_amount,
_signatures
);
}
}
function withdrawERC20(
uint256 _withdrawalId,
address _token,
uint256 _amount,
bytes memory _signatures
)
public
whenNotPaused
{
withdrawERC20For(
_withdrawalId,
msg.sender,
_token,
_amount,
_signatures
);
}
function withdrawERC20For(
uint256 _withdrawalId,
address _user,
address _token,
uint256 _amount,
bytes memory _signatures
)
public
whenNotPaused
onlyMappedToken(_token, 20)
{
bytes32 _hash = keccak256(
abi.encodePacked(
"withdrawERC20",
_withdrawalId,
_user,
_token,
_amount
)
);
require(verifySignatures(_hash, _signatures));
if (_token == registry.getContract(registry.WETH_TOKEN())) {
_withdrawETHFor(_user, _amount);
} else {
uint256 _gatewayBalance = IERC20(_token).balanceOf(address(this));
if (_gatewayBalance < _amount) {
require(
IERC20Mintable(_token).mint(address(this), _amount.sub(_gatewayBalance)),
"MainchainGatewayManager: Minting ERC20 token to gateway failed"
);
}
require(IERC20(_token).transfer(_user, _amount), "Transfer failed");
}
_insertWithdrawalEntry(
_withdrawalId,
_user,
_token,
_amount
);
}
function withdrawERC721(
uint256 _withdrawalId,
address _token,
uint256 _tokenId,
bytes memory _signatures
)
public
whenNotPaused
{
withdrawERC721For(
_withdrawalId,
msg.sender,
_token,
_tokenId,
_signatures
);
}
function withdrawERC721For(
uint256 _withdrawalId,
address _user,
address _token,
uint256 _tokenId,
bytes memory _signatures
)
public
whenNotPaused
onlyMappedToken(_token, 721)
{
bytes32 _hash = keccak256(
abi.encodePacked(
"withdrawERC721",
_withdrawalId,
_user,
_token,
_tokenId
)
);
require(verifySignatures(_hash, _signatures));
if (!_tryERC721TransferFrom(_token, address(this), _user, _tokenId)) {
require(
IERC721Mintable(_token).mint(_user, _tokenId),
"MainchainGatewayManager: Minting ERC721 token to gateway failed"
);
}
_insertWithdrawalEntry(_withdrawalId, _user, _token, _tokenId);
}
/**
* @dev returns true if there is enough signatures from validators.
*/
function verifySignatures(
bytes32 _hash,
bytes memory _signatures
)
public
view
returns (bool)
{
uint256 _signatureCount = _signatures.length.div(66);
Validator _validator = Validator(registry.getContract(registry.VALIDATOR()));
uint256 _validatorCount = 0;
address _lastSigner = address(0);
for (uint256 i = 0; i < _signatureCount; i++) {
address _signer = _hash.recover(_signatures, i.mul(66));
if (_validator.isValidator(_signer)) {
_validatorCount++;
}
// Prevent duplication of signatures
require(_signer > _lastSigner);
_lastSigner = _signer;
}
return _validator.checkThreshold(_validatorCount);
}
function _createDepositEntry(
address _owner,
address _token,
uint32 _standard,
uint256 _number
)
internal
onlyMappedToken(_token, _standard)
returns (uint256 _depositId)
{
(,address _sidechainToken, uint32 _tokenStandard) = registry.getMappedToken(_token, true);
require(_standard == _tokenStandard);
DepositEntry memory _entry = DepositEntry(
_owner,
_token,
_sidechainToken,
_standard,
_number
);
deposits.push(_entry);
_depositId = depositCount++;
emit TokenDeposited(
_depositId,
_owner,
_token,
_sidechainToken,
_standard,
_number
);
}
function _insertWithdrawalEntry(
uint256 _withdrawalId,
address _owner,
address _token,
uint256 _number
)
internal
onlyNewWithdrawal(_withdrawalId)
{
WithdrawalEntry memory _entry = WithdrawalEntry(
_owner,
_token,
_number
);
withdrawals[_withdrawalId] = _entry;
emit TokenWithdrew(_withdrawalId, _owner, _token, _number);
}
function _withdrawETHFor(
address _user,
uint256 _amount
)
internal
{
address _weth = registry.getContract(registry.WETH_TOKEN());
WETH(_weth).withdraw(_amount);
_user.toPayable().transfer(_amount);
}
// See more here https://blog.polymath.network/try-catch-in-solidity-handling-the-revert-exception-f53718f76047
function _tryERC721TransferFrom(
address _token,
address _from,
address _to,
uint256 _tokenId
)
internal
returns (bool)
{
(bool success,) = _token.call(
abi.encodeWithSelector(
IERC721(_token).transferFrom.selector, _from, _to, _tokenId
)
);
return success;
}
}