Forkchoice Ethereum Mainnet

Address Contract Partially Verified

Address 0xe915058dF18e7Efe92aF5c44Df3F575FBA061B64
Balance 0 ETH
Nonce 1
Code Size 12026 bytes
Indexed Transactions 0 (1 on-chain, 0.8% indexed)
External Etherscan · Sourcify

Contract Bytecode

12026 bytes
0x608060405234801561001057600080fd5b506004361061018d5760003560e01c8063a017b3bf116100e3578063c0fd43b41161008c578063cbe45d1811610066578063cbe45d18146102cb578063d51b3a1b146102d3578063d9d10484146102db5761018d565b8063c0fd43b4146102a8578063c415b95c146102bb578063c5c03699146102c35761018d565b8063afa3363d116100bd578063afa3363d14610278578063b95459e41461028d578063bd11257c146102955761018d565b8063a017b3bf14610260578063a664eb8e14610268578063aec2bf59146102705761018d565b806351b42b0011610145578063840fdc781161011f578063840fdc781461022557806385a4b0de1461022d5780638c4751471461024d5761018d565b806351b42b00146101f557806370c62824146101fd5780637ecebe00146102125761018d565b80632630c12f116101765780632630c12f146101c557806337423d5e146101da57806345000dc8146101e25761018d565b80630f15f4c0146101925780631626ba7e1461019c575b600080fd5b61019a6102e3565b005b6101af6101aa36600461263b565b610332565b6040516101bc91906129f9565b60405180910390f35b6101cd6104cb565b6040516101bc91906127ee565b6101cd6104ef565b61019a6101f03660046124b1565b610513565b61019a61087b565b6102056108bf565b6040516101bc9190612923565b6102056102203660046123a2565b6108e3565b6102056108f5565b61024061023b3660046123da565b6108fc565b6040516101bc9190612918565b61019a61025b366004612570565b610cda565b61020561115f565b6101cd611183565b6102056111a7565b6102806111ad565b6040516101bc91906128b2565b6101cd6111bd565b6102406102a33660046125f0565b6111e1565b6102056102b63660046123a2565b611220565b6101cd611248565b6101cd61126c565b6101cd611290565b6101cd6112b4565b6101cd6112d8565b60006102ed611373565b90506102f88161137d565b7f0cc43938d137e7efade6a531f663e78c1fc75257b0d65ffda2fdaf70cb49cdf98160405161032791906127ee565b60405180910390a150565b6040517f4a4fbeec000000000000000000000000000000000000000000000000000000008152600090339073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002f84f6f613280fd4df11ab2480e777ba8bb6282a1690634a4fbeec906103a99084906004016127ee565b60206040518083038186803b1580156103c157600080fd5b505afa1580156103d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103f9919061261b565b156104085750600090506104c5565b6104918173ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561045157600080fd5b505afa158015610465573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061048991906123be565b859085611428565b156104bf57507f1626ba7e0000000000000000000000000000000000000000000000000000000090506104c5565b50600090505b92915050565b7f0000000000000000000000004ead68830f45d73478c93953ed56c532bffff4b581565b7f0000000000000000000000001663647389993181d13cb45e2113c5d92fa89e7081565b61051e888a84611493565b333014158061057857507f8c47514700000000000000000000000000000000000000000000000000000000610554836000611672565b7fffffffff0000000000000000000000000000000000000000000000000000000016145b6105b7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ae90612c4c565b60405180910390fd5b861580156105c457508515155b806105d7575086158015906105d7575085155b61060d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ae90612bde565b6060861561062757610622836000600461168e565b610629565b825b905060607ff3c56bcb8317dca4d93b75989c647335ccd94939f2863c4466c7964f0d15dc958b8b8b8b8b8b8b89805190602001206040516020016106759998979695949392919061292c565b604051602081830303815290604052905060006106b27f83713a68dca33ef314a9a9faab35e2a9ef37599514ba8bbec1879966ef71e6aa8361172c565b6040517f4a4fbeec00000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002f84f6f613280fd4df11ab2480e777ba8bb6282a1690634a4fbeec90610727908f906004016127ee565b60206040518083038186803b15801561073f57600080fd5b505afa158015610753573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610777919061261b565b156107ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ae90612cba565b6108378c73ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156107f757600080fd5b505afa15801561080b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061082f91906123be565b829086611428565b61086d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ae90612aa5565b505050505050505050505050565b6000610885611373565b90506108908161179d565b7f749cb6b4c510bc468cf6b9c2086d6f0a54d6b18e25d37bf3200e68eab0880c008160405161032791906127ee565b7f83713a68dca33ef314a9a9faab35e2a9ef37599514ba8bbec1879966ef71e6aa81565b60006020819052908152604090205481565b62278d0081565b600061090661227f565b6040518060e001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff1681526020018c81526020018b81526020018a73ffffffffffffffffffffffffffffffffffffffff16815260200189815260200188815250905060005a9050603f61098f896040611843565b8161099657fe5b048110156109d0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ae90612c15565b604082015115610a50576109ec826000015183604001516111e1565b610a22576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ae90612bde565b604080830151835173ffffffffffffffffffffffffffffffffffffffff166000908152602081905291909120555b816020015173ffffffffffffffffffffffffffffffffffffffff168260c001516000898986600001518760600151604051602001610a919493929190612734565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052610ac99161277a565b600060405180830381858888f193505050503d8060008114610b07576040519150601f19603f3d011682016040523d82523d6000602084013e610b0c565b606091505b505080935050610bb9826000015183602001518460400151856060015186608001518760a001518860c001518e8e8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508d8d8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061051392505050565b6000601060e086890101025a8303016101bf016159d80190506000808460a00151118015610bf0575060608401511580610bf05750845b90508015610c7d57608084015161ff149092019173ffffffffffffffffffffffffffffffffffffffff16610c2657613a98820391505b60008460c00151831115610c3e578460c00151610c40565b825b9050610c7b85600001517f000000000000000000000000ee94cf48924b720af939e732e98f30f9594f87c587608001518860a0015185611891565b505b8351604080860151606087015191517fe685e02371cebe44a5d2cf72edfeea9b8426d318eb9b70869bc667ec5a7069a193610cbf93339391928b90899061280f565b60405180910390a1505050509b9a5050505050505050505050565b610ce261197e565b15610d19576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ae90612a6e565b846000610d24611373565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161480610e1957508173ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610da157600080fd5b505afa158015610db5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd991906123be565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16148015610e195750610e1782611a25565b155b610e4f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ae90612b81565b6040517fafaee9f100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002f84f6f613280fd4df11ab2480e777ba8bb6282a169063afaee9f190610ec690859062278d009060040161288c565b600060405180830381600087803b158015610ee057600080fd5b505af1158015610ef4573d6000803e3d6000fd5b5050508584149050610f32576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ae90612d28565b60005b858110156111555730878783818110610f4a57fe5b9050602002016020810190610f5f91906123a2565b73ffffffffffffffffffffffffffffffffffffffff161415610fad576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ae90612c4c565b61102a878783818110610fbc57fe5b9050602002016020810190610fd191906123a2565b89878785818110610fde57fe5b9050602002810190610ff09190612da7565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061149392505050565b600087878381811061103857fe5b905060200201602081019061104d91906123a2565b73ffffffffffffffffffffffffffffffffffffffff1686868481811061106f57fe5b90506020028101906110819190612da7565b6040516110979291908d90600090602001612734565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526110cf9161277a565b6000604051808303816000865af19150503d806000811461110c576040519150601f19603f3d011682016040523d82523d6000602084013e611111565b606091505b505090508061114c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ae90612b13565b50600101610f35565b5050505050505050565b7ff3c56bcb8317dca4d93b75989c647335ccd94939f2863c4466c7964f0d15dc9581565b7f000000000000000000000000e915058df18e7efe92af5c44df3f575fba061b6481565b61f61881565b60606111b7611aea565b90505b90565b7f000000000000000000000000c8af9c2389af5710dba268050ebf9350cd0acab381565b73ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604081205482118015611219575043608083901c11155b9392505050565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b7f000000000000000000000000ee94cf48924b720af939e732e98f30f9594f87c581565b7f0000000000000000000000009fad9ffcea95c345d41055a63bd099e1a057610981565b7f000000000000000000000000c6ea970917451fe149537779c20f721eb5e71e7681565b7f0000000000000000000000002f84f6f613280fd4df11ab2480e777ba8bb6282a81565b7f00000000000000000000000015f50bb48ca4be1ad4a6ad5804b18fb7d198618f81565b6000804690507f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f836000015180519060200120846020015180519060200120838660400151604051602001611355959493929190612989565b60405160208183030381529060405280519060200120915050919050565b60006111b7611b55565b8060606113886111ad565b905060005b8151811015611422578273ffffffffffffffffffffffffffffffffffffffff1663b149206e8383815181106113be57fe5b6020026020010151306040518363ffffffff1660e01b81526004016113e4929190612a26565b600060405180830381600087803b1580156113fe57600080fd5b505af1158015611412573d6000803e3d6000fd5b50506001909201915061138d9050565b50505050565b600073ffffffffffffffffffffffffffffffffffffffff831661144d57506000611219565b61146c8373ffffffffffffffffffffffffffffffffffffffff16611c12565b6114805761147b848484611c49565b61148b565b61148b848484611d83565b949350505050565b6040517f1c5ebe2f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c8af9c2389af5710dba268050ebf9350cd0acab31690631c5ebe2f906115059086906004016127ee565b60206040518083038186803b15801561151d57600080fd5b505afa158015611531573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611555919061261b565b806115e157508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161480156115e157507f1ed86f19000000000000000000000000000000000000000000000000000000006115bd826000611672565b7fffffffff0000000000000000000000000000000000000000000000000000000016145b8061163757507f0000000000000000000000009fad9ffcea95c345d41055a63bd099e1a057610973ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16145b61166d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ae90612b4a565b505050565b6000816004018351101561168557600080fd5b50016020015190565b6060818301845110156116a057600080fd5b6060821580156116bb57604051915060208201604052611723565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156116f45780518352602092830192016116dc565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016604052505b50949350505050565b60006040518060400160405280600281526020017f190100000000000000000000000000000000000000000000000000000000000081525083838051906020012060405160200161177f93929190612796565b60405160208183030381529060405280519060200120905092915050565b8060606117a86111ad565b905060005b8151811015611422578273ffffffffffffffffffffffffffffffffffffffff1663b149206e8383815181106117de57fe5b602002602001015160006040518363ffffffff1660e01b8152600401611805929190612a26565b600060405180830381600087803b15801561181f57600080fd5b505af1158015611833573d6000803e3d6000fd5b5050600190920191506117ad9050565b81810282158061185b57508183828161185857fe5b04145b6104c5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ae90612cf1565b600061189d8284611843565b6040517f71689b2b00000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000015f50bb48ca4be1ad4a6ad5804b18fb7d198618f16906371689b2b90611938908990889087907f0000000000000000000000004ead68830f45d73478c93953ed56c532bffff4b590600401612854565b600060405180830381600087803b15801561195257600080fd5b505af1158015611966573d6000803e3d6000fd5b5050505061197686858784611edf565b505050505050565b6000603836108015906119c657503373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e915058df18e7efe92af5c44df3f575fba061b6416145b15611a1d57611a1660206000369050036000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506120319050565b90506111ba565b5060006111ba565b6040517f4a4fbeec00000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002f84f6f613280fd4df11ab2480e777ba8bb6282a1690634a4fbeec90611a9a9085906004016127ee565b60206040518083038186803b158015611ab257600080fd5b505afa158015611ac6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104c5919061261b565b60408051600180825281830190925260609160208083019080368337019050509050631626ba7e60e01b81600081518110611b2157fe5b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015290565b600060383610801590611b9d57503373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e915058df18e7efe92af5c44df3f575fba061b6416145b15611c0b57611a16611bf060346000369050036000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506120449050565b73ffffffffffffffffffffffffffffffffffffffff166111ba565b50336111ba565b6000813f801580159061121957507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470141592915050565b600073ffffffffffffffffffffffffffffffffffffffff8316611c6e57506000611219565b8151600090611c7e906001612070565b90506000611c8c84836120b2565b60ff166004811115611c9a57fe5b82855290506002816004811115611cad57fe5b1415611cf257611cbd86856120ce565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16149250611d76565b6003816004811115611d0057fe5b1415611d7157600086604051602001611d1991906127bd565b604051602081830303815290604052805190602001209050611d3b81866120ce565b73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614935050611d76565b600092505b5060010182529392505050565b60006060631626ba7e60e01b8584604051602401611da29291906129c2565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050600060608573ffffffffffffffffffffffffffffffffffffffff1683604051611e2a919061277a565b600060405180830381855afa9150503d8060008114611e65576040519150601f19603f3d011682016040523d82523d6000602084013e611e6a565b606091505b5091509150818015611e7d575080516020145b8015611ed457507f1626ba7e00000000000000000000000000000000000000000000000000000000611eb0826000611672565b7fffffffff0000000000000000000000000000000000000000000000000000000016145b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff8316611f1b57611f15848383604051806020016040528060008152506121a6565b50611422565b606063a9059cbb60e01b8383604051602401611f3892919061288c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290506060611fc686866000856121a6565b905060008151600014611fec5781806020019051810190611fe7919061261b565b611fef565b60015b905080612028576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ae90612c83565b50505050505050565b6000816020018351101561168557600080fd5b6000816014018351101561205757600080fd5b5001602001516c01000000000000000000000000900490565b6000828211156120ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ae90612adc565b50900390565b600081600101835110156120c557600080fd5b50016001015190565b600081516041146120e1575060006104c5565b60208201516040830151604184015160ff167f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a082111561212757600093505050506104c5565b8060ff16601b148061213c57508060ff16601c145b1561219a576001868285856040516000815260200160405260405161216494939291906129db565b6020604051602081039080840390855afa158015612186573d6000803e3d6000fd5b5050506020604051035193505050506104c5565b600093505050506104c5565b6040517f7122b74c00000000000000000000000000000000000000000000000000000000815260609073ffffffffffffffffffffffffffffffffffffffff861690637122b74c9061220290600190889088908890600401612d5f565b600060405180830381600087803b15801561221c57600080fd5b505af1158015612230573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526122769190810190612680565b95945050505050565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b80356104c581612e9f565b60008083601f8401126122d7578182fd5b50813567ffffffffffffffff8111156122ee578182fd5b602083019150836020808302850101111561230857600080fd5b9250929050565b60008083601f840112612320578182fd5b50813567ffffffffffffffff811115612337578182fd5b60208301915083602082850101111561230857600080fd5b600082601f83011261235f578081fd5b813561237261236d82612e31565b612e0a565b915080825283602082850101111561238957600080fd5b8060208401602084013760009082016020015292915050565b6000602082840312156123b3578081fd5b813561121981612e9f565b6000602082840312156123cf578081fd5b815161121981612e9f565b60008060008060008060008060008060006101208c8e0312156123fb578687fd5b6124058c35612e9f565b8b359a5061241660208d0135612e9f565b60208c0135995060408c0135985060608c013597506124388d60808e016122bb565b965060a08c0135955060c08c0135945067ffffffffffffffff8060e08e01351115612461578485fd5b6124718e60e08f01358f0161230f565b90955093506101008d0135811015612487578283fd5b506124998d6101008e01358e0161230f565b81935080925050509295989b509295989b9093969950565b60008060008060008060008060006101208a8c0312156124cf578485fd5b89356124da81612e9f565b985060208a01356124ea81612e9f565b975060408a0135965060608a013595506125078b60808c016122bb565b945060a08a0135935060c08a0135925060e08a013567ffffffffffffffff80821115612531578384fd5b61253d8d838e0161234f565b93506101008c0135915080821115612553578283fd5b506125608c828d0161234f565b9150509295985092959850929598565b600080600080600060608688031215612587578081fd5b853561259281612e9f565b9450602086013567ffffffffffffffff808211156125ae578283fd5b6125ba89838a016122c6565b909650945060408801359150808211156125d2578283fd5b506125df888289016122c6565b969995985093965092949392505050565b60008060408385031215612602578182fd5b823561260d81612e9f565b946020939093013593505050565b60006020828403121561262c578081fd5b81518015158114611219578182fd5b6000806040838503121561264d578182fd5b82359150602083013567ffffffffffffffff81111561266a578182fd5b6126768582860161234f565b9150509250929050565b600060208284031215612691578081fd5b815167ffffffffffffffff8111156126a7578182fd5b8201601f810184136126b7578182fd5b80516126c561236d82612e31565b8181528560208385010111156126d9578384fd5b612276826020830160208601612e73565b60008151808452612702816020860160208601612e73565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000848683375060609290921b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016919092019081526014810191909152603401919050565b6000825161278c818460208701612e73565b9190910192915050565b600084516127a8818460208901612e73565b91909101928352506020820152604001919050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b73ffffffffffffffffffffffffffffffffffffffff9687168152949095166020850152604084019290925260608301521515608082015260a081019190915260c00190565b73ffffffffffffffffffffffffffffffffffffffff948516815292841660208401526040830191909152909116606082015260800190565b73ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b8181101561290c5783517fffffffff0000000000000000000000000000000000000000000000000000000016835292840192918401916001016128ce565b50909695505050505050565b901515815260200190565b90815260200190565b98895273ffffffffffffffffffffffffffffffffffffffff97881660208a015295871660408901526060880194909452608087019290925290931660a085015260c084019290925260e08301919091526101008201526101200190565b94855260208501939093526040840191909152606083015273ffffffffffffffffffffffffffffffffffffffff16608082015260a00190565b60008382526040602083015261148b60408301846126ea565b93845260ff9290921660208401526040830152606082015260800190565b7fffffffff0000000000000000000000000000000000000000000000000000000091909116815260200190565b7fffffffff0000000000000000000000000000000000000000000000000000000092909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60208082526015908201527f494e56414c49445f54585f41574152455f484153480000000000000000000000604082015260600190565b60208082526011908201527f494e56414c49445f5349474e4154555245000000000000000000000000000000604082015260600190565b6020808252600d908201527f5355425f554e444552464c4f5700000000000000000000000000000000000000604082015260600190565b60208082526013908201527f424154434845445f43414c4c5f4641494c454400000000000000000000000000604082015260600190565b6020808252601d908201527f494e56414c49445f44455354494e4154494f4e5f4f525f4d4554484f44000000604082015260600190565b60208082526029908201527f4e4f545f46524f4d5f57414c4c45545f4f525f4f574e45525f4f525f57414c4c60408201527f45545f4c4f434b45440000000000000000000000000000000000000000000000606082015260800190565b6020808252600d908201527f494e56414c49445f4e4f4e434500000000000000000000000000000000000000604082015260600190565b60208082526019908201527f4f50455241544f525f494e53554646494349454e545f47415300000000000000604082015260600190565b6020808252600e908201527f494e56414c49445f544152474554000000000000000000000000000000000000604082015260600190565b60208082526015908201527f45524332305f5452414e534645525f4641494c45440000000000000000000000604082015260600190565b6020808252600d908201527f57414c4c45545f4c4f434b454400000000000000000000000000000000000000604082015260600190565b6020808252600c908201527f4d554c5f4f564552464c4f570000000000000000000000000000000000000000604082015260600190565b6020808252600c908201527f494e56414c49445f444154410000000000000000000000000000000000000000604082015260600190565b600060ff8616825273ffffffffffffffffffffffffffffffffffffffff8516602083015283604083015260806060830152612d9d60808301846126ea565b9695505050505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612ddb578283fd5b83018035915067ffffffffffffffff821115612df5578283fd5b60200191503681900382131561230857600080fd5b60405181810167ffffffffffffffff81118282101715612e2957600080fd5b604052919050565b600067ffffffffffffffff821115612e47578081fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b83811015612e8e578181015183820152602001612e76565b838111156114225750506000910152565b73ffffffffffffffffffffffffffffffffffffffff81168114612ec157600080fd5b5056fea26469706673582212209b598f470371d5cad3e2e5137947b13a97d8f3d5d252a6498bf33044cebb822c64736f6c63430007000033

