Verified
Ethereum
Verified, Oracle, Router
Solidity
Verified
Ethereum

Contract Information

The following smart contract is called Invoice and it is used to accept payments in either Ether or ERC20 tokens. It verifies the payment using a signature and stores the payment status in a mapping. The contract also allows the owner to withdraw the funds and change the signer address. The SafeERC20 library is used to perform safe transfers of ERC20 tokens.
More Info

Invoice Source Code

{"IERC20.sol":{"content":"pragma solidity ^0.4.23;\n\ncontract IERC20 {\n function totalSupply() public constant returns (uint);\n function balanceOf(address tokenOwner) public constant returns (uint balance);\n function allowance(address tokenOwner, address spender) public constant returns (uint remaining);\n function transfer(address to, uint tokens) public returns (bool success);\n function approve(address spender, uint tokens) public returns (bool success);\n function transferFrom(address from, address to, uint tokens) public returns (bool success);\n\n event Transfer(address indexed from, address indexed to, uint tokens);\n event Approval(address indexed tokenOwner, address indexed spender, uint tokens);\n}"},"Invoice.sol":{"content":"pragma solidity ^0.4.23;\n\nimport \"./IERC20.sol\";\nimport \"./SafeERC20.sol\";\n\ncontract Invoice {\n using SafeERC20 for IERC20;\n\n address public owner;\n address public quoteSigner;\n mapping(bytes32 =\u003e bool) public isPaid;\n\n event PaymentAccepted(bytes32 indexed hash, address indexed tokenContract, uint time, uint value);\n\n\n constructor(address valueSigner) public {\n owner = msg.sender;\n quoteSigner = valueSigner;\n }\n\n function isValidPayment(\n uint value,\n uint gasPrice,\n uint expiration,\n bytes32 payload,\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s,\n address tokenContract\n ) public view returns(bool valid) {\n bool isValid = !isPaid[payload];\n isValid = isValid \u0026\u0026 block.timestamp \u003c= expiration;\n bytes memory prefix = \"\\x19Ethereum Signed Message:\\n32\";\n bytes32 ourHash = keccak256(abi.encodePacked(value, gasPrice, expiration, payload, tokenContract));\n bytes32 payloadHash = keccak256(abi.encodePacked(prefix, ourHash));\n isValid = isValid \u0026\u0026 ourHash == hash;\n isValid = isValid \u0026\u0026 (ecrecover(payloadHash, v, r, s) == quoteSigner);\n return isValid;\n }\n\n function validatePayment(\n uint value,\n uint gasPrice,\n uint expiration,\n bytes32 payload,\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s,\n address tokenContract\n ) public view returns(bool valid) {\n require(isPaid[payload] == false, \"Already been paid\");\n require(block.timestamp \u003c= expiration, \"Payment is late\");\n bytes memory prefix = \"\\x19Ethereum Signed Message:\\n32\";\n bytes32 ourHash = keccak256(abi.encodePacked(value, gasPrice, expiration, payload, tokenContract));\n bytes32 payloadHash = keccak256(abi.encodePacked(prefix, ourHash));\n require(ourHash == hash, \"Hash mismatch\");\n require(ecrecover(payloadHash, v, r, s) == quoteSigner, \"Signature mismatch for quote\");\n return true;\n }\n\n\n function pay(\n uint value,\n uint gasPrice,\n uint expiration,\n bytes32 payload,\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s,\n address tokenContract\n ) public payable {\n if(tokenContract == 0x0) {\n require(validatePayment(msg.value, gasPrice, expiration, payload, hash, v, r, s, tokenContract), \"Only accept valid payments\");\n } else {\n IERC20 token = IERC20(tokenContract);\n require(token.allowance(msg.sender, address(this)) \u003e= value, \"Must have enough tokens to pay\");\n require(validatePayment(value, gasPrice, expiration, payload, hash, v, r, s, tokenContract), \"Only accept valid payments\");\n require(token.safeTransferFrom(msg.sender, address(this), value), \"Transfer must succeed\");\n }\n isPaid[payload] = true;\n emit PaymentAccepted(hash, tokenContract, block.timestamp, value);\n }\n\n modifier isAdmin() {\n require(msg.sender == owner, \"Must be the contract owner\");\n _;\n }\n\n function withdraw(address tokenContract) public isAdmin {\n if(tokenContract == 0x0) {\n owner.transfer(address(this).balance);\n } else {\n IERC20 token = IERC20(tokenContract);\n uint balance = token.balanceOf(address(this));\n require(token.safeTransfer(owner, balance), \"Must succeed withdrawing tokens\");\n }\n }\n\n function setSigner(address newQuoteSigner) public isAdmin {\n quoteSigner = newQuoteSigner;\n }\n function setAdmin(address newAdmin) public isAdmin {\n owner = newAdmin;\n }\n}\n"},"SafeERC20.sol":{"content":"pragma solidity ^0.4.23;\n\nimport \"./IERC20.sol\";\n/**\n* @dev Library to perform safe calls to standard method for ERC20 tokens.\n*\n* Why Transfers: transfer methods could have a return value (bool), throw or revert for insufficient funds or\n* unathorized value.\n*\n* Why Approve: approve method could has a return value (bool) or does not accept 0 as a valid value (BNB token).\n* The common strategy used to clean approvals.\n*\n* We use the Solidity call instead of interface methods because in the case of transfer, it will fail\n* for tokens with an implementation without returning a value.\n* Since versions of Solidity 0.4.22 the EVM has a new opcode, called RETURNDATASIZE.\n* This opcode stores the size of the returned data of an external call. The code checks the size of the return value\n* after an external call and reverts the transaction in case the return data is shorter than expected\n*/\nlibrary SafeERC20 {\n /**\n * @dev Transfer token for a specified address\n * @param _token erc20 The address of the ERC20 contract\n * @param _to address The address which you want to transfer to\n * @param _value uint256 the _value of tokens to be transferred\n * @return bool whether the transfer was successful or not\n */\n function safeTransfer(IERC20 _token, address _to, uint256 _value) internal returns (bool) {\n uint256 prevBalance = _token.balanceOf(address(this));\n\n if (prevBalance \u003c _value) {\n // Insufficient funds\n return false;\n }\n\n address(_token).call(\n abi.encodeWithSignature(\"transfer(address,uint256)\", _to, _value)\n );\n\n // Fail if the new balance its not equal than previous balance sub _value\n return prevBalance - _value == _token.balanceOf(address(this));\n }\n\n /**\n * @dev Transfer tokens from one address to another\n * @param _token erc20 The address of the ERC20 contract\n * @param _from address The address which you want to send tokens from\n * @param _to address The address which you want to transfer to\n * @param _value uint256 the _value of tokens to be transferred\n * @return bool whether the transfer was successful or not\n */\n function safeTransferFrom(\n IERC20 _token,\n address _from,\n address _to,\n uint256 _value\n ) internal returns (bool)\n {\n uint256 prevBalance = _token.balanceOf(_from);\n\n if (\n prevBalance \u003c _value || // Insufficient funds\n _token.allowance(_from, address(this)) \u003c _value // Insufficient allowance\n ) {\n return false;\n }\n\n address(_token).call(\n abi.encodeWithSignature(\"transferFrom(address,address,uint256)\", _from, _to, _value)\n );\n\n // Fail if the new balance its not equal than previous balance sub _value\n return prevBalance - _value == _token.balanceOf(_from);\n }\n\n /**\n * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.\n *\n * Beware that changing an allowance with this method brings the risk that someone may use both the old\n * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this\n * race condition is to first reduce the spender\u0027s allowance to 0 and set the desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * @param _token erc20 The address of the ERC20 contract\n * @param _spender The address which will spend the funds.\n * @param _value The amount of tokens to be spent.\n * @return bool whether the approve was successful or not\n */\n function safeApprove(IERC20 _token, address _spender, uint256 _value) internal returns (bool) {\n address(_token).call(\n abi.encodeWithSignature(\"approve(address,uint256)\",_spender, _value)\n );\n\n // Fail if the new allowance its not equal than _value\n return _token.allowance(address(this), _spender) == _value;\n }\n\n /**\n * @dev Clear approval\n * Note that if 0 is not a valid value it will be set to 1.\n * @param _token erc20 The address of the ERC20 contract\n * @param _spender The address which will spend the funds.\n */\n function clearApprove(IERC20 _token, address _spender) internal returns (bool) {\n bool success = safeApprove(_token, _spender, 0);\n\n if (!success) {\n success = safeApprove(_token, _spender, 1);\n }\n\n return success;\n }\n}"}}
< {"IERC20.sol":{"content":"pragma solidity ^0.4.23;\n\ncontract IERC20 {\n  function totalSupply() public constant returns (uint);\n  function balanceOf(address tokenOwner) public constant returns (uint balance);\n  function allowance(address tokenOwner, address spender) public constant returns (uint remaining);\n  function transfer(address to, uint tokens) public returns (bool success);\n  function approve(address spender, uint tokens) public returns (bool success);\n  function transferFrom(address from, address to, uint tokens) public returns (bool success);\n\n  event Transfer(address indexed from, address indexed to, uint tokens);\n  event Approval(address indexed tokenOwner, address indexed spender, uint tokens);\n}"},"Invoice.sol":{"content":"pragma solidity ^0.4.23;\n\nimport \"./IERC20.sol\";\nimport \"./SafeERC20.sol\";\n\ncontract Invoice {\n  using SafeERC20 for IERC20;\n\n  address public owner;\n  address public quoteSigner;\n  mapping(bytes32 =\u003e bool) public isPaid;\n\n  event PaymentAccepted(bytes32 indexed hash, address indexed tokenContract,  uint time, uint value);\n\n\n  constructor(address valueSigner) public {\n    owner = msg.sender;\n    quoteSigner = valueSigner;\n  }\n\n  function isValidPayment(\n    uint value,\n    uint gasPrice,\n    uint expiration,\n    bytes32 payload,\n    bytes32 hash,\n    uint8 v,\n    bytes32 r,\n    bytes32 s,\n    address tokenContract\n  ) public view returns(bool valid) {\n    bool isValid = !isPaid[payload];\n    isValid = isValid \u0026\u0026 block.timestamp \u003c= expiration;\n    bytes memory prefix = \"\\x19Ethereum Signed Message:\\n32\";\n    bytes32 ourHash = keccak256(abi.encodePacked(value, gasPrice, expiration, payload, tokenContract));\n    bytes32 payloadHash = keccak256(abi.encodePacked(prefix, ourHash));\n    isValid = isValid \u0026\u0026 ourHash == hash;\n    isValid = isValid \u0026\u0026 (ecrecover(payloadHash, v, r, s) == quoteSigner);\n    return isValid;\n  }\n\n  function validatePayment(\n    uint value,\n    uint gasPrice,\n    uint expiration,\n    bytes32 payload,\n    bytes32 hash,\n    uint8 v,\n    bytes32 r,\n    bytes32 s,\n    address tokenContract\n  ) public view returns(bool valid) {\n    require(isPaid[payload] == false, \"Already been paid\");\n    require(block.timestamp \u003c= expiration, \"Payment is late\");\n    bytes memory prefix = \"\\x19Ethereum Signed Message:\\n32\";\n    bytes32 ourHash = keccak256(abi.encodePacked(value, gasPrice, expiration, payload, tokenContract));\n    bytes32 payloadHash = keccak256(abi.encodePacked(prefix, ourHash));\n    require(ourHash == hash, \"Hash mismatch\");\n    require(ecrecover(payloadHash, v, r, s) == quoteSigner, \"Signature mismatch for quote\");\n    return true;\n  }\n\n\n  function pay(\n    uint value,\n    uint gasPrice,\n    uint expiration,\n    bytes32 payload,\n    bytes32 hash,\n    uint8 v,\n    bytes32 r,\n    bytes32 s,\n    address tokenContract\n  ) public payable {\n    if(tokenContract == 0x0) {\n      require(validatePayment(msg.value, gasPrice, expiration, payload, hash, v, r, s, tokenContract), \"Only accept valid payments\");\n    } else {\n      IERC20 token = IERC20(tokenContract);\n      require(token.allowance(msg.sender, address(this)) \u003e= value, \"Must have enough tokens to pay\");\n      require(validatePayment(value, gasPrice, expiration, payload, hash, v, r, s, tokenContract), \"Only accept valid payments\");\n      require(token.safeTransferFrom(msg.sender, address(this), value), \"Transfer must succeed\");\n    }\n    isPaid[payload] = true;\n    emit PaymentAccepted(hash, tokenContract, block.timestamp, value);\n  }\n\n  modifier isAdmin() {\n    require(msg.sender == owner, \"Must be the contract owner\");\n    _;\n  }\n\n  function withdraw(address tokenContract) public isAdmin {\n    if(tokenContract == 0x0) {\n      owner.transfer(address(this).balance);\n    } else {\n      IERC20 token = IERC20(tokenContract);\n      uint balance = token.balanceOf(address(this));\n      require(token.safeTransfer(owner, balance), \"Must succeed withdrawing tokens\");\n    }\n  }\n\n  function setSigner(address newQuoteSigner) public isAdmin {\n    quoteSigner = newQuoteSigner;\n  }\n  function setAdmin(address newAdmin) public isAdmin {\n    owner = newAdmin;\n  }\n}\n"},"SafeERC20.sol":{"content":"pragma solidity ^0.4.23;\n\nimport \"./IERC20.sol\";\n/**\n* @dev Library to perform safe calls to standard method for ERC20 tokens.\n*\n* Why Transfers: transfer methods could have a return value (bool), throw or revert for insufficient funds or\n* unathorized value.\n*\n* Why Approve: approve method could has a return value (bool) or does not accept 0 as a valid value (BNB token).\n* The common strategy used to clean approvals.\n*\n* We use the Solidity call instead of interface methods because in the case of transfer, it will fail\n* for tokens with an implementation without returning a value.\n* Since versions of Solidity 0.4.22 the EVM has a new opcode, called RETURNDATASIZE.\n* This opcode stores the size of the returned data of an external call. The code checks the size of the return value\n* after an external call and reverts the transaction in case the return data is shorter than expected\n*/\nlibrary SafeERC20 {\n    /**\n    * @dev Transfer token for a specified address\n    * @param _token erc20 The address of the ERC20 contract\n    * @param _to address The address which you want to transfer to\n    * @param _value uint256 the _value of tokens to be transferred\n    * @return bool whether the transfer was successful or not\n    */\n    function safeTransfer(IERC20 _token, address _to, uint256 _value) internal returns (bool) {\n        uint256 prevBalance = _token.balanceOf(address(this));\n\n        if (prevBalance \u003c _value) {\n            // Insufficient funds\n            return false;\n        }\n\n        address(_token).call(\n            abi.encodeWithSignature(\"transfer(address,uint256)\", _to, _value)\n        );\n\n        // Fail if the new balance its not equal than previous balance sub _value\n        return prevBalance - _value == _token.balanceOf(address(this));\n    }\n\n    /**\n    * @dev Transfer tokens from one address to another\n    * @param _token erc20 The address of the ERC20 contract\n    * @param _from address The address which you want to send tokens from\n    * @param _to address The address which you want to transfer to\n    * @param _value uint256 the _value of tokens to be transferred\n    * @return bool whether the transfer was successful or not\n    */\n    function safeTransferFrom(\n        IERC20 _token,\n        address _from,\n        address _to,\n        uint256 _value\n    ) internal returns (bool)\n    {\n        uint256 prevBalance = _token.balanceOf(_from);\n\n        if (\n          prevBalance \u003c _value || // Insufficient funds\n          _token.allowance(_from, address(this)) \u003c _value // Insufficient allowance\n        ) {\n            return false;\n        }\n\n        address(_token).call(\n            abi.encodeWithSignature(\"transferFrom(address,address,uint256)\", _from, _to, _value)\n        );\n\n        // Fail if the new balance its not equal than previous balance sub _value\n        return prevBalance - _value == _token.balanceOf(_from);\n    }\n\n   /**\n   * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.\n   *\n   * Beware that changing an allowance with this method brings the risk that someone may use both the old\n   * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this\n   * race condition is to first reduce the spender\u0027s allowance to 0 and set the desired value afterwards:\n   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n   *\n   * @param _token erc20 The address of the ERC20 contract\n   * @param _spender The address which will spend the funds.\n   * @param _value The amount of tokens to be spent.\n   * @return bool whether the approve was successful or not\n   */\n    function safeApprove(IERC20 _token, address _spender, uint256 _value) internal returns (bool) {\n        address(_token).call(\n            abi.encodeWithSignature(\"approve(address,uint256)\",_spender, _value)\n        );\n\n        // Fail if the new allowance its not equal than _value\n        return _token.allowance(address(this), _spender) == _value;\n    }\n\n   /**\n   * @dev Clear approval\n   * Note that if 0 is not a valid value it will be set to 1.\n   * @param _token erc20 The address of the ERC20 contract\n   * @param _spender The address which will spend the funds.\n   */\n    function clearApprove(IERC20 _token, address _spender) internal returns (bool) {\n        bool success = safeApprove(_token, _spender, 0);\n\n        if (!success) {\n            success = safeApprove(_token, _spender, 1);\n        }\n\n        return success;\n    }\n}"}} < 

