Address Contract Verified
Address
0x62D459252db23F928A7074b32C8d6161596E2670
Balance
0.015952 ETH
Nonce
1
Code Size
12537 bytes
Creator
0x513FC992...0B5e at tx 0xe9a9edb3...61c0af
Indexed Transactions
0
Contract Bytecode
12537 bytes
0x6080604052600436106100fe5760003560e01c80638279c7db11610095578063ac8a584a11610064578063ac8a584a146102ef578063be4b177214610318578063f2fde38b14610341578063fc6f94681461036a578063ff53f05b14610395576100fe565b80638279c7db14610249578063896f01711461027257806389ff1f5b1461029b5780638da5cb5b146102c4576100fe565b80633c00a36c116100d15780633c00a36c146101b0578063572b6c05146101d957806370bbcbf514610216578063715018a614610232576100fe565b806313e7c9d81461010357806316fed3e2146101405780632c1e816d1461016b57806338b24c2a14610194575b600080fd5b34801561010f57600080fd5b5061012a60048036038101906101259190611dd8565b6103be565b6040516101379190611e20565b60405180910390f35b34801561014c57600080fd5b506101556103de565b6040516101629190611e4a565b60405180910390f35b34801561017757600080fd5b50610192600480360381019061018d9190611dd8565b610404565b005b6101ae60048036038101906101a9919061200d565b6104c2565b005b3480156101bc57600080fd5b506101d760048036038101906101d2919061210a565b610624565b005b3480156101e557600080fd5b5061020060048036038101906101fb9190611dd8565b610896565b60405161020d9190611e20565b60405180910390f35b610230600480360381019061022b9190612337565b6108ee565b005b34801561023e57600080fd5b50610247610bb0565b005b34801561025557600080fd5b50610270600480360381019061026b9190611dd8565b610bc4565b005b34801561027e57600080fd5b5061029960048036038101906102949190611dd8565b610c82565b005b3480156102a757600080fd5b506102c260048036038101906102bd9190612393565b610de4565b005b3480156102d057600080fd5b506102d961113f565b6040516102e69190611e4a565b60405180910390f35b3480156102fb57600080fd5b5061031660048036038101906103119190611dd8565b611168565b005b34801561032457600080fd5b5061033f600480360381019061033a9190612416565b6112c9565b005b34801561034d57600080fd5b5061036860048036038101906103639190611dd8565b6115aa565b005b34801561037657600080fd5b5061037f61162e565b60405161038c9190611e4a565b60405180910390f35b3480156103a157600080fd5b506103bc60048036038101906103b79190612456565b611654565b005b60036020528060005260406000206000915054906101000a900460ff1681565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61040c611889565b80600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561047d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610474906125d9565b60405180910390fd5b81600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b60003411610505576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104fc90612645565b60405180910390fd5b600061050f611907565b73ffffffffffffffffffffffffffffffffffffffff16311015610567576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161055e906126b1565b60405180910390fd5b80156105d757600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f193505050501580156105d5573d6000803e3d6000fd5b505b7fa97c286dc3d1bc2b6a7ab9066b0ee05b9b7b8539bd18b1004e0911132fede2aa8686868634874288604051610614989796959493929190612757565b60405180910390a1505050505050565b60036000610630611907565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166106b7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106ae9061283d565b60405180910390fd5b600081116106fa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106f1906128a9565b60405180910390fd5b4781111561073d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161073490612915565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156107cf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107c690612981565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015610837573d6000803e3d6000fd5b507f95f34ba6e14773d4f8c50f4f6c39fbc2f47dfba1bb026c1a9a1b17bc534b5cec600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168260405161088b9291906129a1565b60405180910390a150565b60007f00000000000000000000000084a0856b038eaad1cc7e297cf34a7e72685a869373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16149050919050565b60003411610931576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161092890612645565b60405180910390fd5b600061093b611907565b73ffffffffffffffffffffffffffffffffffffffff16311015610993576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161098a906126b1565b60405180910390fd5b6000805b83518110156109df578381815181106109b3576109b26129ca565b5b602002602001015160800151826109ca9190612a28565b915080806109d790612a7e565b915050610997565b50803414610a22576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a1990612b39565b60405180910390fd5b8115610a9257600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015610a90573d6000803e3d6000fd5b505b60005b8351811015610baa577fa97c286dc3d1bc2b6a7ab9066b0ee05b9b7b8539bd18b1004e0911132fede2aa848281518110610ad257610ad16129ca565b5b602002602001015160000151858381518110610af157610af06129ca565b5b602002602001015160200151868481518110610b1057610b0f6129ca565b5b602002602001015160400151878581518110610b2f57610b2e6129ca565b5b602002602001015160600151888681518110610b4e57610b4d6129ca565b5b602002602001015160800151898781518110610b6d57610b6c6129ca565b5b602002602001015160a00151428a604051610b8f989796959493929190612757565b60405180910390a18080610ba290612a7e565b915050610a95565b50505050565b610bb8611889565b610bc26000611916565b565b610bcc611889565b80600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610c3d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c34906125d9565b60405180910390fd5b81600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b610c8a611889565b80600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610cfb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cf2906125d9565b60405180910390fd5b600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615610d88576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7f90612ba5565b60405180910390fd5b6001600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b6000831015610e28576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e1f90612645565b60405180910390fd5b6000805b8551811015610e7457858181518110610e4857610e476129ca565b5b60200260200101516080015182610e5f9190612a28565b91508080610e6c90612a7e565b915050610e2c565b50808414610eb7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610eae90612c37565b60405180910390fd5b838273ffffffffffffffffffffffffffffffffffffffff166370a08231610edc611907565b6040518263ffffffff1660e01b8152600401610ef89190611e4a565b60206040518083038186803b158015610f1057600080fd5b505afa158015610f24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f489190612c6c565b1015610f89576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f80906126b1565b60405180910390fd5b8215610fea57610fe5610f9a611907565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16868573ffffffffffffffffffffffffffffffffffffffff166119da909392919063ffffffff16565b61101f565b61101e610ff5611907565b30868573ffffffffffffffffffffffffffffffffffffffff166119da909392919063ffffffff16565b5b60005b8551811015611137577ffc62bc9478e40c66fb078efa7c02474d4e2abfa47a49ad8d4133355206b6064386828151811061105f5761105e6129ca565b5b60200260200101516000015187838151811061107e5761107d6129ca565b5b60200260200101516020015188848151811061109d5761109c6129ca565b5b6020026020010151604001518985815181106110bc576110bb6129ca565b5b6020026020010151606001518a86815181106110db576110da6129ca565b5b6020026020010151608001518b87815181106110fa576110f96129ca565b5b602002602001015160a00151428b60405161111c989796959493929190612757565b60405180910390a1808061112f90612a7e565b915050611022565b505050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b611170611889565b80600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156111e1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111d8906125d9565b60405180910390fd5b600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1661126d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161126490612ce5565b60405180910390fd5b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b600360006112d5611907565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1661135c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113539061283d565b60405180910390fd5b6000821161139f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611396906128a9565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016113d89190611e4a565b60206040518083038186803b1580156113f057600080fd5b505afa158015611404573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114289190612c6c565b82111561146a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161146190612915565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156114fc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114f390612981565b60405180910390fd5b611549600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16838373ffffffffffffffffffffffffffffffffffffffff16611a639092919063ffffffff16565b7fc7de2d139afb8c4257b3fac58f791fb657180f2f86753ed057e0c3a404f705a3600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16838360405161159e93929190612d05565b60405180910390a15050565b6115b2611889565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611622576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161161990612dae565b60405180910390fd5b61162b81611916565b50565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000841015611698576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161168f90612645565b60405180910390fd5b838373ffffffffffffffffffffffffffffffffffffffff166370a082316116bd611907565b6040518263ffffffff1660e01b81526004016116d99190611e4a565b60206040518083038186803b1580156116f157600080fd5b505afa158015611705573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117299190612c6c565b101561176a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611761906126b1565b60405180910390fd5b80156117cb576117c661177b611907565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16868673ffffffffffffffffffffffffffffffffffffffff166119da909392919063ffffffff16565b611800565b6117ff6117d6611907565b30868673ffffffffffffffffffffffffffffffffffffffff166119da909392919063ffffffff16565b5b7ffc62bc9478e40c66fb078efa7c02474d4e2abfa47a49ad8d4133355206b60643888888888887428860405161183d989796959493929190612757565b60405180910390a15050505050505050565b600061185a33610896565b1561186e57601436033560601c905061187d565b611876611881565b905061187e565b5b90565b600033905090565b611891611907565b73ffffffffffffffffffffffffffffffffffffffff166118af61113f565b73ffffffffffffffffffffffffffffffffffffffff1614611905576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118fc90612e1a565b60405180910390fd5b565b600061191161184f565b905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b611a5d846323b872dd60e01b8585856040516024016119fb93929190612e3a565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050611ae9565b50505050565b611ae48363a9059cbb60e01b8484604051602401611a829291906129a1565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050611ae9565b505050565b6000611b4b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16611bb09092919063ffffffff16565b9050600081511115611bab5780806020019051810190611b6b9190612e86565b611baa576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ba190612f25565b60405180910390fd5b5b505050565b6060611bbf8484600085611bc8565b90509392505050565b606082471015611c0d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c0490612fb7565b60405180910390fd5b611c1685611cdc565b611c55576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c4c90613023565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051611c7e919061308a565b60006040518083038185875af1925050503d8060008114611cbb576040519150601f19603f3d011682016040523d82523d6000602084013e611cc0565b606091505b5091509150611cd0828286611cff565b92505050949350505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b60608315611d0f57829050611d5f565b600083511115611d225782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d5691906130a1565b60405180910390fd5b9392505050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000611da582611d7a565b9050919050565b611db581611d9a565b8114611dc057600080fd5b50565b600081359050611dd281611dac565b92915050565b600060208284031215611dee57611ded611d70565b5b6000611dfc84828501611dc3565b91505092915050565b60008115159050919050565b611e1a81611e05565b82525050565b6000602082019050611e356000830184611e11565b92915050565b611e4481611d9a565b82525050565b6000602082019050611e5f6000830184611e3b565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b611eb882611e6f565b810181811067ffffffffffffffff82111715611ed757611ed6611e80565b5b80604052505050565b6000611eea611d66565b9050611ef68282611eaf565b919050565b600067ffffffffffffffff821115611f1657611f15611e80565b5b611f1f82611e6f565b9050602081019050919050565b82818337600083830152505050565b6000611f4e611f4984611efb565b611ee0565b905082815260208101848484011115611f6a57611f69611e6a565b5b611f75848285611f2c565b509392505050565b600082601f830112611f9257611f91611e65565b5b8135611fa2848260208601611f3b565b91505092915050565b6000819050919050565b611fbe81611fab565b8114611fc957600080fd5b50565b600081359050611fdb81611fb5565b92915050565b611fea81611e05565b8114611ff557600080fd5b50565b60008135905061200781611fe1565b92915050565b60008060008060008060c0878903121561202a57612029611d70565b5b600087013567ffffffffffffffff81111561204857612047611d75565b5b61205489828a01611f7d565b965050602087013567ffffffffffffffff81111561207557612074611d75565b5b61208189828a01611f7d565b955050604087013567ffffffffffffffff8111156120a2576120a1611d75565b5b6120ae89828a01611f7d565b94505060606120bf89828a01611fcc565b935050608087013567ffffffffffffffff8111156120e0576120df611d75565b5b6120ec89828a01611f7d565b92505060a06120fd89828a01611ff8565b9150509295509295509295565b6000602082840312156121205761211f611d70565b5b600061212e84828501611fcc565b91505092915050565b600067ffffffffffffffff82111561215257612151611e80565b5b602082029050602081019050919050565b600080fd5b600080fd5b600080fd5b600060c0828403121561218857612187612168565b5b61219260c0611ee0565b9050600082013567ffffffffffffffff8111156121b2576121b161216d565b5b6121be84828501611f7d565b600083015250602082013567ffffffffffffffff8111156121e2576121e161216d565b5b6121ee84828501611f7d565b602083015250604082013567ffffffffffffffff8111156122125761221161216d565b5b61221e84828501611f7d565b604083015250606061223284828501611fcc565b606083015250608061224684828501611fcc565b60808301525060a082013567ffffffffffffffff81111561226a5761226961216d565b5b61227684828501611f7d565b60a08301525092915050565b600061229561229084612137565b611ee0565b905080838252602082019050602084028301858111156122b8576122b7612163565b5b835b818110156122ff57803567ffffffffffffffff8111156122dd576122dc611e65565b5b8086016122ea8982612172565b855260208501945050506020810190506122ba565b5050509392505050565b600082601f83011261231e5761231d611e65565b5b813561232e848260208601612282565b91505092915050565b6000806040838503121561234e5761234d611d70565b5b600083013567ffffffffffffffff81111561236c5761236b611d75565b5b61237885828601612309565b925050602061238985828601611ff8565b9150509250929050565b600080600080608085870312156123ad576123ac611d70565b5b600085013567ffffffffffffffff8111156123cb576123ca611d75565b5b6123d787828801612309565b94505060206123e887828801611fcc565b93505060406123f987828801611ff8565b925050606061240a87828801611dc3565b91505092959194509250565b6000806040838503121561242d5761242c611d70565b5b600061243b85828601611fcc565b925050602061244c85828601611dc3565b9150509250929050565b600080600080600080600080610100898b03121561247757612476611d70565b5b600089013567ffffffffffffffff81111561249557612494611d75565b5b6124a18b828c01611f7d565b985050602089013567ffffffffffffffff8111156124c2576124c1611d75565b5b6124ce8b828c01611f7d565b975050604089013567ffffffffffffffff8111156124ef576124ee611d75565b5b6124fb8b828c01611f7d565b965050606061250c8b828c01611fcc565b955050608061251d8b828c01611fcc565b94505060a061252e8b828c01611dc3565b93505060c089013567ffffffffffffffff81111561254f5761254e611d75565b5b61255b8b828c01611f7d565b92505060e061256c8b828c01611ff8565b9150509295985092959890939650565b600082825260208201905092915050565b7f46575f496e76616c696420616464726573730000000000000000000000000000600082015250565b60006125c360128361257c565b91506125ce8261258d565b602082019050919050565b600060208201905081810360008301526125f2816125b6565b9050919050565b7f46575f5472616e7366657220616d6f756e7420696e76616c6964000000000000600082015250565b600061262f601a8361257c565b915061263a826125f9565b602082019050919050565b6000602082019050818103600083015261265e81612622565b9050919050565b7f46575f496e73756666696369656e7420746f6b656e2062616c616e6365000000600082015250565b600061269b601d8361257c565b91506126a682612665565b602082019050919050565b600060208201905081810360008301526126ca8161268e565b9050919050565b600081519050919050565b60005b838110156126fa5780820151818401526020810190506126df565b83811115612709576000848401525b50505050565b600061271a826126d1565b612724818561257c565b93506127348185602086016126dc565b61273d81611e6f565b840191505092915050565b61275181611fab565b82525050565b6000610100820190508181036000830152612772818b61270f565b90508181036020830152612786818a61270f565b9050818103604083015261279a818961270f565b90506127a96060830188612748565b6127b66080830187612748565b81810360a08301526127c8818661270f565b90506127d760c0830185612748565b6127e460e0830184611e11565b9998505050505050505050565b7f46575f596f7520617265206e6f74204f70657261746f72000000000000000000600082015250565b600061282760178361257c565b9150612832826127f1565b602082019050919050565b600060208201905081810360008301526128568161281a565b9050919050565b7f46575f576974686472617720616d6f756e7420696e76616c6964000000000000600082015250565b6000612893601a8361257c565b915061289e8261285d565b602082019050919050565b600060208201905081810360008301526128c281612886565b9050919050565b7f46575f4e6f7420656e6f75676820616d6f756e7420746f207769746864726177600082015250565b60006128ff60208361257c565b915061290a826128c9565b602082019050919050565b6000602082019050818103600083015261292e816128f2565b9050919050565b7f46575f496e76616c69642061646d696e20616464726573730000000000000000600082015250565b600061296b60188361257c565b915061297682612935565b602082019050919050565b6000602082019050818103600083015261299a8161295e565b9050919050565b60006040820190506129b66000830185611e3b565b6129c36020830184612748565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000612a3382611fab565b9150612a3e83611fab565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115612a7357612a726129f9565b5b828201905092915050565b6000612a8982611fab565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415612abc57612abb6129f9565b5b600182019050919050565b7f46575f53756d206f662063617274206e6f74206d617463682073656e64206e6160008201527f7469766520616d6f756e74000000000000000000000000000000000000000000602082015250565b6000612b23602b8361257c565b9150612b2e82612ac7565b604082019050919050565b60006020820190508181036000830152612b5281612b16565b9050919050565b7f46575f4f70657261746f7220616c726561647920657869737473000000000000600082015250565b6000612b8f601a8361257c565b9150612b9a82612b59565b602082019050919050565b60006020820190508181036000830152612bbe81612b82565b9050919050565b7f46575f53756d206f662063617274206e6f74206d617463682073656e6420746f60008201527f6b656e20616d6f756e7400000000000000000000000000000000000000000000602082015250565b6000612c21602a8361257c565b9150612c2c82612bc5565b604082019050919050565b60006020820190508181036000830152612c5081612c14565b9050919050565b600081519050612c6681611fb5565b92915050565b600060208284031215612c8257612c81611d70565b5b6000612c9084828501612c57565b91505092915050565b7f46575f4f70657261746f72206e6f742073657475702079657400000000000000600082015250565b6000612ccf60198361257c565b9150612cda82612c99565b602082019050919050565b60006020820190508181036000830152612cfe81612cc2565b9050919050565b6000606082019050612d1a6000830186611e3b565b612d276020830185612748565b612d346040830184611e3b565b949350505050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000612d9860268361257c565b9150612da382612d3c565b604082019050919050565b60006020820190508181036000830152612dc781612d8b565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000612e0460208361257c565b9150612e0f82612dce565b602082019050919050565b60006020820190508181036000830152612e3381612df7565b9050919050565b6000606082019050612e4f6000830186611e3b565b612e5c6020830185611e3b565b612e696040830184612748565b949350505050565b600081519050612e8081611fe1565b92915050565b600060208284031215612e9c57612e9b611d70565b5b6000612eaa84828501612e71565b91505092915050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e60008201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b6000612f0f602a8361257c565b9150612f1a82612eb3565b604082019050919050565b60006020820190508181036000830152612f3e81612f02565b9050919050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f60008201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b6000612fa160268361257c565b9150612fac82612f45565b604082019050919050565b60006020820190508181036000830152612fd081612f94565b9050919050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b600061300d601d8361257c565b915061301882612fd7565b602082019050919050565b6000602082019050818103600083015261303c81613000565b9050919050565b600081519050919050565b600081905092915050565b600061306482613043565b61306e818561304e565b935061307e8185602086016126dc565b80840191505092915050565b60006130968284613059565b915081905092915050565b600060208201905081810360008301526130bb818461270f565b90509291505056fea2646970667358221220ce4a8b53ae754bc95748cb81e726fd9156b8efeb84286d66c97be94d4a40f17f64736f6c63430008090033
Verified Source Code Full Match
Compiler: v0.8.9+commit.e5eed63a
EVM: london
Optimization: No
IERC20.sol 82 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @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);
/**
* @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 `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, 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 `from` to `to` 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 from,
address to,
uint256 amount
) external returns (bool);
}
SafeMath.sol 227 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)
pragma solidity ^0.8.0;
// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.
/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
* now has built in overflow checking.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// 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 (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @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) {
return a + b;
}
/**
* @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 a - b;
}
/**
* @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) {
return a * b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting 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 a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
/**
* @dev Returns the integer division of two unsigned integers, reverting 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.
*/
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* 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,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}
ERC20.sol 383 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* The default value of {decimals} is 18. To select a different value for
* {decimals} you should overload it.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless this function is
* overridden;
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += amount;
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}
IERC20Metadata.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
Ownable.sol 83 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
ERC2771Context.sol 43 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (metatx/ERC2771Context.sol)
pragma solidity ^0.8.9;
import "../utils/Context.sol";
/**
* @dev Context variant with ERC2771 support.
*/
abstract contract ERC2771Context is Context {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address private immutable _trustedForwarder;
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(address trustedForwarder) {
_trustedForwarder = trustedForwarder;
}
function isTrustedForwarder(address forwarder) public view virtual returns (bool) {
return forwarder == _trustedForwarder;
}
function _msgSender() internal view virtual override returns (address sender) {
if (isTrustedForwarder(msg.sender)) {
// The assembly code is more direct than the Solidity version using `abi.decode`.
/// @solidity memory-safe-assembly
assembly {
sender := shr(96, calldataload(sub(calldatasize(), 20)))
}
} else {
return super._msgSender();
}
}
function _msgData() internal view virtual override returns (bytes calldata) {
if (isTrustedForwarder(msg.sender)) {
return msg.data[:msg.data.length - 20];
} else {
return super._msgData();
}
}
}
SafeERC20.sol 116 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.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 IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
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));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
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'
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) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @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. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
Context.sol 24 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
Address.sol 222 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @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
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @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].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
draft-IERC20Permit.sol 60 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
PurchaseGiftcard.sol 322 lines
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/metatx/ERC2771Context.sol";
contract PurchaseGiftcard is ERC2771Context, Ownable {
using SafeMath for uint256;
using SafeERC20 for IERC20;
struct CartItem {
string _voucherID;
string _fromFiatID;
string _toCryptoID;
uint256 _fiatDenomination;
uint256 _cryptoDenomination;
string _orderID;
}
address public adminAddress;
address public receiverAddress;
mapping(address => bool) public operators;
event PurchaseByCurrency(
string voucherID,
string fromFiatID,
string toCryptoID,
uint256 fiatDenomination,
uint256 cryptoAmount,
string orderID,
uint256 purchaseTime,
bool isSwap
);
event PurchaseByToken(
string voucherID,
string fromFiatID,
string toCryptoID,
uint256 fiatDenomination,
uint256 cryptoAmount,
string orderID,
uint256 purchaseTime,
bool isSwap
);
event WithdrawCurrency(address adminAddress, uint256 currencyAmount);
event WithdrawToken(
address adminAddress,
uint256 tokenAmount,
address tokenAddress
);
constructor(address _trustedForwarder) ERC2771Context(_trustedForwarder) {
adminAddress = _msgSender();
receiverAddress = _msgSender();
}
/* ****************** */
/* Internal View */
/* ****************** */
function _msgSender()
internal
view
virtual
override(Context, ERC2771Context)
returns (address)
{
return ERC2771Context._msgSender();
}
function _msgData()
internal
view
virtual
override(Context, ERC2771Context)
returns (bytes calldata)
{
return ERC2771Context._msgData();
}
// For owner
function setupOperator(address operatorAddress)
external
onlyOwner
isValidAddress(operatorAddress)
{
require(!operators[operatorAddress], "FW_Operator already exists");
operators[operatorAddress] = true;
}
function removeOperator(address operatorAddress)
external
onlyOwner
isValidAddress(operatorAddress)
{
require(operators[operatorAddress], "FW_Operator not setup yet");
operators[operatorAddress] = false;
}
function setAdminAddress(address _adminAddress)
external
onlyOwner
isValidAddress(_adminAddress)
{
adminAddress = _adminAddress;
}
function setReceiverAddress(address _receiverAddress)
external
onlyOwner
isValidAddress(_receiverAddress)
{
receiverAddress = _receiverAddress;
}
// For operator
function withdrawCurrency(uint256 currencyAmount) external onlyOperater {
require(currencyAmount > 0, "FW_Withdraw amount invalid");
require(
currencyAmount <= address(this).balance,
"FW_Not enough amount to withdraw"
);
require(adminAddress != address(0), "FW_Invalid admin address");
payable(adminAddress).transfer(currencyAmount);
emit WithdrawCurrency(adminAddress, currencyAmount);
}
function withdrawToken(uint256 tokenAmount, address tokenAddress)
external
onlyOperater
{
require(tokenAmount > 0, "FW_Withdraw amount invalid");
require(
tokenAmount <= IERC20(tokenAddress).balanceOf(address(this)),
"FW_Not enough amount to withdraw"
);
require(adminAddress != address(0), "FW_Invalid admin address");
IERC20(tokenAddress).safeTransfer(adminAddress, tokenAmount);
emit WithdrawToken(adminAddress, tokenAmount, tokenAddress);
}
function purchaseByCurrency(
string memory _voucherID,
string memory _fromFiatID,
string memory _toCryptoID,
uint256 _fiatDenomination,
string memory _orderID,
bool _isSwap
) external payable {
require(msg.value > 0, "FW_Transfer amount invalid");
require(_msgSender().balance >= 0, "FW_Insufficient token balance");
if (_isSwap) {
payable(receiverAddress).transfer(msg.value);
}
emit PurchaseByCurrency(
_voucherID,
_fromFiatID,
_toCryptoID,
_fiatDenomination,
msg.value,
_orderID,
block.timestamp,
_isSwap
);
}
function purchaseMultipleByCurrency(
CartItem[] memory _cartItems,
bool _isSwap
) external payable {
require(msg.value > 0, "FW_Transfer amount invalid");
require(_msgSender().balance >= 0, "FW_Insufficient token balance");
uint256 cartSum = 0;
for (uint256 i = 0; i < _cartItems.length; i++) {
cartSum = cartSum + _cartItems[i]._cryptoDenomination;
}
require(
msg.value == cartSum,
"FW_Sum of cart not match send native amount"
);
if (_isSwap) {
payable(receiverAddress).transfer(cartSum);
}
for (uint256 i = 0; i < _cartItems.length; i++) {
emit PurchaseByCurrency(
_cartItems[i]._voucherID,
_cartItems[i]._fromFiatID,
_cartItems[i]._toCryptoID,
_cartItems[i]._fiatDenomination,
_cartItems[i]._cryptoDenomination,
_cartItems[i]._orderID,
block.timestamp,
_isSwap
);
}
}
function purchaseByToken(
string memory _voucherID,
string memory _fromFiatID,
string memory _toCryptoID,
uint256 _fiatDenomination,
uint256 _cryptoAmount,
address token,
string memory _orderID,
bool _isSwap
) external {
require(_cryptoAmount >= 0, "FW_Transfer amount invalid");
require(
IERC20(token).balanceOf(_msgSender()) >= _cryptoAmount,
"FW_Insufficient token balance"
);
if (_isSwap) {
IERC20(token).safeTransferFrom(
_msgSender(),
receiverAddress,
_cryptoAmount
);
} else {
IERC20(token).safeTransferFrom(
_msgSender(),
address(this),
_cryptoAmount
);
}
emit PurchaseByToken(
_voucherID,
_fromFiatID,
_toCryptoID,
_fiatDenomination,
_cryptoAmount,
_orderID,
block.timestamp,
_isSwap
);
}
function purchaseMultipleByToken(
CartItem[] memory _cartItems,
uint256 _cryptoAmount,
bool _isSwap,
address token
) external {
require(_cryptoAmount >= 0, "FW_Transfer amount invalid");
uint256 cartSum = 0;
for (uint256 i = 0; i < _cartItems.length; i++) {
cartSum = cartSum + _cartItems[i]._cryptoDenomination;
}
require(
_cryptoAmount == cartSum,
"FW_Sum of cart not match send token amount"
);
require(
IERC20(token).balanceOf(_msgSender()) >= _cryptoAmount,
"FW_Insufficient token balance"
);
if (_isSwap) {
IERC20(token).safeTransferFrom(
_msgSender(),
receiverAddress,
_cryptoAmount
);
} else {
IERC20(token).safeTransferFrom(
_msgSender(),
address(this),
_cryptoAmount
);
}
for (uint256 i = 0; i < _cartItems.length; i++) {
emit PurchaseByToken(
_cartItems[i]._voucherID,
_cartItems[i]._fromFiatID,
_cartItems[i]._toCryptoID,
_cartItems[i]._fiatDenomination,
_cartItems[i]._cryptoDenomination,
_cartItems[i]._orderID,
block.timestamp,
_isSwap
);
}
}
modifier onlyOperater() {
require(operators[_msgSender()], "FW_You are not Operator");
_;
}
modifier isValidAddress(address _address) {
require(_address != address(0), "FW_Invalid address");
_;
}
}
Read Contract
adminAddress 0xfc6f9468 → address
isTrustedForwarder 0x572b6c05 → bool
operators 0x13e7c9d8 → bool
owner 0x8da5cb5b → address
receiverAddress 0x16fed3e2 → address
Write Contract 12 functions
These functions modify contract state and require a wallet transaction to execute.
purchaseByCurrency 0x38b24c2a
string _voucherID
string _fromFiatID
string _toCryptoID
uint256 _fiatDenomination
string _orderID
bool _isSwap
purchaseByToken 0xff53f05b
string _voucherID
string _fromFiatID
string _toCryptoID
uint256 _fiatDenomination
uint256 _cryptoAmount
address token
string _orderID
bool _isSwap
purchaseMultipleByCurrency 0x3a6700de
tuple[] _cartItems
bool _isSwap
purchaseMultipleByToken 0xf00e48aa
tuple[] _cartItems
uint256 _cryptoAmount
bool _isSwap
address token
removeOperator 0xac8a584a
address operatorAddress
renounceOwnership 0x715018a6
No parameters
setAdminAddress 0x2c1e816d
address _adminAddress
setReceiverAddress 0x8279c7db
address _receiverAddress
setupOperator 0x896f0171
address operatorAddress
transferOwnership 0xf2fde38b
address newOwner
withdrawCurrency 0x3c00a36c
uint256 currencyAmount
withdrawToken 0xbe4b1772
uint256 tokenAmount
address tokenAddress
Token Balances (1)
View Transfers →Recent Transactions
No transactions found for this address