Verified Source Code Partial Match

Compiler: v0.7.0+commit.9e61f92b EVM: istanbul Optimization: Yes (999999 runs)
FinalCoreModule.sol 5043 lines
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
// File: contracts/iface/Wallet.sol

// Copyright 2017 Loopring Technology Limited.


/// @title Wallet
/// @dev Base contract for smart wallets.
///      Sub-contracts must NOT use non-default constructor to initialize
///      wallet states, instead, `init` shall be used. This is to enable
///      proxies to be deployed in front of the real wallet contract for
///      saving gas.
///
/// @author Daniel Wang - <[email protected]>
interface Wallet
{
    function version() external pure returns (string memory);

    function owner() external view returns (address);

    /// @dev Set a new owner.
    function setOwner(address newOwner) external;

    /// @dev Adds a new module. The `init` method of the module
    ///      will be called with `address(this)` as the parameter.
    ///      This method must throw if the module has already been added.
    /// @param _module The module's address.
    function addModule(address _module) external;

    /// @dev Removes an existing module. This method must throw if the module
    ///      has NOT been added or the module is the wallet's only module.
    /// @param _module The module's address.
    function removeModule(address _module) external;

    /// @dev Checks if a module has been added to this wallet.
    /// @param _module The module to check.
    /// @return True if the module exists; False otherwise.
    function hasModule(address _module) external view returns (bool);