Invoice ABI

[{"constant":true,"inputs":[{"name":"value","type":"uint256"},{"name":"gasPrice","type":"uint256"},{"name":"expiration","type":"uint256"},{"name":"payload","type":"bytes32"},{"name":"hash","type":"bytes32"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"},{"name":"tokenContract","type":"address"}],"name":"validatePayment","outputs":[{"name":"valid","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"tokenContract","type":"address"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newQuoteSigner","type":"address"}],"name":"setSigner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newAdmin","type":"address"}],"name":"setAdmin","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"value","type":"uint256"},{"name":"gasPrice","type":"uint256"},{"name":"expiration","type":"uint256"},{"name":"payload","type":"bytes32"},{"name":"hash","type":"bytes32"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"},{"name":"tokenContract","type":"address"}],"name":"isValidPayment","outputs":[{"name":"valid","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"value","type":"uint256"},{"name":"gasPrice","type":"uint256"},{"name":"expiration","type":"uint256"},{"name":"payload","type":"bytes32"},{"name":"hash","type":"bytes32"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"},{"name":"tokenContract","type":"address"}],"name":"pay","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"quoteSigner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"isPaid","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"valueSigner","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"hash","type":"bytes32"},{"indexed":true,"name":"tokenContract","type":"address"},{"indexed":false,"name":"time","type":"uint256"},{"indexed":false,"name":"value","type":"uint256"}],"name":"PaymentAccepted","type":"event"}]
[{"constant":true,"inputs":[{"name":"value","type":"uint256"},{"name":"gasPrice","type":"uint256"},{"name":"expiration","type":"uint256"},{"name":"payload","type":"bytes32"},{"name":"hash","type":"bytes32"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"},{"name":"tokenContract","type":"address"}],"name":"validatePayment","outputs":[{"name":"valid","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"tokenContract","type":"address"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newQuoteSigner","type":"address"}],"name":"setSigner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newAdmin","type":"address"}],"name":"setAdmin","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"value","type":"uint256"},{"name":"gasPrice","type":"uint256"},{"name":"expiration","type":"uint256"},{"name":"payload","type":"bytes32"},{"name":"hash","type":"bytes32"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"},{"name":"tokenContract","type":"address"}],"name":"isValidPayment","outputs":[{"name":"valid","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"value","type":"uint256"},{"name":"gasPrice","type":"uint256"},{"name":"expiration","type":"uint256"},{"name":"payload","type":"bytes32"},{"name":"hash","type":"bytes32"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"},{"name":"tokenContract","type":"address"}],"name":"pay","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"quoteSigner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"isPaid","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"valueSigner","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"hash","type":"bytes32"},{"indexed":true,"name":"tokenContract","type":"address"},{"indexed":false,"name":"time","type":"uint256"},{"indexed":false,"name":"value","type":"uint256"}],"name":"PaymentAccepted","type":"event"}]

Invoice Bytecode

608060405234801561001057600080fd5b50604051602080611e9883398101806040528101908080519060200190929190505050336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050611dd4806100c46000396000f300608060405260043610610099576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630b0898211461009e57806351cff8d91461015c5780636c19e7831461019f578063704b6c02146101e25780638da5cb5b1461022557806398a89c1b1461027c578063b6b4af051461033a578063f413bdb3146103d3578063feef66401461042a575b600080fd5b3480156100aa57600080fd5b5061014260048036038101908080359060200190929190803590602001909291908035906020019092919080356000191690602001909291908035600019169060200190929190803560ff16906020019092919080356000191690602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610473565b604051808215151515815260200191505060405180910390f35b34801561016857600080fd5b5061019d600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061096e565b005b3480156101ab57600080fd5b506101e0600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c79565b005b3480156101ee57600080fd5b50610223600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610d81565b005b34801561023157600080fd5b5061023a610e88565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561028857600080fd5b5061032060048036038101908080359060200190929190803590602001909291908035906020019092919080356000191690602001909291908035600019169060200190929190803560ff16906020019092919080356000191690602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ead565b604051808215151515815260200191505060405180910390f35b6103d160048036038101908080359060200190929190803590602001909291908035906020019092919080356000191690602001909291908035600019169060200190929190803560ff16906020019092919080356000191690602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506111f6565b005b3480156103df57600080fd5b506103e86115e6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561043657600080fd5b50610459600480360381019080803560001916906020019092919050505061160c565b604051808215151515815260200191505060405180910390f35b6000606060008060001515600260008c6000191660001916815260200190815260200160002060009054906101000a900460ff16151514151561051e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f416c7265616479206265656e207061696400000000000000000000000000000081525060200191505060405180910390fd5b8a4211151515610596576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f5061796d656e74206973206c617465000000000000000000000000000000000081525060200191505060405180910390fd5b6040805190810160405280601c81526020017f19457468657265756d205369676e6564204d6573736167653a0a33320000000081525092508c8c8c8c886040516020018086815260200185815260200184815260200183600019166000191681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401955050505050506040516020818303038152906040526040518082805190602001908083835b6020831015156106865780518252602082019150602081019050602083039250610661565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020915082826040516020018083805190602001908083835b6020831015156106ef57805182526020820191506020810190506020830392506106ca565b6001836020036101000a0380198251168184511680821785525050505050509050018260001916600019168152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831015156107675780518252602082019150602081019050602083039250610742565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020905088600019168260001916141515610815576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f48617368206d69736d617463680000000000000000000000000000000000000081525060200191505060405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166001828a8a8a604051600081526020016040526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000865af11580156108c5573d6000803e3d6000fd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff1614151561095a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f5369676e6174757265206d69736d6174636820666f722071756f74650000000081525060200191505060405180910390fd5b600193505050509998505050505050505050565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610a35576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f4d7573742062652074686520636f6e7472616374206f776e657200000000000081525060200191505060405180910390fd5b60008373ffffffffffffffffffffffffffffffffffffffff161415610ad8576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f19350505050158015610ad2573d6000803e3d6000fd5b50610c74565b8291508173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015610b7657600080fd5b505af1158015610b8a573d6000803e3d6000fd5b505050506040513d6020811015610ba057600080fd5b81019080805190602001909291905050509050610bff6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828473ffffffffffffffffffffffffffffffffffffffff1661162c9092919063ffffffff16565b1515610c73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f4d7573742073756363656564207769746864726177696e6720746f6b656e730081525060200191505060405180910390fd5b5b505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610d3d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f4d7573742062652074686520636f6e7472616374206f776e657200000000000081525060200191505060405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610e45576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f4d7573742062652074686520636f6e7472616374206f776e657200000000000081525060200191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000806060600080600260008c6000191660001916815260200190815260200160002060009054906101000a900460ff16159350838015610eee57508b4211155b93506040805190810160405280601c81526020017f19457468657265756d205369676e6564204d6573736167653a0a33320000000081525092508d8d8d8d896040516020018086815260200185815260200184815260200183600019166000191681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401955050505050506040516020818303038152906040526040518082805190602001908083835b602083101515610fe05780518252602082019150602081019050602083039250610fbb565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020915082826040516020018083805190602001908083835b6020831015156110495780518252602082019150602081019050602083039250611024565b6001836020036101000a0380198251168184511680821785525050505050509050018260001916600019168152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831015156110c1578051825260208201915060208101905060208303925061109c565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209050838015611104575089600019168260001916145b93508380156111e05750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166001828b8b8b604051600081526020016040526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000865af11580156111be573d6000803e3d6000fd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff16145b9350839450505050509998505050505050505050565b6000808273ffffffffffffffffffffffffffffffffffffffff1614156112a057611227348a8a8a8a8a8a8a8a610473565b151561129b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f4f6e6c79206163636570742076616c6964207061796d656e747300000000000081525060200191505060405180910390fd5b61154b565b819050898173ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e33306040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600087803b15801561137357600080fd5b505af1158015611387573d6000803e3d6000fd5b505050506040513d602081101561139d57600080fd5b810190808051906020019092919050505010151515611424576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f4d757374206861766520656e6f75676820746f6b656e7320746f20706179000081525060200191505060405180910390fd5b6114358a8a8a8a8a8a8a8a8a610473565b15156114a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f4f6e6c79206163636570742076616c6964207061796d656e747300000000000081525060200191505060405180910390fd5b6114d633308c8473ffffffffffffffffffffffffffffffffffffffff16611946909392919063ffffffff16565b151561154a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f5472616e73666572206d7573742073756363656564000000000000000000000081525060200191505060405180910390fd5b5b600160026000896000191660001916815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff1686600019167f826e7792f434a28ba302e6767da85b4b8e56b83a5e028687f30e848e32667f95428d604051808381526020018281526020019250505060405180910390a350505050505050505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60026020528060005260406000206000915054906101000a900460ff1681565b6000808473ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156116ca57600080fd5b505af11580156116de573d6000803e3d6000fd5b505050506040513d60208110156116f457600080fd5b8101908080519060200190929190505050905082811015611718576000915061193e565b8473ffffffffffffffffffffffffffffffffffffffff168484604051602401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506040516020818303038152906040527fa9059cbb000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405180828051906020019080838360005b8381101561181e578082015181840152602081019050611803565b50505050905090810190601f16801561184b5780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af1915050508473ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156118fc57600080fd5b505af1158015611910573d6000803e3d6000fd5b505050506040513d602081101561192657600080fd5b81019080805190602001909291905050508382031491505b509392505050565b6000808573ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156119e457600080fd5b505af11580156119f8573d6000803e3d6000fd5b505050506040513d6020811015611a0e57600080fd5b8101908080519060200190929190505050905082811080611b375750828673ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e87306040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600087803b158015611afa57600080fd5b505af1158015611b0e573d6000803e3d6000fd5b505050506040513d6020811015611b2457600080fd5b8101908080519060200190929190505050105b15611b455760009150611d9f565b8573ffffffffffffffffffffffffffffffffffffffff16858585604051602401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200193505050506040516020818303038152906040527f23b872dd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405180828051906020019080838360005b83811015611c7f578082015181840152602081019050611c64565b50505050905090810190601f168015611cac5780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af1915050508573ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015611d5d57600080fd5b505af1158015611d71573d6000803e3d6000fd5b505050506040513d6020811015611d8757600080fd5b81019080805190602001909291905050508382031491505b509493505050505600a165627a7a7230582084ea8b0fc708d384163b217b0469bcdaed7970e5c5d34d783e960923add11a820029000000000000000000000000a97ceb180ca61d124b6a4aadc5530bc53198922f
608060405234801561001057600080fd5b50604051602080611e9883398101806040528101908080519060200190929190505050336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050611dd4806100c46000396000f300608060405260043610610099576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630b0898211461009e57806351cff8d91461015c5780636c19e7831461019f578063704b6c02146101e25780638da5cb5b1461022557806398a89c1b1461027c578063b6b4af051461033a578063f413bdb3146103d3578063feef66401461042a575b600080fd5b3480156100aa57600080fd5b5061014260048036038101908080359060200190929190803590602001909291908035906020019092919080356000191690602001909291908035600019169060200190929190803560ff16906020019092919080356000191690602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610473565b604051808215151515815260200191505060405180910390f35b34801561016857600080fd5b5061019d600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061096e565b005b3480156101ab57600080fd5b506101e0600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c79565b005b3480156101ee57600080fd5b50610223600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610d81565b005b34801561023157600080fd5b5061023a610e88565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561028857600080fd5b5061032060048036038101908080359060200190929190803590602001909291908035906020019092919080356000191690602001909291908035600019169060200190929190803560ff16906020019092919080356000191690602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ead565b604051808215151515815260200191505060405180910390f35b6103d160048036038101908080359060200190929190803590602001909291908035906020019092919080356000191690602001909291908035600019169060200190929190803560ff16906020019092919080356000191690602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506111f6565b005b3480156103df57600080fd5b506103e86115e6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561043657600080fd5b50610459600480360381019080803560001916906020019092919050505061160c565b604051808215151515815260200191505060405180910390f35b6000606060008060001515600260008c6000191660001916815260200190815260200160002060009054906101000a900460ff16151514151561051e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f416c7265616479206265656e207061696400000000000000000000000000000081525060200191505060405180910390fd5b8a4211151515610596576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f5061796d656e74206973206c617465000000000000000000000000000000000081525060200191505060405180910390fd5b6040805190810160405280601c81526020017f19457468657265756d205369676e6564204d6573736167653a0a33320000000081525092508c8c8c8c886040516020018086815260200185815260200184815260200183600019166000191681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401955050505050506040516020818303038152906040526040518082805190602001908083835b6020831015156106865780518252602082019150602081019050602083039250610661565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020915082826040516020018083805190602001908083835b6020831015156106ef57805182526020820191506020810190506020830392506106ca565b6001836020036101000a0380198251168184511680821785525050505050509050018260001916600019168152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831015156107675780518252602082019150602081019050602083039250610742565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020905088600019168260001916141515610815576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f48617368206d69736d617463680000000000000000000000000000000000000081525060200191505060405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166001828a8a8a604051600081526020016040526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000865af11580156108c5573d6000803e3d6000fd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff1614151561095a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f5369676e6174757265206d69736d6174636820666f722071756f74650000000081525060200191505060405180910390fd5b600193505050509998505050505050505050565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610a35576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f4d7573742062652074686520636f6e7472616374206f776e657200000000000081525060200191505060405180910390fd5b60008373ffffffffffffffffffffffffffffffffffffffff161415610ad8576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f19350505050158015610ad2573d6000803e3d6000fd5b50610c74565b8291508173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015610b7657600080fd5b505af1158015610b8a573d6000803e3d6000fd5b505050506040513d6020811015610ba057600080fd5b81019080805190602001909291905050509050610bff6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828473ffffffffffffffffffffffffffffffffffffffff1661162c9092919063ffffffff16565b1515610c73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f4d7573742073756363656564207769746864726177696e6720746f6b656e730081525060200191505060405180910390fd5b5b505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610d3d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f4d7573742062652074686520636f6e7472616374206f776e657200000000000081525060200191505060405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610e45576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f4d7573742062652074686520636f6e7472616374206f776e657200000000000081525060200191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000806060600080600260008c6000191660001916815260200190815260200160002060009054906101000a900460ff16159350838015610eee57508b4211155b93506040805190810160405280601c81526020017f19457468657265756d205369676e6564204d6573736167653a0a33320000000081525092508d8d8d8d896040516020018086815260200185815260200184815260200183600019166000191681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401955050505050506040516020818303038152906040526040518082805190602001908083835b602083101515610fe05780518252602082019150602081019050602083039250610fbb565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020915082826040516020018083805190602001908083835b6020831015156110495780518252602082019150602081019050602083039250611024565b6001836020036101000a0380198251168184511680821785525050505050509050018260001916600019168152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831015156110c1578051825260208201915060208101905060208303925061109c565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209050838015611104575089600019168260001916145b93508380156111e05750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166001828b8b8b604051600081526020016040526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000865af11580156111be573d6000803e3d6000fd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff16145b9350839450505050509998505050505050505050565b6000808273ffffffffffffffffffffffffffffffffffffffff1614156112a057611227348a8a8a8a8a8a8a8a610473565b151561129b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f4f6e6c79206163636570742076616c6964207061796d656e747300000000000081525060200191505060405180910390fd5b61154b565b819050898173ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e33306040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600087803b15801561137357600080fd5b505af1158015611387573d6000803e3d6000fd5b505050506040513d602081101561139d57600080fd5b810190808051906020019092919050505010151515611424576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f4d757374206861766520656e6f75676820746f6b656e7320746f20706179000081525060200191505060405180910390fd5b6114358a8a8a8a8a8a8a8a8a610473565b15156114a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f4f6e6c79206163636570742076616c6964207061796d656e747300000000000081525060200191505060405180910390fd5b6114d633308c8473ffffffffffffffffffffffffffffffffffffffff16611946909392919063ffffffff16565b151561154a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f5472616e73666572206d7573742073756363656564000000000000000000000081525060200191505060405180910390fd5b5b600160026000896000191660001916815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff1686600019167f826e7792f434a28ba302e6767da85b4b8e56b83a5e028687f30e848e32667f95428d604051808381526020018281526020019250505060405180910390a350505050505050505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60026020528060005260406000206000915054906101000a900460ff1681565b6000808473ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156116ca57600080fd5b505af11580156116de573d6000803e3d6000fd5b505050506040513d60208110156116f457600080fd5b8101908080519060200190929190505050905082811015611718576000915061193e565b8473ffffffffffffffffffffffffffffffffffffffff168484604051602401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506040516020818303038152906040527fa9059cbb000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405180828051906020019080838360005b8381101561181e578082015181840152602081019050611803565b50505050905090810190601f16801561184b5780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af1915050508473ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156118fc57600080fd5b505af1158015611910573d6000803e3d6000fd5b505050506040513d602081101561192657600080fd5b81019080805190602001909291905050508382031491505b509392505050565b6000808573ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156119e457600080fd5b505af11580156119f8573d6000803e3d6000fd5b505050506040513d6020811015611a0e57600080fd5b8101908080519060200190929190505050905082811080611b375750828673ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e87306040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600087803b158015611afa57600080fd5b505af1158015611b0e573d6000803e3d6000fd5b505050506040513d6020811015611b2457600080fd5b8101908080519060200190929190505050105b15611b455760009150611d9f565b8573ffffffffffffffffffffffffffffffffffffffff16858585604051602401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200193505050506040516020818303038152906040527f23b872dd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405180828051906020019080838360005b83811015611c7f578082015181840152602081019050611c64565b50505050905090810190601f168015611cac5780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af1915050508573ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015611d5d57600080fd5b505af1158015611d71573d6000803e3d6000fd5b505050506040513d6020811015611d8757600080fd5b81019080805190602001909291905050508382031491505b509493505050505600a165627a7a7230582084ea8b0fc708d384163b217b0469bcdaed7970e5c5d34d783e960923add11a820029000000000000000000000000a97ceb180ca61d124b6a4aadc5530bc53198922f

Check out more smart contracts

Build blockchain magic with Alchemy

Alchemy combines the most powerful web3 developer products and tools with resources, community and legendary support.