Transaction Hash:
Block:
12825120 at Jul-14-2021 12:25:01 PM +UTC
Transaction Fee:
0.004939112 ETH
$9.40
Gas Used:
145,268 Gas / 34 Gwei
Emitted Events:
211 |
SmoothLovePotion.Transfer( _from=[Sender] 0x7ac4d324fb170231a334f5d7d0b916c98031169c, _to=[Receiver] MainchainGatewayProxy, _value=70 )
|
212 |
MainchainGatewayProxy.TokenDeposited( _depositId=428067, _owner=0xE0eFa072...25F9f8FCE, _tokenAddress=SmoothLovePotion, _sidechainAddress=0xa8754b9F...a12cD2014, _standard=20, _tokenNumber=70 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x1A2a1c93...a9DD454F2 | (Axie Infinity: Ronin Bridge) | ||||
0x7ac4D324...98031169c |
0.145738214430422815 Eth
Nonce: 10
|
0.140799102430422815 Eth
Nonce: 11
| 0.004939112 | ||
0xCC8Fa225...5D6cAAa25 | |||||
0xEA674fdD...16B898ec8
Miner
| (Ethermine) | 1,927.22744928238539832 Eth | 1,927.23238839438539832 Eth | 0.004939112 |
Execution Trace
MainchainGatewayProxy.85eb3a35( )
MainchainGatewayManager.depositERC20For( _user=0xE0eFa07296395Ce9ff7f53C8882B1E825F9f8FCE, _token=0xCC8Fa225D80b9c7D42F96e9570156c65D6cAAa25, _amount=70 ) => ( 428067 )
-
SmoothLovePotion.transferFrom( _from=0x7ac4D324fb170231A334F5d7d0B916c98031169c, _to=0x1A2a1c938CE3eC39b6D47113c7955bAa9DD454F2, _value=70 ) => ( _success=True )
-
Registry.isTokenMapped( _token=0xCC8Fa225D80b9c7D42F96e9570156c65D6cAAa25, _standard=20, _isMainchain=True ) => ( True )
-
Registry.getMappedToken( _token=0xCC8Fa225D80b9c7D42F96e9570156c65D6cAAa25, _isMainchain=True ) => ( _mainchainToken=0xCC8Fa225D80b9c7D42F96e9570156c65D6cAAa25, _sidechainToken=0xa8754b9Fa15fc18BB59458815510E40a12cD2014, _standard=20 )
-
depositERC20For[MainchainGatewayManager (ln:911)]
transferFrom[MainchainGatewayManager (ln:917)]
_createDepositEntry[MainchainGatewayManager (ln:920)]
getMappedToken[MainchainGatewayManager (ln:1161)]
DepositEntry[MainchainGatewayManager (ln:1164)]
push[MainchainGatewayManager (ln:1172)]
TokenDeposited[MainchainGatewayManager (ln:1175)]
File 1 of 4: MainchainGatewayProxy
File 2 of 4: SmoothLovePotion
File 3 of 4: MainchainGatewayManager
File 4 of 4: Registry
// 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/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/proxy/Proxy.sol pragma solidity ^0.5.2; /** * @title Proxy * @dev Gives the possibility to delegate any call to a foreign implementation. */ contract Proxy is ProxyStorage { event ProxyUpdated(address indexed _new, address indexed _old); constructor(address _proxyTo) public { updateProxyTo(_proxyTo); } /** * @dev Tells the address of the implementation where every call will be delegated. * @return address of the implementation to which it will be delegated */ function implementation() public view returns (address) { return _proxyTo; } /** * @dev See more at: https://eips.ethereum.org/EIPS/eip-897 * @return type of proxy - always upgradable */ function proxyType() external pure returns (uint256) { // Upgradeable proxy return 2; } /** * @dev Fallback function allowing to perform a delegatecall to the given implementation. * This function will return whatever the implementation call returns */ function () payable external { address _impl = implementation(); require(_impl != address(0)); assembly { let ptr := mload(0x40) calldatacopy(ptr, 0, calldatasize) let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0) let size := returndatasize returndatacopy(ptr, 0, size) switch result case 0 { revert(ptr, size) } default { return(ptr, size) } } } function updateProxyTo(address _newProxyTo) public onlyAdmin { require(_newProxyTo != address(0x0)); _proxyTo = _newProxyTo; emit ProxyUpdated(_newProxyTo, _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: @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: 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/MainchainGatewayProxy.sol pragma solidity ^0.5.17; contract MainchainGatewayProxy is Proxy, MainchainGatewayStorage { constructor(address _proxyTo, address _registry) public Proxy(_proxyTo) { registry = Registry(_registry); } }
File 2 of 4: SmoothLovePotion
// File: math/SafeMath.sol pragma solidity 0.5.17; library SafeMath { function add(uint256 a, uint256 b) internal pure returns (uint256 c) { c = a + b; require(c >= a, "SafeMath: addition overflow"); } function sub(uint256 a, uint256 b) internal pure returns (uint256 c) { require(b <= a, "SafeMath: subtraction overflow"); 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, "SafeMath: multiplication overflow"); } 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, "SafeMath: division by zero"); return a / b; } function mod(uint256 a, uint256 b) internal pure returns (uint256 c) { // Same reason as `div`. require(b > 0, "SafeMath: modulo by zero"); return a % b; } } // File: token/erc20/IERC20.sol pragma solidity 0.5.17; 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: token/erc20/ERC20.sol pragma solidity 0.5.17; contract ERC20 is IERC20 { using SafeMath for uint256; uint256 public totalSupply; mapping (address => uint256) public balanceOf; mapping (address => mapping (address => uint256)) internal _allowance; function approve(address _spender, uint256 _value) public returns (bool) { _approve(msg.sender, _spender, _value); return true; } function allowance(address _owner, address _spender) public view returns (uint256) { return _allowance[_owner][_spender]; } function increaseAllowance(address _spender, uint256 _value) public returns (bool) { _approve(msg.sender, _spender, _allowance[msg.sender][_spender].add(_value)); return true; } function decreaseAllowance(address _spender, uint256 _value) public returns (bool) { _approve(msg.sender, _spender, _allowance[msg.sender][_spender].sub(_value)); return true; } function transfer(address _to, uint256 _value) public returns (bool _success) { _transfer(msg.sender, _to, _value); return true; } function transferFrom(address _from, address _to, uint256 _value) public returns (bool _success) { _transfer(_from, _to, _value); _approve(_from, msg.sender, _allowance[_from][msg.sender].sub(_value)); return true; } function _approve(address _owner, address _spender, uint256 _amount) internal { require(_owner != address(0), "ERC20: approve from the zero address"); require(_spender != address(0), "ERC20: approve to the zero address"); _allowance[_owner][_spender] = _amount; emit Approval(_owner, _spender, _amount); } function _transfer(address _from, address _to, uint256 _value) internal { require(_from != address(0), "ERC20: transfer from the zero address"); require(_to != address(0), "ERC20: transfer to the zero address"); require(_to != address(this), "ERC20: transfer to this contract address"); balanceOf[_from] = balanceOf[_from].sub(_value); balanceOf[_to] = balanceOf[_to].add(_value); emit Transfer(_from, _to, _value); } } // File: token/erc20/IERC20Detailed.sol pragma solidity 0.5.17; 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: token/erc20/ERC20Detailed.sol pragma solidity 0.5.17; 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: token/erc20/ERC20GatewayWhitelist.sol pragma solidity 0.5.17; contract ERC20GatewayWhitelist is ERC20 { address public mainchainGateway; function allowance(address _owner, address _spender) public view returns (uint256 _value) { if (_spender == mainchainGateway) return uint256(-1); return _allowance[_owner][_spender]; } function transferFrom( address _from, address _to, uint256 _value ) public returns (bool _success) { if (allowance(_from, msg.sender) != uint256(-1)) { super._approve(_from, msg.sender, _allowance[_from][msg.sender].sub(_value)); } _transfer(_from, _to, _value); return true; } function _setGateway(address _mainchainGateway) internal { require( _mainchainGateway != address(0), "ERC20GatewayWhitelist: setting gateway to the zero address" ); mainchainGateway = _mainchainGateway; } } // File: access/HasAdmin.sol pragma solidity 0.5.17; contract HasAdmin { event AdminChanged(address indexed _oldAdmin, address indexed _newAdmin); event AdminRemoved(address indexed _oldAdmin); address public admin; modifier onlyAdmin { require(msg.sender == admin, "HasAdmin: not admin"); _; } constructor() internal { admin = msg.sender; emit AdminChanged(address(0), admin); } function changeAdmin(address _newAdmin) external onlyAdmin { require(_newAdmin != address(0), "HasAdmin: new admin is the zero address"); emit AdminChanged(admin, _newAdmin); admin = _newAdmin; } function removeAdmin() external onlyAdmin { emit AdminRemoved(admin); admin = address(0); } } // File: access/HasMinters.sol pragma solidity 0.5.17; 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: token/erc20/ERC20Mintable.sol pragma solidity 0.5.17; 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: SmoothLovePotion.sol pragma solidity 0.5.17; contract SmoothLovePotion is ERC20Detailed, ERC20Mintable, ERC20GatewayWhitelist { constructor(address _mainchainGateway) public ERC20Detailed("Smooth Love Potion", "SLP", 0) { _setGateway(_mainchainGateway); address[] memory _minters = new address[](1); _minters[0] = _mainchainGateway; addMinters(_minters); } }
File 3 of 4: 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; } }
File 4 of 4: Registry
// 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: 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; } }