    /// @dev Binds a method from the given module to this
    ///      wallet so the method can be invoked using this wallet's default
    ///      function.
    ///      Note that this method must throw when the given module has
    ///      not been added to this wallet.
    /// @param _method The method's 4-byte selector.
    /// @param _module The module's address. Use address(0) to unbind the method.
    function bindMethod(bytes4 _method, address _module) external;

    /// @dev Returns the module the given method has been bound to.
    /// @param _method The method's 4-byte selector.
    /// @return _module The address of the bound module. If no binding exists,
    ///                 returns address(0) instead.
    function boundMethodModule(bytes4 _method) external view returns (address _module);

    /// @dev Performs generic transactions. Any module that has been added to this
    ///      wallet can use this method to transact on any third-party contract with
    ///      msg.sender as this wallet itself.
    ///
    ///      Note: 1) this method must ONLY allow invocations from a module that has
    ///      been added to this wallet. The wallet owner shall NOT be permitted
    ///      to call this method directly. 2) Reentrancy inside this function should
    ///      NOT cause any problems.
    ///
    /// @param mode The transaction mode, 1 for CALL, 2 for DELEGATECALL.
    /// @param to The desitination address.
    /// @param value The amount of Ether to transfer.
    /// @param data The data to send over using `to.call{value: value}(data)`
    /// @return returnData The transaction's return value.
    function transact(
        uint8    mode,
        address  to,
        uint     value,
        bytes    calldata data
        )
        external
        returns (bytes memory returnData);
}

