Address Contract Partially Verified
Address
0xe915058dF18e7Efe92aF5c44Df3F575FBA061B64
Balance
0 ETH
Nonce
1
Code Size
12026 bytes
Creator
0xfbbDEc9B...5980 at tx 0x5c46fc69...82c1d5
Indexed Transactions
0 (1 on-chain, 0.8% indexed)
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 →