Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x3BaE89B27Cc92c8f3FC97617cDd0F196e992E4b2
Balance 0 ETH
Nonce 1
Code Size 9496 bytes
Indexed Transactions 2 (24,428,30324,428,303)
Gas Used (indexed) 196,436
External Etherscan · Sourcify

Contract Bytecode

9496 bytes
0x6080604052600436106101095760003560e01c80636548e9bc116100955780638da5cb5b116100645780638da5cb5b146105345780638eb4e0ad14610549578063b0eefabe14610ada578063e55dc4e614610b0d578063e9600f1214610b5057610109565b80636548e9bc146104235780636cc6cde1146104565780637bd352b7146104875780638406c0791461051f57610109565b80631aeaad03116100dc5780631aeaad03146101e257806324943c7d1461024f5780632cc9636c146102cb5780632d83549c1461033d5780633bad7c7e1461039857610109565b806304f83df11461010e5780630947587e146101535780630d98ed3b1461017f57806313af4035146101af575b600080fd5b34801561011a57600080fd5b506101416004803603602081101561013157600080fd5b50356001600160a01b0316610bae565b60408051918252519081900360200190f35b34801561015f57600080fd5b50610168610bc0565b6040805161ffff9092168252519081900360200190f35b34801561018b57600080fd5b506101ad600480360360208110156101a257600080fd5b503561ffff16610bd1565b005b3480156101bb57600080fd5b506101ad600480360360208110156101d257600080fd5b50356001600160a01b0316610c3c565b6101ad60048036036101208110156101f957600080fd5b506001600160801b0319813516906001600160a01b03602082013581169160408101358216916060820135169060808101359061ffff60a0820135169060ff60c0820135169060e0810135906101000135610ca7565b34801561025b57600080fd5b506101ad600480360361012081101561027357600080fd5b506001600160801b0319813516906001600160a01b03602082013581169160408101359091169060608101359061ffff6080820135169060ff60a082013581169160c08101359160e082013591610100013516610f54565b3480156102d757600080fd5b50610329600480360360a08110156102ee57600080fd5b5080356001600160801b0319169060208101356001600160a01b03908116916040810135909116906060810135906080013561ffff166112c3565b604080519115158252519081900360200190f35b34801561034957600080fd5b506103676004803603602081101561036057600080fd5b503561132b565b6040805193151584526001600160801b0390921660208401526001600160a01b031682820152519081900360600190f35b6101ad60048036036101a08110156103af57600080fd5b506001600160801b0319813516906001600160a01b03602082013581169160408101358216916060820135169060808101359061ffff60a0820135169060ff60c082013581169160e08101359161010082013591610120810135916101408201351690610160810135906101800135611361565b34801561042f57600080fd5b506101ad6004803603602081101561044657600080fd5b50356001600160a01b03166116b5565b34801561046257600080fd5b5061046b611720565b604080516001600160a01b039092168252519081900360200190f35b34801561049357600080fd5b5061032960048036036101608110156104ab57600080fd5b506001600160801b0319813516906001600160a01b03602082013581169160408101359091169060608101359061ffff6080820135169060a08101356001600160801b039081169160ff60c082013581169260e083013592610100810135926101208201351691610140909101351661172f565b34801561052b57600080fd5b5061046b611824565b34801561054057600080fd5b5061046b611833565b34801561055557600080fd5b50610a8a600480360361014081101561056d57600080fd5b810190602081018135600160201b81111561058757600080fd5b82018360208201111561059957600080fd5b803590602001918460208302840111600160201b831117156105ba57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561060957600080fd5b82018360208201111561061b57600080fd5b803590602001918460208302840111600160201b8311171561063c57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561068b57600080fd5b82018360208201111561069d57600080fd5b803590602001918460208302840111600160201b831117156106be57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561070d57600080fd5b82018360208201111561071f57600080fd5b803590602001918460208302840111600160201b8311171561074057600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561078f57600080fd5b8201836020820111156107a157600080fd5b803590602001918460208302840111600160201b831117156107c257600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561081157600080fd5b82018360208201111561082357600080fd5b803590602001918460208302840111600160201b8311171561084457600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561089357600080fd5b8201836020820111156108a557600080fd5b803590602001918460208302840111600160201b831117156108c657600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561091557600080fd5b82018360208201111561092757600080fd5b803590602001918460208302840111600160201b8311171561094857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561099757600080fd5b8201836020820111156109a957600080fd5b803590602001918460208302840111600160201b831117156109ca57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b811115610a1957600080fd5b820183602082011115610a2b57600080fd5b803590602001918460208302840111600160201b83111715610a4c57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611842945050505050565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610ac6578181015183820152602001610aae565b505050509050019250505060405180910390f35b348015610ae657600080fd5b506101ad60048036036020811015610afd57600080fd5b50356001600160a01b03166119d7565b348015610b1957600080fd5b506101ad60048036036060811015610b3057600080fd5b506001600160a01b03813581169160208101359091169060400135611a42565b348015610b5c57600080fd5b50610329600480360360a0811015610b7357600080fd5b5080356001600160801b0319169060208101356001600160a01b03908116916040810135909116906060810135906080013561ffff16611b17565b60046020526000908152604090205481565b600254600160a01b900461ffff1681565b6001546001600160a01b03163314610c1a5760405162461bcd60e51b815260040180806020018281038252602b81526020018061243a602b913960400191505060405180910390fd5b6002805461ffff909216600160a01b0261ffff60a01b19909216919091179055565b6001546001600160a01b03163314610c855760405162461bcd60e51b815260040180806020018281038252602b81526020018061243a602b913960400191505060405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b604080516001600160801b03198b166020808301919091526001600160601b031960608b811b821660308501528a901b166044830152605882018890526001600160f01b031960f088901b1660788301528251605a818403018152607a9092018352815191810191909120600081815260039092529190205460ff1615610d6c576040805162461bcd60e51b8152602060048201526014602482015273547261646520616c72656164792065786973747360601b604482015290519081900360640190fd5b6040805160208082018490528251808303820181529183019092528051910120600254600160a01b900461ffff168711610dd75760405162461bcd60e51b815260040180806020018281038252602f815260200180612465602f913960400191505060405180910390fd5b6002546001600160a01b0316610def82878787611b76565b6001600160a01b031614610e345760405162461bcd60e51b815260040180806020018281038252602f815260200180612369602f913960400191505060405180910390fd5b610e4f6001600160a01b038b1633308a63ffffffff611c8c16565b604051806060016040528060011515815260200160006001600160801b031681526020018b6001600160a01b03168152506003600084815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a8154816001600160801b0302191690836001600160801b0316021790555060408201518160010160006101000a8154816001600160a01b0302191690836001600160a01b031602179055509050507f102d25c49d33fcdb8976a3f2744e0785c98d9e43b88364859e6aec4ae82eff5c826040518082815260200191505060405180910390a15050505050505050505050565b6000546001600160a01b03163314610f9d5760405162461bcd60e51b815260040180806020018281038252603081526020018061240a6030913960400191505060405180910390fd5b604080516001600160801b03198b16602080830191909152600360f81b60308301528251601181840301815260319092019092528051910120600090610fe590868686611b76565b9050876001600160a01b0316816001600160a01b031614806110185750886001600160a01b0316816001600160a01b0316145b611069576040805162461bcd60e51b815260206004820152601760248201527f4d757374206265206275796572206f722073656c6c6572000000000000000000604482015290519081900360640190fd5b611071612348565b60006110808c8c8c8c8c611cec565b60408051606081018252835460ff811615158083526101009091046001600160801b031660208301526001909401546001600160a01b0316918101919091529350915061110c576040805162461bcd60e51b8152602060048201526015602482015274115cd8dc9bddc8191bd95cc81b9bdd08195e1a5cdd605a1b604482015290519081900360640190fd5b60648460ff16111561114f5760405162461bcd60e51b81526004018080602001828103825260228152602001806123e86022913960400191505060405180910390fd5b602082810180513a6136ec02016001600160801b03908116825260008481526003845260409081902080546001600160881b031916815560010180546001600160a01b03191690559151825185815291169281019290925280517f437ec3256bbed400455e142c7ce305c6e705cad2d1ba5a4ebed6a6dd133d93fb9281900390910190a160ff8416156112865761271061ffff89168a0204606460ff86168b02048190038a1015611238576040805162461bcd60e51b815260206004820152600e60248201526d27bb32b9333637bb9032b93937b960911b604482015290519081900360640190fd5b6040808401516001600160a01b031660009081526004602052208054820190556112848b82606460ff89168e02040385604001516001600160a01b0316611d6c9092919063ffffffff16565b505b60648460ff1610156112b55760408201516112b5906001600160a01b03168c606487810360ff168d0204611d6c565b505050505050505050505050565b6000336001600160a01b03851614611312576040805162461bcd60e51b815260206004820152600d60248201526c26bab9ba10313290313abcb2b960991b604482015290519081900360640190fd5b61132186868686866000611dbe565b9695505050505050565b6003602052600090815260409020805460019091015460ff82169161010090046001600160801b0316906001600160a01b031683565b604080516001600160801b03198f166020808301919091526001600160601b031960608f811b821660308501528e901b166044830152605882018c90526001600160f01b031960f08c901b1660788301528251605a818403018152607a9092018352815191810191909120600081815260039092529190205460ff16156114195760405162461bcd60e51b81526004018080602001828103825260268152602001806123986026913960400191505060405180910390fd5b6040805160208082018490528251808303820181529183019092528051910120600254600160a01b900461ffff168b116114845760405162461bcd60e51b815260040180806020018281038252602f815260200180612465602f913960400191505060405180910390fd5b6002546001600160a01b031661149c828b8b8b611b76565b6001600160a01b0316146114e15760405162461bcd60e51b815260040180806020018281038252602f815260200180612369602f913960400191505060405180910390fd5b8d6001600160a01b031663e3ee160e33308e60006005548c8c8c8c6040518a63ffffffff1660e01b8152600401808a6001600160a01b03166001600160a01b03168152602001896001600160a01b03166001600160a01b031681526020018881526020018781526020018681526020018581526020018460ff1660ff1681526020018381526020018281526020019950505050505050505050600060405180830381600087803b15801561159457600080fd5b505af11580156115a8573d6000803e3d6000fd5b50505050604051806060016040528060011515815260200160006001600160801b031681526020018f6001600160a01b03168152506003600084815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a8154816001600160801b0302191690836001600160801b0316021790555060408201518160010160006101000a8154816001600160a01b0302191690836001600160a01b031602179055509050507f102d25c49d33fcdb8976a3f2744e0785c98d9e43b88364859e6aec4ae82eff5c826040518082815260200191505060405180910390a1505050505050505050505050505050565b6001546001600160a01b031633146116fe5760405162461bcd60e51b815260040180806020018281038252602b81526020018061243a602b913960400191505060405180910390fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031681565b6000806117408d858a8a8a8a611f34565b90508a6001600160a01b0316816001600160a01b031614156117835760ff84166002141561177e576117768d8d8d8d8d88611dbe565b915050611815565b611813565b8b6001600160a01b0316816001600160a01b031614156117b75760ff84166001141561177e576117768d8d8d8d8d88611fe7565b336001600160a01b038d1614611809576040805162461bcd60e51b8152602060048201526012602482015271556e7265636f676e6973656420706172747960701b604482015290519081900360640190fd5b6000915050611815565b505b9b9a5050505050505050505050565b6002546001600160a01b031681565b6001546001600160a01b031681565b6060808b51604051908082528060200260200182016040528015611870578160200160208202803883390190505b506002549091506000906001600160a01b0316331461189057600061189e565b8c516175308161189c57fe5b045b905060005b8d518160ff1610156119c55761199e8e8260ff16815181106118c157fe5b60200260200101518e8360ff16815181106118d857fe5b60200260200101518e8460ff16815181106118ef57fe5b60200260200101518e8560ff168151811061190657fe5b60200260200101518e8660ff168151811061191d57fe5b60200260200101518e8760ff168151811061193457fe5b60200260200101518e8860ff168151811061194b57fe5b60200260200101518e8960ff168151811061196257fe5b60200260200101518e8a60ff168151811061197957fe5b60200260200101518e8b60ff168151811061199057fe5b60200260200101518c61172f565b838260ff16815181106119ad57fe5b911515602092830291909101909101526001016118a3565b50909c9b505050505050505050505050565b6001546001600160a01b03163314611a205760405162461bcd60e51b815260040180806020018281038252602b81526020018061243a602b913960400191505060405180910390fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b03163314611a8b5760405162461bcd60e51b815260040180806020018281038252602b81526020018061243a602b913960400191505060405180910390fd5b6001600160a01b038216600090815260046020526040902054811115611ae25760405162461bcd60e51b81526004018080602001828103825260268152602001806124946026913960400191505060405180910390fd5b6001600160a01b038216600081815260046020526040902080548390039055611b1290848363ffffffff611d6c16565b505050565b6000336001600160a01b03861614611b67576040805162461bcd60e51b815260206004820152600e60248201526d26bab9ba1031329039b2b63632b960911b604482015290519081900360640190fd5b61132186868686866000611fe7565b600060606040518060400160405280601c81526020017f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152509050600081876040516020018083805190602001908083835b60208310611be85780518252601f199092019160209182019101611bc9565b51815160209384036101000a6000190180199092169116179052920193845250604080518085038152848301808352815191840191909120600090915281850180835281905260ff8c166060860152608085018b905260a085018a905290519095506001945060c080850194929350601f198201928290030190855afa158015611c76573d6000803e3d6000fd5b5050604051601f19015198975050505050505050565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611ce6908590612101565b50505050565b604080516001600160801b031996909616602080880191909152606095861b6001600160601b031990811660308901529490951b9093166044860152605885019190915260f01b6001600160f01b03191660788401528051808403605a018152607a90930181528251928201929092206000818152600390925291902091565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611b12908490612101565b6000611dc8612348565b6000611dd78989898989611cec565b60408051606081018252835460ff811615158083526101009091046001600160801b031660208301526001909401546001600160a01b03169181019190915293509150611e63576040805162461bcd60e51b8152602060048201526015602482015274115cd8dc9bddc8191bd95cc81b9bdd08195e1a5cdd605a1b604482015290519081900360640190fd5b8151611e7457600092505050611321565b6002546000906001600160a01b03163314611e90576000611e98565b61093f85013a025b60208481015160008581526003835260409081902080546001600160881b031916815560010180546001600160a01b03191690558051868152939091016001600160801b0381169284019290925280519193507fef5d27f6da36198207d0bf4c1db4f2d6e12a27045c53f7e7f2529ec7045a65c0928290030190a1611f2483604001518a8960006122b9565b5060019998505050505050505050565b604080516001600160801b03198089166020808401919091526001600160f81b031960f88a901b166030840152608088901b909116603183015282516021818403018152604190920190925280519101206000906001600160801b0386163a10611fcf5760405162461bcd60e51b815260040180806020018281038252602a8152602001806123be602a913960400191505060405180910390fd5b611fdb81868686611b76565b98975050505050505050565b6000611ff1612348565b60006120008989898989611cec565b60408051606081018252835460ff811615158083526101009091046001600160801b031660208301526001909401546001600160a01b0316918101919091529350915061205257600092505050611321565b6002546000906001600160a01b0316331461206e576000612076565b610e4a85013a025b60208481015160008581526003835260409081902080546001600160881b031916815560010180546001600160a01b03191690558051868152939091016001600160801b0381169284019290925280519193507f44306e460694e3f7e04300c4479a6818c0a825e0482fd6d4d0f16b0232e96205928290030190a1611f2483604001518989896122b9565b612113826001600160a01b031661230c565b612164576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b602083106121a25780518252601f199092019160209182019101612183565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612204576040519150601f19603f3d011682016040523d82523d6000602084013e612209565b606091505b509150915081612260576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b805115611ce65780806020019051602081101561227c57600080fd5b5051611ce65760405162461bcd60e51b815260040180806020018281038252602a8152602001806124ba602a913960400191505060405180910390fd5b61271061ffff82168302048083038310156122d45750611ce6565b6001600160a01b0385166000818152600460205260409020805483019055612305908583860363ffffffff611d6c16565b5050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061234057508115155b949350505050565b60408051606081018252600080825260208201819052918101919091529056fe5472616e73616374696f6e207369676e617475726520646964206e6f7420636f6d652066726f6d2072656c61796572547261646520616c72656164792065786973747320696e20657363726f77206d617070696e6747617320707269636520697320686967686572207468616e206d6178696d756d206761732070726963655f627579657250657263656e74206d75737420626520313030206f72206c6f7765724f6e6c79207468652063757272656e74206f776e65722063616e206368616e6765207468652061726269747261746f724f6e6c79207468652063757272656e74206f776e65722063616e206368616e676520746865206f776e6572457363726f772076616c7565206d7573742062652067726561746572207468616e206d696e696d756d2076616c7565416d6f756e7420697320686967686572207468616e20616d6f756e7420617661696c61626c655361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a265627a7a7231582013a65d3ad08c19451eb55f0dbe8c4ea4940824e8cd33487a8a105fade058e8b264736f6c63430005110032