// File: contracts/lib/AddressUtil.sol

// Copyright 2017 Loopring Technology Limited.


/// @title Utility Functions for addresses
/// @author Daniel Wang - <[email protected]>
/// @author Brecht Devos - <[email protected]>
library AddressUtil
{
    using AddressUtil for *;

    function isContract(
        address addr
        )
        internal
        view
        returns (bool)
    {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(addr) }
        return (codehash != 0x0 &&
                codehash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470);
    }

    function toPayable(
        address addr
        )
        internal
        pure
        returns (address payable)
    {
        return payable(addr);
    }

    // Works like address.send but with a customizable gas limit
    // Make sure your code is safe for reentrancy when using this function!
    function sendETH(
        address to,
        uint    amount,
        uint    gasLimit
        )
        internal
        returns (bool success)
    {
        if (amount == 0) {
            return true;
        }
        address payable recipient = to.toPayable();
        /* solium-disable-next-line */
        (success,) = recipient.call{value: amount, gas: gasLimit}("");
    }

    // Works like address.transfer but with a customizable gas limit
    // Make sure your code is safe for reentrancy when using this function!
    function sendETHAndVerify(
        address to,
        uint    amount,
        uint    gasLimit
        )
        internal
        returns (bool success)
    {
        success = to.sendETH(amount, gasLimit);
        require(success, "TRANSFER_FAILURE");
    }

    // Works like call but is slightly more efficient when data
    // needs to be copied from memory to do the call.
    function fastCall(
        address to,
        uint    gasLimit,
        uint    value,
        bytes   memory data
        )
        internal
        returns (bool success, bytes memory returnData)
    {
        if (to != address(0)) {
            assembly {
                // Do the call
                success := call(gasLimit, to, value, add(data, 32), mload(data), 0, 0)
                // Copy the return data
                let size := returndatasize()
                returnData := mload(0x40)
                mstore(returnData, size)
                returndatacopy(add(returnData, 32), 0, size)
                // Update free memory pointer
                mstore(0x40, add(returnData, add(32, size)))
            }
        }
    }

    // Like fastCall, but throws when the call is unsuccessful.
    function fastCallAndVerify(
        address to,
        uint    gasLimit,
        uint    value,
        bytes   memory data
        )
        internal
        returns (bytes memory returnData)
    {
        bool success;
        (success, returnData) = fastCall(to, gasLimit, value, data);
        if (!success) {
            assembly {
                revert(add(returnData, 32), mload(returnData))
            }
        }
    }
}

// File: contracts/lib/ERC1271.sol

// Copyright 2017 Loopring Technology Limited.

abstract contract ERC1271 {
    // bytes4(keccak256("isValidSignature(bytes32,bytes)")
    bytes4 constant internal ERC1271_MAGICVALUE = 0x1626ba7e;

    function isValidSignature(
        bytes32      _hash,
        bytes memory _signature)
        public
        view
        virtual
        returns (bytes4 magicValueB32);
}

// File: contracts/thirdparty/BytesUtil.sol

//Mainly taken from https://github.com/GNSPS/solidity-bytes-utils/blob/master/contracts/BytesLib.sol

library BytesUtil {
    function slice(
        bytes memory _bytes,
        uint _start,
        uint _length
    )
        internal
        pure
        returns (bytes memory)
    {
        require(_bytes.length >= (_start + _length));

        bytes memory tempBytes;

        assembly {
            switch iszero(_length)
            case 0 {
                // Get a location of some free memory and store it in tempBytes as
                // Solidity does for memory variables.
                tempBytes := mload(0x40)

                // The first word of the slice result is potentially a partial
                // word read from the original array. To read it, we calculate
                // the length of that partial word and start copying that many
                // bytes into the array. The first word we copy will start with
                // data we don't care about, but the last `lengthmod` bytes will
                // land at the beginning of the contents of the new array. When
                // we're done copying, we overwrite the full first word with
                // the actual length of the slice.
                let lengthmod := and(_length, 31)

                // The multiplication in the next line is necessary
                // because when slicing multiples of 32 bytes (lengthmod == 0)
                // the following copy loop was copying the origin's length
                // and then ending prematurely not copying everything it should.
                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                let end := add(mc, _length)

                for {
                    // The multiplication in the next line has the same exact purpose
                    // as the one above.
                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                } lt(mc, end) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    mstore(mc, mload(cc))
                }

                mstore(tempBytes, _length)

                //update free-memory pointer
                //allocating the array padded to 32 bytes like the compiler does now
                mstore(0x40, and(add(mc, 31), not(31)))
            }
            //if we want a zero-length slice let's just return a zero-length array
            default {
                tempBytes := mload(0x40)

                mstore(0x40, add(tempBytes, 0x20))
            }
        }

        return tempBytes;
    }

    function toAddress(bytes memory _bytes, uint _start) internal  pure returns (address) {
        require(_bytes.length >= (_start + 20));
        address tempAddress;

        assembly {
            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
        }

        return tempAddress;
    }

    function toUint8(bytes memory _bytes, uint _start) internal  pure returns (uint8) {
        require(_bytes.length >= (_start + 1));
        uint8 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x1), _start))
        }

        return tempUint;
    }

    function toUint16(bytes memory _bytes, uint _start) internal  pure returns (uint16) {
        require(_bytes.length >= (_start + 2));
        uint16 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x2), _start))
        }

        return tempUint;
    }

    function toUint24(bytes memory _bytes, uint _start) internal  pure returns (uint24) {
        require(_bytes.length >= (_start + 3));
        uint24 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x3), _start))
        }

        return tempUint;
    }

    function toUint32(bytes memory _bytes, uint _start) internal  pure returns (uint32) {
        require(_bytes.length >= (_start + 4));
        uint32 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x4), _start))
        }

        return tempUint;
    }

    function toUint64(bytes memory _bytes, uint _start) internal  pure returns (uint64) {
        require(_bytes.length >= (_start + 8));
        uint64 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x8), _start))
        }

        return tempUint;
    }

    function toUint96(bytes memory _bytes, uint _start) internal  pure returns (uint96) {
        require(_bytes.length >= (_start + 12));
        uint96 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0xc), _start))
        }

        return tempUint;
    }

    function toUint128(bytes memory _bytes, uint _start) internal  pure returns (uint128) {
        require(_bytes.length >= (_start + 16));
        uint128 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x10), _start))
        }

        return tempUint;
    }

    function toUint(bytes memory _bytes, uint _start) internal  pure returns (uint256) {
        require(_bytes.length >= (_start + 32));
        uint256 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x20), _start))
        }

        return tempUint;
    }

    function toBytes4(bytes memory _bytes, uint _start) internal  pure returns (bytes4) {
        require(_bytes.length >= (_start + 4));
        bytes4 tempBytes4;

        assembly {
            tempBytes4 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes4;
    }

    function toBytes32(bytes memory _bytes, uint _start) internal  pure returns (bytes32) {
        require(_bytes.length >= (_start + 32));
        bytes32 tempBytes32;

        assembly {
            tempBytes32 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes32;
    }

    function fastSHA256(
        bytes memory data
        )
        internal
        view
        returns (bytes32)
    {
        bytes32[] memory result = new bytes32[](1);
        bool success;
        assembly {
             let ptr := add(data, 32)
             success := staticcall(sub(gas(), 2000), 2, ptr, mload(data), add(result, 32), 32)
        }
        require(success, "SHA256_FAILED");
        return result[0];
    }
}

// File: contracts/lib/MathUint.sol

// Copyright 2017 Loopring Technology Limited.


/// @title Utility Functions for uint
/// @author Daniel Wang - <[email protected]>
library MathUint
{
    function mul(
        uint a,
        uint b
        )
        internal
        pure
        returns (uint c)
    {
        c = a * b;
        require(a == 0 || c / a == b, "MUL_OVERFLOW");
    }

    function sub(
        uint a,
        uint b
        )
        internal
        pure
        returns (uint)
    {
        require(b <= a, "SUB_UNDERFLOW");
        return a - b;
    }

    function add(
        uint a,
        uint b
        )
        internal
        pure
        returns (uint c)
    {
        c = a + b;
        require(c >= a, "ADD_OVERFLOW");
    }
}

// File: contracts/lib/SignatureUtil.sol

// Copyright 2017 Loopring Technology Limited.






/// @title SignatureUtil
/// @author Daniel Wang - <[email protected]>
/// @dev This method supports multihash standard. Each signature's last byte indicates
///      the signature's type.
library SignatureUtil
{
    using BytesUtil     for bytes;
    using MathUint      for uint;
    using AddressUtil   for address;

    enum SignatureType {
        ILLEGAL,
        INVALID,
        EIP_712,
        ETH_SIGN,
        WALLET   // deprecated
    }

    bytes4 constant internal ERC1271_MAGICVALUE = 0x1626ba7e;

    function verifySignatures(
        bytes32          signHash,
        address[] memory signers,
        bytes[]   memory signatures
        )
        internal
        view
        returns (bool)
    {
        require(signers.length == signatures.length, "BAD_SIGNATURE_DATA");
        address lastSigner;
        for (uint i = 0; i < signers.length; i++) {
            require(signers[i] > lastSigner, "INVALID_SIGNERS_ORDER");
            lastSigner = signers[i];
            if (!verifySignature(signHash, signers[i], signatures[i])) {
                return false;
            }
        }
        return true;
    }

    function verifySignature(
        bytes32        signHash,
        address        signer,
        bytes   memory signature
        )
        internal
        view
        returns (bool)
    {
        if (signer == address(0)) {
            return false;
        }

        return signer.isContract()?
            verifyERC1271Signature(signHash, signer, signature):
            verifyEOASignature(signHash, signer, signature);
    }

    function recoverECDSASigner(
        bytes32      signHash,
        bytes memory signature
        )
        internal
        pure
        returns (address)
    {
        if (signature.length != 65) {
            return address(0);
        }

        bytes32 r;
        bytes32 s;
        uint8   v;
        // we jump 32 (0x20) as the first slot of bytes contains the length
        // we jump 65 (0x41) per signature
        // for v we load 32 bytes ending with v (the first 31 come from s) then apply a mask
        assembly {
            r := mload(add(signature, 0x20))
            s := mload(add(signature, 0x40))
            v := and(mload(add(signature, 0x41)), 0xff)
        }
        // See https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/cryptography/ECDSA.sol
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return address(0);
        }
        if (v == 27 || v == 28) {
            return ecrecover(signHash, v, r, s);
        } else {
            return address(0);
        }
    }

    function verifyEOASignature(
        bytes32        signHash,
        address        signer,
        bytes   memory signature
        )
        private
        pure
        returns (bool success)
    {
        if (signer == address(0)) {
            return false;
        }

        uint signatureTypeOffset = signature.length.sub(1);
        SignatureType signatureType = SignatureType(signature.toUint8(signatureTypeOffset));

        // Strip off the last byte of the signature by updating the length
        assembly {
            mstore(signature, signatureTypeOffset)
        }

        if (signatureType == SignatureType.EIP_712) {
            success = (signer == recoverECDSASigner(signHash, signature));
        } else if (signatureType == SignatureType.ETH_SIGN) {
            bytes32 hash = keccak256(
                abi.encodePacked("\x19Ethereum Signed Message:\n32", signHash)
            );
            success = (signer == recoverECDSASigner(hash, signature));
        } else {
            success = false;
        }

        // Restore the signature length
        assembly {
            mstore(signature, add(signatureTypeOffset, 1))
        }

        return success;
    }

    function verifyERC1271Signature(
        bytes32 signHash,
        address signer,
        bytes   memory signature
        )
        private
        view
        returns (bool)
    {
        bytes memory callData = abi.encodeWithSelector(
            ERC1271.isValidSignature.selector,
            signHash,
            signature
        );
        (bool success, bytes memory result) = signer.staticcall(callData);
        return (
            success &&
            result.length == 32 &&
            result.toBytes4(0) == ERC1271_MAGICVALUE
        );
    }
}

// File: contracts/lib/EIP712.sol

// Copyright 2017 Loopring Technology Limited.

library EIP712
{
    struct Domain {
        string  name;
        string  version;
        address verifyingContract;
    }

    bytes32 constant internal EIP712_DOMAIN_TYPEHASH = keccak256(
        "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
    );

    string constant internal EIP191_HEADER = "\x19\x01";

    function hash(Domain memory domain)
        internal
        pure
        returns (bytes32)
    {
        uint _chainid;
        assembly { _chainid := chainid() }

        return keccak256(
            abi.encode(
                EIP712_DOMAIN_TYPEHASH,
                keccak256(bytes(domain.name)),
                keccak256(bytes(domain.version)),
                _chainid,
                domain.verifyingContract
            )
        );
    }

    function hashPacked(
        bytes32 domainSeperator,
        bytes   memory encodedData
        )
        internal
        pure
        returns (bytes32)
    {
        return keccak256(
            abi.encodePacked(EIP191_HEADER, domainSeperator, keccak256(encodedData))
        );
    }
}

// File: contracts/lib/Ownable.sol

// Copyright 2017 Loopring Technology Limited.