Verified Source Code Full Match

Compiler: v0.5.17+commit.d19bba13 EVM: istanbul Optimization: Yes (200 runs)
SafeMath.sol 156 lines
pragma solidity ^0.5.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     *
     * _Available since v2.4.0._
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     *
     * _Available since v2.4.0._
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     *
     * _Available since v2.4.0._
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}
Address.sol 70 lines
pragma solidity ^0.5.5;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following 
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != accountHash && codehash != 0x0);
    }

    /**
     * @dev Converts an `address` into `address payable`. Note that this is
     * simply a type cast: the actual underlying value is not changed.
     *
     * _Available since v2.4.0._
     */
    function toPayable(address account) internal pure returns (address payable) {
        return address(uint160(account));
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     *
     * _Available since v2.4.0._
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-call-value
        (bool success, ) = recipient.call.value(amount)("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }
}
LocalCoinSwapV2.sol 422 lines
pragma solidity ^0.5.17;

import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";


contract Token is IERC20 {
    function transferWithAuthorization(
        address from,
        address to,
        uint256 value,
        uint256 validAfter,
        uint256 validBefore,
        bytes32 nonce,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}


contract LocalCoinSwapV2Escrow {

    using SafeERC20 for Token;

    /***********************
    +       Globals        +
    ***********************/

    address public arbitrator;
    address public owner;
    address public relayer;

    uint16 public minimumTradeValue = 1; // Token

    struct Escrow {
      bool exists;
      uint128 totalGasFeesSpentByRelayer;
      address tokenContract;
    }

    mapping (bytes32 => Escrow) public escrows;
    mapping (address => uint256) public feesAvailableForWithdraw;

    uint256 MAX_INT = 2**256 - 1;

    /***********************
    +     Instructions     +
    ***********************/

    uint8 constant RELEASE_ESCROW = 0x01;
    uint8 constant BUYER_CANCELS = 0x02;
    uint8 constant RESOLVE_DISPUTE = 0x03;

    /***********************
    +       Events        +
    ***********************/

    event Created(bytes32 _tradeHash);
    event CancelledByBuyer(bytes32 _tradeHash, uint128 totalGasFeesSpentByRelayer);
    event Released(bytes32 _tradeHash, uint128 totalGasFeesSpentByRelayer);
    event DisputeResolved(bytes32 _tradeHash, uint128 totalGasFeesSpentByRelayer);

    /***********************
    +     Constructor      +
    ***********************/

    constructor(address initialAddress) public {
        owner = initialAddress;
        arbitrator = initialAddress;
        relayer = initialAddress;
    }

    /***********************
    +     Open Escrow     +
    ***********************/

    function createEscrow(
      bytes16 _tradeID,
      address _currency,
      address _seller,
      address _buyer,
      uint256 _value,
      uint16 _fee, // Our fee in 1/10000ths of a token
      uint8 _v, // Signature value
      bytes32 _r, // Signature value
      bytes32 _s // Signature value
    ) external payable {
        bytes32 _tradeHash = keccak256(abi.encodePacked(_tradeID, _seller, _buyer, _value, _fee));
        require(!escrows[_tradeHash].exists, "Trade already exists");
        bytes32 _invitationHash = keccak256(abi.encodePacked(_tradeHash));
        require(_value > minimumTradeValue, "Escrow value must be greater than minimum value"); // Check escrow value is greater than minimum value
        require(recoverAddress(_invitationHash, _v, _r, _s) == relayer, "Transaction signature did not come from relayer");

        Token(_currency).safeTransferFrom(msg.sender, address(this), _value);

        escrows[_tradeHash] = Escrow(true, 0, _currency);
        emit Created(_tradeHash);
    }

    function relayEscrow(
      bytes16 _tradeID,
      address _currency,
      address _seller,
      address _buyer,
      uint256 _value,
      uint16 _fee, // Our fee in 1/10000ths of a token
      uint8 _v, // Signature value for trade invitation by LocalCoinSwap
      bytes32 _r, // Signature value for trade invitation by LocalCoinSwap
      bytes32 _s, // Signature value for trade invitation by LocalCoinSwp
      bytes32 _nonce, // Random nonce used for gasless send
      uint8 _v_gasless, // Signature value for GasLess send
      bytes32 _r_gasless, // Signature value for GasLess send
      bytes32 _s_gasless // Signature value for GasLess send
    ) external payable {
        bytes32 _tradeHash = keccak256(abi.encodePacked(_tradeID, _seller, _buyer, _value, _fee));
        require(!escrows[_tradeHash].exists, "Trade already exists in escrow mapping");
        bytes32 _invitationHash = keccak256(abi.encodePacked(_tradeHash));
        require(_value > minimumTradeValue, "Escrow value must be greater than minimum value"); // Check escrow value is greater than minimum value
        require(recoverAddress(_invitationHash, _v, _r, _s) == relayer, "Transaction signature did not come from relayer");

        // Perform gasless send from seller to contract
        Token(_currency).transferWithAuthorization(
            msg.sender,
            address(this),
            _value,
            0,
            MAX_INT,
            _nonce,
            _v_gasless,
            _r_gasless,
            _s_gasless
        );

        escrows[_tradeHash] = Escrow(true, 0, _currency);
        emit Created(_tradeHash);
    }

    /***********************
    +   Complete Escrow    +
    ***********************/

    function release(
        bytes16 _tradeID,
        address payable _seller,
        address payable _buyer,
        uint256 _value,
        uint16 _fee
    ) external returns (bool){
        require(msg.sender == _seller, "Must be seller");
        return doRelease(_tradeID, _seller, _buyer, _value, _fee, 0);
    }

    uint16 constant GAS_doRelease = 3658;
    function doRelease(
        bytes16 _tradeID,
        address payable _seller,
        address payable _buyer,
        uint256 _value,
        uint16 _fee,
        uint128 _additionalGas
    ) private returns (bool) {
        Escrow memory _escrow;
        bytes32 _tradeHash;
        (_escrow, _tradeHash) = getEscrowAndHash(_tradeID, _seller, _buyer, _value, _fee);
        if (!_escrow.exists) return false;
        uint128 _gasFees = _escrow.totalGasFeesSpentByRelayer + (msg.sender == relayer
                ? (GAS_doRelease + _additionalGas ) * uint128(tx.gasprice)
                : 0
            );
        delete escrows[_tradeHash];
        emit Released(_tradeHash, _gasFees);
        transferMinusFees(_escrow.tokenContract, _buyer, _value, _fee);
        return true;
    }

    uint16 constant GAS_doResolveDispute = 14060;
    function resolveDispute(
        bytes16 _tradeID,
        address payable _seller,
        address payable _buyer,
        uint256 _value,
        uint16 _fee,
        uint8 _v,
        bytes32 _r,
        bytes32 _s,
        uint8 _buyerPercent
    ) external onlyArbitrator {
        address _signature = recoverAddress(keccak256(abi.encodePacked(
            _tradeID,
            RESOLVE_DISPUTE
        )), _v, _r, _s);
        require(_signature == _buyer || _signature == _seller, "Must be buyer or seller");

        Escrow memory _escrow;
        bytes32 _tradeHash;
        (_escrow, _tradeHash) = getEscrowAndHash(_tradeID, _seller, _buyer, _value, _fee);
        require(_escrow.exists, "Escrow does not exist");
        require(_buyerPercent <= 100, "_buyerPercent must be 100 or lower");

        _escrow.totalGasFeesSpentByRelayer += (GAS_doResolveDispute * uint128(tx.gasprice));

        delete escrows[_tradeHash];
        emit DisputeResolved(_tradeHash, _escrow.totalGasFeesSpentByRelayer);
        if (_buyerPercent > 0) {
          // If dispute goes to buyer take the fee
          uint256 _totalFees = (_value * _fee / 10000);
          // Prevent underflow
          require(_value * _buyerPercent / 100 - _totalFees <= _value, "Overflow error");
          feesAvailableForWithdraw[_escrow.tokenContract] += _totalFees;
          Token(_escrow.tokenContract).safeTransfer(_buyer, _value * _buyerPercent / 100 - _totalFees);
        }
        if (_buyerPercent < 100) {
          Token(_escrow.tokenContract).safeTransfer(_seller, _value * (100 - _buyerPercent) / 100);
        }
    }

    function buyerCancel(
      bytes16 _tradeID,
      address payable _seller,
      address payable _buyer,
      uint256 _value,
      uint16 _fee
    ) external returns (bool) {
        require(msg.sender == _buyer, "Must be buyer");
        return doBuyerCancel(_tradeID, _seller, _buyer, _value, _fee, 0);
    }

    function increaseGasSpent(bytes32 _tradeHash, uint128 _gas) private {
        escrows[_tradeHash].totalGasFeesSpentByRelayer += _gas * uint128(tx.gasprice);
    }

    uint16 constant GAS_doBuyerCancel = 2367;
    function doBuyerCancel(
        bytes16 _tradeID,
        address payable _seller,
        address payable _buyer,
        uint256 _value,
        uint16 _fee,
        uint128 _additionalGas
    ) private returns (bool) {
        Escrow memory _escrow;
        bytes32 _tradeHash;
        (_escrow, _tradeHash) = getEscrowAndHash(_tradeID, _seller, _buyer, _value, _fee);
        require(_escrow.exists, "Escrow does not exist");
        if (!_escrow.exists) {
            return false;
        }
        uint128 _gasFees = _escrow.totalGasFeesSpentByRelayer + (msg.sender == relayer
                ? (GAS_doBuyerCancel + _additionalGas ) * uint128(tx.gasprice)
                : 0
            );
        delete escrows[_tradeHash];
        emit CancelledByBuyer(_tradeHash, _gasFees);
        transferMinusFees(_escrow.tokenContract, _seller, _value, 0);
        return true;
    }

    /***********************
    +        Relays        +
    ***********************/

    uint16 constant GAS_batchRelayBaseCost = 30000;
    function batchRelay(
        bytes16[] memory _tradeID,
        address payable[] memory _seller,
        address payable[] memory _buyer,
        uint256[] memory _value,
        uint16[] memory _fee,
        uint128[] memory _maximumGasPrice,
        uint8[] memory _v,
        bytes32[] memory _r,
        bytes32[] memory _s,
        uint8[] memory _instructionByte
    ) public returns (bool[] memory) {
        bool[] memory _results = new bool[](_tradeID.length);
        uint128 _additionalGas = uint128(msg.sender == relayer ? GAS_batchRelayBaseCost / _tradeID.length : 0);
        for (uint8 i = 0; i < _tradeID.length; i++) {
            _results[i] = relay(
                _tradeID[i],
                _seller[i],
                _buyer[i],
                _value[i],
                _fee[i],
                _maximumGasPrice[i],
                _v[i],
                _r[i],
                _s[i],
                _instructionByte[i],
                _additionalGas
            );
        }
        return _results;
    }

    function relay(
        bytes16 _tradeID,
        address payable _seller,
        address payable _buyer,
        uint256 _value,
        uint16 _fee,
        uint128 _maximumGasPrice,
        uint8 _v,
        bytes32 _r,
        bytes32 _s,
        uint8 _instructionByte,
        uint128 _additionalGas
    ) public returns (bool) {
        address _relayedSender = getRelayedSender(
            _tradeID,
            _instructionByte,
            _maximumGasPrice,
            _v,
            _r,
            _s
        );
        if (_relayedSender == _buyer) {
            if (_instructionByte == BUYER_CANCELS) {
                return doBuyerCancel(_tradeID, _seller, _buyer, _value, _fee, _additionalGas);
            }
        } else if (_relayedSender == _seller) {
            if (_instructionByte == RELEASE_ESCROW) {
                return doRelease(_tradeID, _seller, _buyer, _value, _fee, _additionalGas);
            }
        } else {
            require(msg.sender == _seller, "Unrecognised party");
            return false;
        }
    }

    /***********************
    +      Management      +
    ***********************/

    function setArbitrator(address _newArbitrator) external onlyOwner {
        arbitrator = _newArbitrator;
    }

    function setOwner(address _newOwner) external onlyOwner {
        owner = _newOwner;
    }

    function setRelayer(address _newRelayer) external onlyOwner {
        relayer = _newRelayer;
    }

    function setMinimumValue(uint16 _newMinimumValue) external onlyOwner {
        minimumTradeValue = _newMinimumValue;
    }

    /***********************
    +   Helper Functions   +
    ***********************/

    function transferMinusFees(
        address _currency,
        address payable _to,
        uint256 _value,
        uint16 _fee
    ) private {
        uint256 _totalFees = (_value * _fee / 10000);
        // Prevent underflow
        if(_value - _totalFees > _value) {
            return;
        }
        // Add fees to the pot for localcoinswap to withdraw
        feesAvailableForWithdraw[_currency] += _totalFees;
        Token(_currency).safeTransfer(_to, _value - _totalFees);
    }

    function withdrawFees(address payable _to, address _currency, uint256 _amount) external onlyOwner {
        // This check also prevents underflow
        require(_amount <= feesAvailableForWithdraw[_currency], "Amount is higher than amount available");
        feesAvailableForWithdraw[_currency] -= _amount;
        Token(_currency).safeTransfer(_to, _amount);
    }

    function getEscrowAndHash(
      bytes16 _tradeID,
      address _seller,
      address _buyer,
      uint256 _value,
      uint16 _fee
    ) private view returns (Escrow storage, bytes32) {
        bytes32 _tradeHash = keccak256(abi.encodePacked(_tradeID, _seller, _buyer, _value, _fee));
        return (escrows[_tradeHash], _tradeHash);
    }

    function recoverAddress(
        bytes32 _h,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    ) private pure returns (address) {
        bytes memory _prefix = "\x19Ethereum Signed Message:\n32";
        bytes32 _prefixedHash = keccak256(abi.encodePacked(_prefix, _h));
        return ecrecover(_prefixedHash, _v, _r, _s);
    }

    function getRelayedSender(
      bytes16 _tradeID,
      uint8 _instructionByte,
      uint128 _maximumGasPrice,
      uint8 _v,
      bytes32 _r,
      bytes32 _s
    ) private view returns (address) {
        bytes32 _hash = keccak256(abi.encodePacked(_tradeID, _instructionByte, _maximumGasPrice));
        require(tx.gasprice < _maximumGasPrice, "Gas price is higher than maximum gas price");
        return recoverAddress(_hash, _v, _r, _s);
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Only the current owner can change the owner");
        _;
    }

    modifier onlyArbitrator() {
        require(msg.sender == arbitrator, "Only the current owner can change the arbitrator");
        _;
    }
}
IERC20.sol 76 lines
pragma solidity ^0.5.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see {ERC20Detailed}.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}
SafeERC20.sol 75 lines
pragma solidity ^0.5.0;

import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using SafeMath for uint256;
    using Address for address;

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves.

        // A Solidity high level call has three parts:
        //  1. The target address is checked to verify it contains contract code
        //  2. The call itself is made, and success asserted
        //  3. The return value is decoded, which in turn checks the size of the returned data.
        // solhint-disable-next-line max-line-length
        require(address(token).isContract(), "SafeERC20: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = address(token).call(data);
        require(success, "SafeERC20: low-level call failed");

        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

Read Contract

arbitrator 0x6cc6cde1 → address
escrows 0x2d83549c → bool, uint128, address
feesAvailableForWithdraw 0x04f83df1 → uint256
minimumTradeValue 0x0947587e → uint16
owner 0x8da5cb5b → address
relayer 0x8406c079 → address

Write Contract 12 functions

These functions modify contract state and require a wallet transaction to execute.

batchRelay 0x8eb4e0ad
bytes16[] _tradeID
address[] _seller
address[] _buyer
uint256[] _value
uint16[] _fee
uint128[] _maximumGasPrice
uint8[] _v
bytes32[] _r
bytes32[] _s
uint8[] _instructionByte
returns: bool[]
buyerCancel 0x2cc9636c
bytes16 _tradeID
address _seller
address _buyer
uint256 _value
uint16 _fee
returns: bool
createEscrow 0x1aeaad03
bytes16 _tradeID
address _currency
address _seller
address _buyer
uint256 _value
uint16 _fee
uint8 _v
bytes32 _r
bytes32 _s
relay 0x7bd352b7
bytes16 _tradeID
address _seller
address _buyer
uint256 _value
uint16 _fee
uint128 _maximumGasPrice
uint8 _v
bytes32 _r
bytes32 _s
uint8 _instructionByte
uint128 _additionalGas
returns: bool
relayEscrow 0x3bad7c7e
bytes16 _tradeID
address _currency
address _seller
address _buyer
uint256 _value
uint16 _fee
uint8 _v
bytes32 _r
bytes32 _s
bytes32 _nonce
uint8 _v_gasless
bytes32 _r_gasless
bytes32 _s_gasless
release 0xe9600f12
bytes16 _tradeID
address _seller
address _buyer
uint256 _value
uint16 _fee
returns: bool
resolveDispute 0x24943c7d
bytes16 _tradeID
address _seller
address _buyer
uint256 _value
uint16 _fee
uint8 _v
bytes32 _r
bytes32 _s
uint8 _buyerPercent
setArbitrator 0xb0eefabe
address _newArbitrator
setMinimumValue 0x0d98ed3b
uint16 _newMinimumValue
setOwner 0x13af4035
address _newOwner
setRelayer 0x6548e9bc
address _newRelayer
withdrawFees 0xe55dc4e6
address _to
address _currency
uint256 _amount

Top Interactions

AddressTxnsSentReceived
0x87F64A33...F694 1 1
0x877cf5F0...5ce5 1 1

Recent Transactions

CSV
|
Hash Method Block Age From/To Value Txn Fee Type
0x90746beb...daabdf 0x8eb4e0ad 24,428,303 IN 0x877cf5F0...5ce5 0 ETH 0.000017931539 ETH Legacy
0xe843cd60...1af2b8 0x1aeaad03 24,428,303 IN 0x87F64A33...F694 0 ETH 0.000020918744 ETH Legacy