/// @title Ownable
/// @author Brecht Devos - <[email protected]>
/// @dev The Ownable contract has an owner address, and provides basic
///      authorization control functions, this simplifies the implementation of
///      "user permissions".
contract Ownable
{
    address public owner;

    event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
    );

    /// @dev The Ownable constructor sets the original `owner` of the contract
    ///      to the sender.
    constructor()
    {
        owner = msg.sender;
    }

    /// @dev Throws if called by any account other than the owner.
    modifier onlyOwner()
    {
        require(msg.sender == owner, "UNAUTHORIZED");
        _;
    }

    /// @dev Allows the current owner to transfer control of the contract to a
    ///      new owner.
    /// @param newOwner The address to transfer ownership to.
    function transferOwnership(
        address newOwner
        )
        public
        virtual
        onlyOwner
    {
        require(newOwner != address(0), "ZERO_ADDRESS");
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
    }

    function renounceOwnership()
        public
        onlyOwner
    {
        emit OwnershipTransferred(owner, address(0));
        owner = address(0);
    }
}

// File: contracts/iface/Module.sol

// Copyright 2017 Loopring Technology Limited.




/// @title Module
/// @dev Base contract for all smart wallet modules.
///
/// @author Daniel Wang - <[email protected]>
interface Module
{
    /// @dev Activates the module for the given wallet (msg.sender) after the module is added.
    ///      Warning: this method shall ONLY be callable by a wallet.
    function activate() external;

    /// @dev Deactivates the module for the given wallet (msg.sender) before the module is removed.
    ///      Warning: this method shall ONLY be callable by a wallet.
    function deactivate() external;
}

// File: contracts/lib/ERC20.sol

// Copyright 2017 Loopring Technology Limited.


/// @title ERC20 Token Interface
/// @dev see https://github.com/ethereum/EIPs/issues/20
/// @author Daniel Wang - <[email protected]>
abstract contract ERC20
{
    function totalSupply()
        public
        view
        virtual
        returns (uint);

    function balanceOf(
        address who
        )
        public
        view
        virtual
        returns (uint);

    function allowance(
        address owner,
        address spender
        )
        public
        view
        virtual
        returns (uint);

    function transfer(
        address to,
        uint value
        )
        public
        virtual
        returns (bool);

    function transferFrom(
        address from,
        address to,
        uint    value
        )
        public
        virtual
        returns (bool);

    function approve(
        address spender,
        uint    value
        )
        public
        virtual
        returns (bool);
}

// File: contracts/iface/ModuleRegistry.sol

// Copyright 2017 Loopring Technology Limited.


/// @title ModuleRegistry
/// @dev A registry for modules.
///
/// @author Daniel Wang - <[email protected]>
interface ModuleRegistry
{
	/// @dev Registers and enables a new module.
    function registerModule(address module) external;

    /// @dev Disables a module
    function disableModule(address module) external;

    /// @dev Returns true if the module is registered and enabled.
    function isModuleEnabled(address module) external view returns (bool);

    /// @dev Returns the list of enabled modules.
    function enabledModules() external view returns (address[] memory _modules);

    /// @dev Returns the number of enbaled modules.
    function numOfEnabledModules() external view returns (uint);

    /// @dev Returns true if the module is ever registered.
    function isModuleRegistered(address module) external view returns (bool);
}

// File: contracts/base/Controller.sol

// Copyright 2017 Loopring Technology Limited.



/// @title Controller
///
/// @author Daniel Wang - <[email protected]>
abstract contract Controller
{
    function moduleRegistry()
        external
        view
        virtual
        returns (ModuleRegistry);

    function walletFactory()
        external
        view
        virtual
        returns (address);
}

// File: contracts/iface/PriceOracle.sol

// Copyright 2017 Loopring Technology Limited.


/// @title PriceOracle
interface PriceOracle
{
    // @dev Return's the token's value in ETH
    function tokenValue(address token, uint amount)
        external
        view
        returns (uint value);
}

// File: contracts/lib/Claimable.sol

// Copyright 2017 Loopring Technology Limited.



/// @title Claimable
/// @author Brecht Devos - <[email protected]>
/// @dev Extension for the Ownable contract, where the ownership needs
///      to be claimed. This allows the new owner to accept the transfer.
contract Claimable is Ownable
{
    address public pendingOwner;

    /// @dev Modifier throws if called by any account other than the pendingOwner.
    modifier onlyPendingOwner() {
        require(msg.sender == pendingOwner, "UNAUTHORIZED");
        _;
    }

    /// @dev Allows the current owner to set the pendingOwner address.
    /// @param newOwner The address to transfer ownership to.
    function transferOwnership(
        address newOwner
        )
        public
        override
        onlyOwner
    {
        require(newOwner != address(0) && newOwner != owner, "INVALID_ADDRESS");
        pendingOwner = newOwner;
    }

    /// @dev Allows the pendingOwner address to finalize the transfer.
    function claimOwnership()
        public
        onlyPendingOwner
    {
        emit OwnershipTransferred(owner, pendingOwner);
        owner = pendingOwner;
        pendingOwner = address(0);
    }
}

// File: contracts/base/DataStore.sol

// Copyright 2017 Loopring Technology Limited.



/// @title DataStore
/// @dev Modules share states by accessing the same storage instance.
///      Using ModuleStorage will achieve better module decoupling.
///
/// @author Daniel Wang - <[email protected]>
abstract contract DataStore
{
    modifier onlyWalletModule(address wallet)
    {
        requireWalletModule(wallet);
        _;
    }

    function requireWalletModule(address wallet) view internal
    {
        require(Wallet(wallet).hasModule(msg.sender), "UNAUTHORIZED");
    }
}

// File: contracts/stores/HashStore.sol

// Copyright 2017 Loopring Technology Limited.




/// @title HashStore
/// @dev This store maintains all hashes for SignedRequest.
contract HashStore is DataStore
{
    // wallet => hash => consumed
    mapping(address => mapping(bytes32 => bool)) public hashes;

    constructor() {}

    function verifyAndUpdate(address wallet, bytes32 hash)
        external
    {
        require(!hashes[wallet][hash], "HASH_EXIST");
        requireWalletModule(wallet);
        hashes[wallet][hash] = true;
    }
}

// File: contracts/thirdparty/SafeCast.sol

// Taken from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/SafeCast.sol



/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 *
 * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and `int256` and then downcasting.
 */
library SafeCast {

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        require(value < 2**96, "SafeCast: value doesn\'t fit in 96 bits");
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        require(value < 2**40, "SafeCast: value doesn\'t fit in 40 bits");
        return uint40(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value < 2**16, "SafeCast: value doesn\'t fit in 16 bits");
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value < 2**8, "SafeCast: value doesn\'t fit in 8 bits");
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "SafeCast: value must be positive");
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     *
     * _Available since v3.1._
     */
    function toInt128(int256 value) internal pure returns (int128) {
        require(value >= -2**127 && value < 2**127, "SafeCast: value doesn\'t fit in 128 bits");
        return int128(value);
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     *
     * _Available since v3.1._
     */
    function toInt64(int256 value) internal pure returns (int64) {
        require(value >= -2**63 && value < 2**63, "SafeCast: value doesn\'t fit in 64 bits");
        return int64(value);
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v3.1._
     */
    function toInt32(int256 value) internal pure returns (int32) {
        require(value >= -2**31 && value < 2**31, "SafeCast: value doesn\'t fit in 32 bits");
        return int32(value);
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     *
     * _Available since v3.1._
     */
    function toInt16(int256 value) internal pure returns (int16) {
        require(value >= -2**15 && value < 2**15, "SafeCast: value doesn\'t fit in 16 bits");
        return int16(value);
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     *
     * _Available since v3.1._
     */
    function toInt8(int256 value) internal pure returns (int8) {
        require(value >= -2**7 && value < 2**7, "SafeCast: value doesn\'t fit in 8 bits");
        return int8(value);
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        require(value < 2**255, "SafeCast: value doesn't fit in an int256");
        return int256(value);
    }
}

// File: contracts/stores/QuotaStore.sol

// Copyright 2017 Loopring Technology Limited.





/// @title QuotaStore
/// @dev This store maintains daily spending quota for each wallet.
///      A rolling daily limit is used.
contract QuotaStore is DataStore
{
    using MathUint for uint;
    using SafeCast for uint;

    uint128 public constant MAX_QUOTA = uint128(-1);

    // Optimized to fit into 64 bytes (2 slots)
    struct Quota
    {
        uint128 currentQuota;
        uint128 pendingQuota;
        uint128 spentAmount;
        uint64  spentTimestamp;
        uint64  pendingUntil;
    }

    mapping (address => Quota) public quotas;

    event QuotaScheduled(
        address wallet,
        uint    pendingQuota,
        uint64  pendingUntil
    );

    constructor()
        DataStore()
    {
    }

    // 0 for newQuota indicates unlimited quota, or daily quota is disabled.
    function changeQuota(
        address wallet,
        uint    newQuota,
        uint    effectiveTime
        )
        external
        onlyWalletModule(wallet)
    {
        require(newQuota <= MAX_QUOTA, "INVALID_VALUE");
        if (newQuota == MAX_QUOTA) {
            newQuota = 0;
        }

        quotas[wallet].currentQuota = currentQuota(wallet).toUint128();
        quotas[wallet].pendingQuota = newQuota.toUint128();
        quotas[wallet].pendingUntil = effectiveTime.toUint64();

        emit QuotaScheduled(
            wallet,
            newQuota,
            quotas[wallet].pendingUntil
        );
    }

    function checkAndAddToSpent(
        address     wallet,
        address     token,
        uint        amount,
        PriceOracle priceOracle
        )
        external
    {
        Quota memory q = quotas[wallet];
        uint available = _availableQuota(q);
        if (available != MAX_QUOTA) {
            uint value = (token == address(0)) ?
                amount :
                priceOracle.tokenValue(token, amount);
            if (value > 0) {
                require(available >= value, "QUOTA_EXCEEDED");
                requireWalletModule(wallet);
                _addToSpent(wallet, q, value);
            }
        }
    }

    function addToSpent(
        address wallet,
        uint    amount
        )
        external
        onlyWalletModule(wallet)
    {
        _addToSpent(wallet, quotas[wallet], amount);
    }

    // Returns 0 to indiciate unlimited quota
    function currentQuota(address wallet)
        public
        view
        returns (uint)
    {
        return _currentQuota(quotas[wallet]);
    }

    // Returns 0 to indiciate unlimited quota
    function pendingQuota(address wallet)
        public
        view
        returns (
            uint __pendingQuota,
            uint __pendingUntil
        )
    {
        return _pendingQuota(quotas[wallet]);
    }

    function spentQuota(address wallet)
        public
        view
        returns (uint)
    {
        return _spentQuota(quotas[wallet]);
    }

    function availableQuota(address wallet)
        public
        view
        returns (uint)
    {
        return _availableQuota(quotas[wallet]);
    }

    function hasEnoughQuota(
        address wallet,
        uint    requiredAmount
        )
        public
        view
        returns (bool)
    {
        return _hasEnoughQuota(quotas[wallet], requiredAmount);
    }

    // Internal

    function _currentQuota(Quota memory q)
        private
        view
        returns (uint)
    {
        return q.pendingUntil <= block.timestamp ? q.pendingQuota : q.currentQuota;
    }

    function _pendingQuota(Quota memory q)
        private
        view
        returns (
            uint __pendingQuota,
            uint __pendingUntil
        )
    {
        if (q.pendingUntil > 0 && q.pendingUntil > block.timestamp) {
            __pendingQuota = q.pendingQuota;
            __pendingUntil = q.pendingUntil;
        }
    }

    function _spentQuota(Quota memory q)
        private
        view
        returns (uint)
    {
        uint timeSinceLastSpent = block.timestamp.sub(q.spentTimestamp);
        if (timeSinceLastSpent < 1 days) {
            return uint(q.spentAmount).sub(timeSinceLastSpent.mul(q.spentAmount) / 1 days);
        } else {
            return 0;
        }
    }

    function _availableQuota(Quota memory q)
        private
        view
        returns (uint)
    {
        uint quota = _currentQuota(q);
        if (quota == 0) {
            return MAX_QUOTA;
        }
        uint spent = _spentQuota(q);
        return quota > spent ? quota - spent : 0;
    }

    function _hasEnoughQuota(
        Quota   memory q,
        uint    requiredAmount
        )
        private
        view
        returns (bool)
    {
        return _availableQuota(q) >= requiredAmount;
    }

    function _addToSpent(
        address wallet,
        Quota   memory q,
        uint    amount
        )
        private
    {
        Quota storage s = quotas[wallet];
        s.spentAmount = _spentQuota(q).add(amount).toUint128();
        s.spentTimestamp = uint64(block.timestamp);
    }
}

// File: contracts/stores/Data.sol

// Copyright 2017 Loopring Technology Limited.


library Data
{
    enum GuardianStatus {
        REMOVE,    // Being removed or removed after validUntil timestamp
        ADD        // Being added or added after validSince timestamp.
    }

    // Optimized to fit into 32 bytes (1 slot)
    struct Guardian
    {
        address addr;
        uint8   status;
        uint64  timestamp; // validSince if status = ADD; validUntil if adding = REMOVE;
    }
}

// File: contracts/stores/GuardianStore.sol

// Copyright 2017 Loopring Technology Limited.






/// @title GuardianStore
///
/// @author Daniel Wang - <[email protected]>
abstract contract GuardianStore is DataStore
{
    using MathUint      for uint;
    using SafeCast      for uint;

    struct Wallet
    {
        address    inheritor;
        uint32     inheritWaitingPeriod;
        uint64     lastActive; // the latest timestamp the owner is considered to be active
        bool       locked;

        Data.Guardian[]            guardians;
        mapping (address => uint)  guardianIdx;
    }

    mapping (address => Wallet) public wallets;

    constructor() DataStore() {}

    function isGuardian(
        address wallet,
        address addr,
        bool    includePendingAddition
        )
        public
        view
        returns (bool)
    {
        Data.Guardian memory g = _getGuardian(wallet, addr);
        return _isActiveOrPendingAddition(g, includePendingAddition);
    }

    function guardians(
        address wallet,
        bool    includePendingAddition
        )
        public
        view
        returns (Data.Guardian[] memory _guardians)
    {
        Wallet storage w = wallets[wallet];
        _guardians = new Data.Guardian[](w.guardians.length);
        uint index = 0;
        for (uint i = 0; i < w.guardians.length; i++) {
            Data.Guardian memory g = w.guardians[i];
            if (_isActiveOrPendingAddition(g, includePendingAddition)) {
                _guardians[index] = g;
                index++;
            }
        }
        assembly { mstore(_guardians, index) }
    }

    function numGuardians(
        address wallet,
        bool    includePendingAddition
        )
        public
        view
        returns (uint count)
    {
        Wallet storage w = wallets[wallet];
        for (uint i = 0; i < w.guardians.length; i++) {
            Data.Guardian memory g = w.guardians[i];
            if (_isActiveOrPendingAddition(g, includePendingAddition)) {
                count++;
            }
        }
    }

    function removeAllGuardians(address wallet)
        external
    {
        Wallet storage w = wallets[wallet];
        uint size = w.guardians.length;
        if (size == 0) return;

        requireWalletModule(wallet);
        for (uint i = 0; i < w.guardians.length; i++) {
            delete w.guardianIdx[w.guardians[i].addr];
        }
        delete w.guardians;
    }

    function cancelPendingGuardians(address wallet)
        external
    {
        bool cancelled = false;
        Wallet storage w = wallets[wallet];
        for (uint i = 0; i < w.guardians.length; i++) {
            Data.Guardian memory g = w.guardians[i];
            if (_isPendingAddition(g)) {
                w.guardians[i].status = uint8(Data.GuardianStatus.REMOVE);
                w.guardians[i].timestamp = 0;
                cancelled = true;
            }
            if (_isPendingRemoval(g)) {
                w.guardians[i].status = uint8(Data.GuardianStatus.ADD);
                w.guardians[i].timestamp = 0;
                cancelled = true;
            }
        }
        if (cancelled) {
            requireWalletModule(wallet);
        }
        _cleanRemovedGuardians(wallet, true);
    }

    function cleanRemovedGuardians(address wallet)
        external
    {
        _cleanRemovedGuardians(wallet, true);
    }

    function addGuardian(
        address wallet,
        address addr,
        uint    validSince,
        bool    alwaysOverride
        )
        external
        onlyWalletModule(wallet)
        returns (uint)
    {
        require(validSince >= block.timestamp, "INVALID_VALID_SINCE");
        require(addr != address(0), "ZERO_ADDRESS");

        Wallet storage w = wallets[wallet];
        uint pos = w.guardianIdx[addr];

        if(pos == 0) {
            // Add the new guardian
            Data.Guardian memory g = Data.Guardian(
                addr,
                uint8(Data.GuardianStatus.ADD),
                validSince.toUint64()
            );
            w.guardians.push(g);
            w.guardianIdx[addr] = w.guardians.length;

            _cleanRemovedGuardians(wallet, false);
            return validSince;
        }

        Data.Guardian memory g = w.guardians[pos - 1];

        if (_isRemoved(g)) {
            w.guardians[pos - 1].status = uint8(Data.GuardianStatus.ADD);
            w.guardians[pos - 1].timestamp = validSince.toUint64();
            return validSince;
        }

        if (_isPendingRemoval(g)) {
            w.guardians[pos - 1].status = uint8(Data.GuardianStatus.ADD);
            w.guardians[pos - 1].timestamp = 0;
            return 0;
        }

        if (_isPendingAddition(g)) {
            if (!alwaysOverride) return g.timestamp;

            w.guardians[pos - 1].timestamp = validSince.toUint64();
            return validSince;
        }

        require(_isAdded(g), "UNEXPECTED_RESULT");
        return 0;
    }

    function removeGuardian(
        address wallet,
        address addr,
        uint    validUntil,
        bool    alwaysOverride
        )
        external
        onlyWalletModule(wallet)
        returns (uint)
    {
        require(validUntil >= block.timestamp, "INVALID_VALID_UNTIL");
        require(addr != address(0), "ZERO_ADDRESS");

        Wallet storage w = wallets[wallet];
        uint pos = w.guardianIdx[addr];
        require(pos > 0, "GUARDIAN_NOT_EXISTS");

        Data.Guardian memory g = w.guardians[pos - 1];

        if (_isAdded(g)) {
            w.guardians[pos - 1].status = uint8(Data.GuardianStatus.REMOVE);
            w.guardians[pos - 1].timestamp = validUntil.toUint64();
            return validUntil;
        }

        if (_isPendingAddition(g)) {
            w.guardians[pos - 1].status = uint8(Data.GuardianStatus.REMOVE);
            w.guardians[pos - 1].timestamp = 0;
            return 0;
        }

        if (_isPendingRemoval(g)) {
            if (!alwaysOverride) return g.timestamp;

            w.guardians[pos - 1].timestamp = validUntil.toUint64();
            return validUntil;
        }

        require(_isRemoved(g), "UNEXPECTED_RESULT");
        return 0;
    }

    // ---- internal functions ---

    function _getGuardian(
        address wallet,
        address addr
        )
        private
        view
        returns (Data.Guardian memory)
    {
        Wallet storage w = wallets[wallet];
        uint pos = w.guardianIdx[addr];
        if (pos > 0) {
            return w.guardians[pos - 1];
        }
    }

    function _isAdded(Data.Guardian memory guardian)
        private
        view
        returns (bool)
    {
        return guardian.status == uint8(Data.GuardianStatus.ADD) &&
            guardian.timestamp <= block.timestamp;
    }

    function _isPendingAddition(Data.Guardian memory guardian)
        private
        view
        returns (bool)
    {
        return guardian.status == uint8(Data.GuardianStatus.ADD) &&
            guardian.timestamp > block.timestamp;
    }

    function _isRemoved(Data.Guardian memory guardian)
        private
        view
        returns (bool)
    {
        return guardian.status == uint8(Data.GuardianStatus.REMOVE) &&
            guardian.timestamp <= block.timestamp;
    }

    function _isPendingRemoval(Data.Guardian memory guardian)
        private
        view
        returns (bool)
    {
         return guardian.status == uint8(Data.GuardianStatus.REMOVE) &&
            guardian.timestamp > block.timestamp;
    }

    function _isActive(Data.Guardian memory guardian)
        private
        view
        returns (bool)
    {
        return _isAdded(guardian) || _isPendingRemoval(guardian);
    }

    function _isActiveOrPendingAddition(
        Data.Guardian memory guardian,
        bool includePendingAddition
        )
        private
        view
        returns (bool)
    {
        return _isAc...

// [truncated — 150105 bytes total]

Read Contract

FORWARDER_DOMAIN_SEPARATOR 0x70c62824 → bytes32
MAX_REIMBURSTMENT_OVERHEAD 0xaec2bf59 → uint256
META_TX_TYPEHASH 0xa017b3bf → bytes32
TOUCH_GRACE_PERIOD 0x840fdc78 → uint256
bindableMethods 0xafa3363d → bytes4[]
feeCollector 0xc415b95c → address
hashStore 0xcbe45d18 → address
isNonceValid 0xbd11257c → bool
isValidSignature 0x1626ba7e → bytes4
lastNonce 0xc0fd43b4 → uint256
metaTxForwarder 0xa664eb8e → address
moduleRegistry 0xb95459e4 → address
nonces 0x7ecebe00 → uint256
priceOracle 0x2630c12f → address
quotaStore 0xd9d10484 → address
securityStore 0xd51b3a1b → address
validateMetaTx 0x45000dc8
walletFactory 0xc5c03699 → address
whitelistStore 0x37423d5e → address

Write Contract 4 functions

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

activate 0x0f15f4c0
No parameters
batchCall 0x8c475147
address wallet
address[] to
bytes[] data
deactivate 0x51b42b00
No parameters
executeMetaTx 0x85a4b0de
address from
address to
uint256 nonce
bytes32 txAwareHash
address gasToken
uint256 gasPrice
uint256 gasLimit
bytes data
bytes signature
returns: bool

Recent Transactions

This address has 1 on-chain transactions, but only 0.8% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →