Forkchoice Ethereum Mainnet

Address Contract Partially Verified

Address 0x75258e3C04472aA07a535006793740C9ebccBDAf
Balance 0 ETH
Nonce 1
Code Size 18750 bytes
Indexed Transactions 0 (1 on-chain, 0.6% indexed)
External Etherscan · Sourcify

Contract Bytecode

18750 bytes
0x60806040526004361061031a5760003560e01c80637d73b231116101ab578063cbd2ac68116100f7578063e2b4ce9711610095578063f36febda1161006f578063f36febda14610c97578063f40b51f814610cd0578063f41c431914610cfa578063f421764814610d245761031a565b8063e2b4ce9714610c2e578063e61c51ca14610c43578063eadd3cea14610c6d5761031a565b8063ce0b5bd5116100d1578063ce0b5bd514610bb0578063d251fefc14610bda578063da84b1ed14610c04578063de212bf314610c195761031a565b8063cbd2ac6814610ac3578063cc0e7e5614610aed578063cd7958dd14610b025761031a565b8063b221f31611610164578063be40ba791161013e578063be40ba7914610a41578063beabacc814610a56578063c4856cd914610a99578063c785141814610aae5761031a565b8063b221f316146109a3578063b242e534146109cd578063b87e21ef14610a085761031a565b80637d73b231146108a35780637d7d0046146108d45780637fd004fa146108e9578063877337b0146109645780638da5cb5b146109795780639b0dfd271461098e5761031a565b806332531c3c1161026a5780634aa46fde116102235780636137d670116101fd5780636137d670146107d4578063715018a61461084f57806374624c5514610864578063747c31d61461088e5761031a565b80634aa46fde146107805780635adc02ab146107955780635d2362a8146107bf5761031a565b806332531c3c146106285780633a43199f1461065b5780633bfec254146106875780633c672eb7146106b15780633f579f42146106db57806347b55a9d1461076b5761031a565b80631efd0299116102d7578063227149a3116102b1578063227149a3146105845780632587a6a21461059957806326d05ab2146105ae578063294f4025146105c35761031a565b80631efd0299146105305780632121dc751461054557806321ce918d1461055a5761031a565b806301ffc9a714610356578063027ef3eb1461039e5780630f3a85d8146103c5578063100f23fd146103f15780631127b57e1461041b5780631aa21fba146104a5575b6040805133815234602082015281517f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f88525874929181900390910190a1005b34801561036257600080fd5b5061038a6004803603602081101561037957600080fd5b50356001600160e01b031916610d9f565b604080519115158252519081900360200190f35b3480156103aa57600080fd5b506103b3610db9565b60408051918252519081900360200190f35b3480156103d157600080fd5b506103ef600480360360208110156103e857600080fd5b5035610dc0565b005b3480156103fd57600080fd5b506103ef6004803603602081101561041457600080fd5b5035610eb1565b34801561042757600080fd5b5061043061104c565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561046a578181015183820152602001610452565b50505050905090810190601f1680156104975780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156104b157600080fd5b506103ef600480360360408110156104c857600080fd5b6001600160a01b038235169190810190604081016020820135600160201b8111156104f257600080fd5b82018360208201111561050457600080fd5b803590602001918460208302840111600160201b8311171561052557600080fd5b50909250905061106d565b34801561053c57600080fd5b506103b36111ed565b34801561055157600080fd5b5061038a6111fe565b34801561056657600080fd5b506103ef6004803603602081101561057d57600080fd5b503561120e565b34801561059057600080fd5b5061038a61129d565b3480156105a557600080fd5b506103b36112a6565b3480156105ba57600080fd5b5061038a6112ac565b3480156105cf57600080fd5b506105d86112b5565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156106145781810151838201526020016105fc565b505050509050019250505060405180910390f35b34801561063457600080fd5b5061038a6004803603602081101561064b57600080fd5b50356001600160a01b0316611317565b6103ef6004803603604081101561067157600080fd5b506001600160a01b03813516906020013561132c565b34801561069357600080fd5b506103ef600480360360208110156106aa57600080fd5b503561155b565b3480156106bd57600080fd5b506103ef600480360360208110156106d457600080fd5b5035611646565b3480156106e757600080fd5b50610430600480360360608110156106fe57600080fd5b6001600160a01b0382351691602081013591810190606081016040820135600160201b81111561072d57600080fd5b82018360208201111561073f57600080fd5b803590602001918460018302840111600160201b8311171561076057600080fd5b5090925090506116dd565b34801561077757600080fd5b506105d8611b48565b34801561078c57600080fd5b5061038a611ba8565b3480156107a157600080fd5b506103ef600480360360208110156107b857600080fd5b5035611bb1565b3480156107cb57600080fd5b506103b3611e73565b3480156107e057600080fd5b506103ef600480360360208110156107f757600080fd5b810190602081018135600160201b81111561081157600080fd5b82018360208201111561082357600080fd5b803590602001918460208302840111600160201b8311171561084457600080fd5b509092509050611e7f565b34801561085b57600080fd5b506103ef612066565b34801561087057600080fd5b506103ef6004803603602081101561088757600080fd5b5035612159565b34801561089a57600080fd5b506103b3612242565b3480156108af57600080fd5b506108b8612248565b604080516001600160a01b039092168252519081900360200190f35b3480156108e057600080fd5b506103b3612257565b3480156108f557600080fd5b506103ef6004803603602081101561090c57600080fd5b810190602081018135600160201b81111561092657600080fd5b82018360208201111561093857600080fd5b803590602001918460208302840111600160201b8311171561095957600080fd5b509092509050612263565b34801561097057600080fd5b506103b361254c565b34801561098557600080fd5b506108b8612552565b34801561099a57600080fd5b506103b3612561565b3480156109af57600080fd5b506103ef600480360360208110156109c657600080fd5b5035612567565b3480156109d957600080fd5b506103ef600480360360408110156109f057600080fd5b506001600160a01b038135169060200135151561264a565b348015610a1457600080fd5b506103b360048036036040811015610a2b57600080fd5b506001600160a01b0381351690602001356127f9565b348015610a4d57600080fd5b5061038a612894565b348015610a6257600080fd5b506103ef60048036036060811015610a7957600080fd5b506001600160a01b038135811691602081013590911690604001356128a3565b348015610aa557600080fd5b506103b3612a44565b348015610aba57600080fd5b5061038a612a4a565b348015610acf57600080fd5b506103ef60048036036020811015610ae657600080fd5b5035612a53565b348015610af957600080fd5b506103b3612dc2565b348015610b0e57600080fd5b506103b360048036036020811015610b2557600080fd5b810190602081018135600160201b811115610b3f57600080fd5b820183602082011115610b5157600080fd5b803590602001918460208302840111600160201b83111715610b7257600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550612dc8945050505050565b348015610bbc57600080fd5b506103ef60048036036020811015610bd357600080fd5b5035612e22565b348015610be657600080fd5b506108b860048036036020811015610bfd57600080fd5b5035612fc1565b348015610c1057600080fd5b506103b3612fe8565b348015610c2557600080fd5b5061038a612fee565b348015610c3a57600080fd5b506103b3612ffc565b348015610c4f57600080fd5b506103ef60048036036020811015610c6657600080fd5b5035613002565b348015610c7957600080fd5b506103ef60048036036020811015610c9057600080fd5b5035613166565b348015610ca357600080fd5b506103b360048036036040811015610cba57600080fd5b506001600160a01b0381351690602001356131bf565b348015610cdc57600080fd5b506103ef60048036036020811015610cf357600080fd5b5035613384565b348015610d0657600080fd5b506103ef60048036036020811015610d1d57600080fd5b50356133dd565b348015610d3057600080fd5b506103ef60048036036020811015610d4757600080fd5b810190602081018135600160201b811115610d6157600080fd5b820183602082011115610d7357600080fd5b803590602001918460208302840111600160201b83111715610d9457600080fd5b509092509050613436565b6001600160e01b031981166301ffc9a760e01b145b919050565b600c545b90565b610dc9336136f5565b610e08576040805162461bcd60e51b815260206004820152601660248201526000805160206145f2833981519152604482015290519081900360640190fd5b8066038d7ea4c6800011158015610e2757506706f05b59d3b200008111155b610e625760405162461bcd60e51b815260040180806020018281038252602e815260200180614579602e913960400191505060405180910390fd5b610e73600f8263ffffffff61370916565b604080513381526020810183905281517f41ff5d5ce3b7935893a4e7269ec5caae9cca5e3bf0eb4b21d2f443489667112e929181900390910190a150565b610eba336136f5565b80610ec95750610ec93361377e565b610f17576040805162461bcd60e51b815260206004820152601a60248201527932b4ba3432b91037bbb732b91037b91031b7b73a3937b63632b960311b604482015290519081900360640190fd5b60085460ff16610f585760405162461bcd60e51b81526004018080602001828103825260298152602001806147276029913960400191505060405180910390fd5b610fbb6006805480602002602001604051908101604052809291908181526020018280548015610fb157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610f93575b5050505050612dc8565b8114610ff85760405162461bcd60e51b81526004018080602001828103825260358152602001806147c06035913960400191505060405180910390fd5b6110046006600061444a565b6008805460ff19169055604080513381526020810183905281517f7794eff834d760583543e6e510e717a5e66d2c064e225f4db448343c3e66afcf929181900390910190a150565b604051806040016040528060058152602001640322e322e360dc1b81525081565b611076336136f5565b6110b5576040805162461bcd60e51b815260206004820152601660248201526000805160206145f2833981519152604482015290519081900360640190fd5b80611107576040805162461bcd60e51b815260206004820152601f60248201527f61737365742061727261792073686f756c64206265206e6f6e2d656d70747900604482015290519081900360640190fd5b60005b8181101561116a5760006111393085858581811061112457fe5b905060200201356001600160a01b0316613812565b90506111618585858581811061114b57fe5b905060200201356001600160a01b0316836128a3565b5060010161110a565b507fd4f62f23021706247dcffea245d104ae7ddaec7f23acf3d11d7136d5de6a69ad83838360405180846001600160a01b03166001600160a01b03168152602001806020018281038252848482818152602001925060200280828437600083820152604051601f909101601f1916909201829003965090945050505050a1505050565b60006111f960156138bd565b905090565b600354600160a01b900460ff1690565b611217336136f5565b611256576040805162461bcd60e51b815260206004820152601660248201526000805160206145f2833981519152604482015290519081900360640190fd5b61126760098263ffffffff6138f216565b6040805182815290517f4b1b970c8a0fa761e7803ed70c13d7aca71904b13df60fbe03f981da1730da919181900360200190a150565b60195460ff1690565b600f5490565b60085460ff1681565b6060600780548060200260200160405190810160405280929190818152602001828054801561130d57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116112ef575b5050505050905090565b60046020526000908152604090205460ff1681565b611335336136f5565b611374576040805162461bcd60e51b815260206004820152601660248201526000805160206145f2833981519152604482015290519081900360640190fd5b61137d82613953565b6113c3576040805162461bcd60e51b8152602060048201526012602482015271746f6b656e206e6f74206c6f616461626c6560701b604482015290519081900360640190fd5b60006113cf83836131bf565b90506113e260158263ffffffff61396d16565b60006113ef601a546139da565b90506001600160a01b038416156114975761141a6001600160a01b038516828563ffffffff613a9c16565b806001600160a01b0316631b3c96b485856040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561147a57600080fd5b505af115801561148e573d6000803e3d6000fd5b50505050611511565b806001600160a01b0316631b3c96b48486866040518463ffffffff1660e01b815260040180836001600160a01b03166001600160a01b03168152602001828152602001925050506000604051808303818588803b1580156114f757600080fd5b505af115801561150b573d6000803e3d6000fd5b50505050505b604080516001600160a01b03861681526020810185905281517f5f65674bec9af81f71be68674135a0ea3f163fb91984e3893d06da9f6ea2ce8a929181900390910190a150505050565b611564336136f5565b6115a3576040805162461bcd60e51b815260206004820152601660248201526000805160206145f2833981519152604482015290519081900360640190fd5b8066038d7ea4c68000111580156115bc57506014548111155b6115f75760405162461bcd60e51b815260040180806020018281038252602d8152602001806148dd602d913960400191505060405180910390fd5b61160860158263ffffffff61370916565b604080513381526020810183905281517f0b05243483e17c3f3377aee82b7d47e5700b48288695fc08b7ecc2759afa44ef929181900390910190a150565b61164f336136f5565b61168e576040805162461bcd60e51b815260206004820152601660248201526000805160206145f2833981519152604482015290519081900360640190fd5b61169f60098263ffffffff61370916565b604080513381526020810183905281517f068f112e5ec923d412be64779fe69e0fcbb6784c6617e94cccc8fd348f2e0f21929181900390910190a150565b60606116e8336136f5565b611727576040805162461bcd60e51b815260206004820152601660248201526000805160206145f2833981519152604482015290519081900360640190fd5b6001600160a01b03851660009081526004602052604090205460ff166117585761175860098563ffffffff61396d16565b61176a856001600160a01b0316613bb4565b801561177a575061177a85613bba565b15611999576000806117c28786868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613bd492505050565b6001600160a01b038216600090815260046020526040902054919350915060ff166118085760006117f388836127f9565b905061180660098263ffffffff61396d16565b505b61185885858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506001600160a01b038b169291505063ffffffff613cde16565b604080516020808252818301909252606091602082018180388339019050509050600160f81b81601f8151811061188b57fe5b60200101906001600160f81b031916908160001a9053507ff77753fab406ecfff96d6ff2476c64a838fa9f6d37b1bf190f8546e395e3b613888888888560405180866001600160a01b03166001600160a01b03168152602001858152602001806020018060200183810383528686828181526020019250808284376000838201819052601f909101601f191690920185810384528651815286516020918201939188019250908190849084905b83811015611950578181015183820152602001611938565b50505050905090810190601f16801561197d5780820380516001836020036101000a031916815260200191505b5097505050505050505060405180910390a19250611b40915050565b60006060866001600160a01b0316868686604051808383808284376040519201945060009350909150508083038185875af1925050503d80600081146119fb576040519150601f19603f3d011682016040523d82523d6000602084013e611a00565b606091505b509150915081611a4f576040805162461bcd60e51b81526020600482015260156024820152741b1bddcb5b195d995b0818d85b1b0819985a5b1959605a1b604482015290519081900360640190fd5b7ff77753fab406ecfff96d6ff2476c64a838fa9f6d37b1bf190f8546e395e3b613878787878560405180866001600160a01b03166001600160a01b03168152602001858152602001806020018060200183810383528686828181526020019250808284376000838201819052601f909101601f191690920185810384528651815286516020918201939188019250908190849084905b83811015611afd578181015183820152602001611ae5565b50505050905090810190601f168015611b2a5780820380516001836020036101000a031916815260200191505b5097505050505050505060405180910390a19150505b949350505050565b6060600680548060200260200160405190810160405280929190818152602001828054801561130d576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116112ef575050505050905090565b600d5460ff1690565b611bba3361377e565b611bf9576040805162461bcd60e51b815260206004820152601a602482015260008051602061463a833981519152604482015290519081900360640190fd5b60085460ff16611c3a5760405162461bcd60e51b81526004018080602001828103825260298152602001806147276029913960400191505060405180910390fd5b611c9b6006805480602002602001604051908101604052809291908181526020018280548015610fb1576020028201919060005260206000209081546001600160a01b03168152600190910190602001808311610f93575050505050612dc8565b8114611cd85760405162461bcd60e51b81526004018080602001828103825260338152602001806147f56033913960400191505060405180910390fd5b60005b600654811015611dbf576004600060068381548110611cf657fe5b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff16611db75760016004600060068481548110611d3557fe5b6000918252602080832091909101546001600160a01b031683528201929092526040019020805460ff1916911515919091179055600680546005919083908110611d7b57fe5b60009182526020808320909101548354600181018555938352912090910180546001600160a01b0319166001600160a01b039092169190911790555b600101611cdb565b507fb2f6cccee7a369e23e293c25aa19bef80af11eb26deba3ea0f2a02783f752e4a33600660405180836001600160a01b03166001600160a01b03168152602001806020018281038252838181548152602001915080548015611e4b57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611e2d575b5050935050505060405180910390a1611e666006600061444a565b506008805460ff19169055565b60006111f960096138bd565b611e88336136f5565b611ec7576040805162461bcd60e51b815260206004820152601660248201526000805160206145f2833981519152604482015290519081900360640190fd5b60085460ff16158015611ee25750600854610100900460ff16155b611f1d5760405162461bcd60e51b815260040180806020018281038252602e81526020018061465a602e913960400191505060405180910390fd5b60085462010000900460ff16611f645760405162461bcd60e51b81526004018080602001828103825260228152602001806145d06022913960400191505060405180910390fd5b80611fa05760405162461bcd60e51b815260040180806020018281038252602281526020018061479e6022913960400191505060405180910390fd5b611fac60078383614468565b506008805461ff00191661010017905560408051602080840282810182019093528382527ffbc0e5ca6c7e4858daf0fdb185ef5186203e74ec9c64737e93c0aeaec596e1d1928592859261201b92859185918291850190849080828437600092019190915250612dc892505050565b60405180806020018381526020018281038252858582818152602001925060200280828437600083820152604051601f909101601f1916909201829003965090945050505050a15050565b61206f336136f5565b6120ae576040805162461bcd60e51b815260206004820152601660248201526000805160206145f2833981519152604482015290519081900360640190fd5b600354600160a01b900460ff1661210c576040805162461bcd60e51b815260206004820152601d60248201527f6f776e657273686970206973206e6f74207472616e7366657261626c65000000604482015290519081900360640190fd5b600380546001600160a01b0319169055604080516000808252602082015281517f850b3df64837d7d518b45f5aa64d104652c3b80eb5b34a8e3d9eb666cb7cdea5929181900390910190a1565b612162336136f5565b6121a1576040805162461bcd60e51b815260206004820152601660248201526000805160206145f2833981519152604482015290519081900360640190fd5b8066038d7ea4c68000111580156121c057506706f05b59d3b200008111155b6121fb5760405162461bcd60e51b815260040180806020018281038252602e815260200180614579602e913960400191505060405180910390fd5b61220c600f8263ffffffff6138f216565b6040805182815290517faf2a77cd04c3cc155588dd3bf67b310ab4fb3b1da3cf6b8d7d4d2aa1d09b794c9181900360200190a150565b601a5490565b6001546001600160a01b031690565b60006111f9600f6138bd565b61226c336136f5565b6122ab576040805162461bcd60e51b815260206004820152601660248201526000805160206145f2833981519152604482015290519081900360640190fd5b60085460ff161580156122c65750600854610100900460ff16155b6123015760405162461bcd60e51b815260040180806020018281038252602e81526020018061465a602e913960400191505060405180910390fd5b8181808060200260200160405190810160405280939291908181526020018383602002808284376000920182905250925050505b81518110156124035761235a82828151811061234d57fe5b60200260200101516136f5565b156123965760405162461bcd60e51b815260040180806020018281038252602d815260200180614771602d913960400191505060405180910390fd5b60006001600160a01b03168282815181106123ad57fe5b60200260200101516001600160a01b031614156123fb5760405162461bcd60e51b815260040180806020018281038252602c81526020018061452a602c913960400191505060405180910390fd5b600101612335565b5060085462010000900460ff1661244b5760405162461bcd60e51b81526004018080602001828103825260228152602001806145d06022913960400191505060405180910390fd5b816124875760405162461bcd60e51b81526004018080602001828103825260238152602001806145566023913960400191505060405180910390fd5b61249360068484614468565b506008805460ff1916600117905560408051602080850282810182019093528482527f9c80b3b5f68b3e017766d59e8d09b34efe6462b05c398f35cab9e271d9bc3b9c928692869261250092859185918291850190849080828437600092019190915250612dc892505050565b60405180806020018381526020018281038252858582818152602001925060200280828437600083820152604051601f909101601f1916909201829003965090945050505050a1505050565b600e5490565b6003546001600160a01b031690565b60095490565b612570336136f5565b6125af576040805162461bcd60e51b815260206004820152601660248201526000805160206145f2833981519152604482015290519081900360640190fd5b8066038d7ea4c68000111580156125c857506014548111155b6126035760405162461bcd60e51b815260040180806020018281038252602d8152602001806148dd602d913960400191505060405180910390fd5b61261460158263ffffffff6138f216565b6040805182815290517fc178d379965e5657b6fc57494e392f121a14119215dfb422aad7db4cc03f2d109181900360200190a150565b612653336136f5565b612692576040805162461bcd60e51b815260206004820152601660248201526000805160206145f2833981519152604482015290519081900360640190fd5b600354600160a01b900460ff166126f0576040805162461bcd60e51b815260206004820152601d60248201527f6f776e657273686970206973206e6f74207472616e7366657261626c65000000604482015290519081900360640190fd5b6001600160a01b0382166127355760405162461bcd60e51b81526004018080602001828103825260238152602001806148286023913960400191505060405180910390fd5b6003805460ff60a01b1916600160a01b831515021790558061278e57604080516001600160a01b038416815290517f808639ff9c8e4732d60b6c2330de498035416d229f27a77d259680895efec1229181900360200190a15b600354604080516001600160a01b039283168152918416602083015280517f850b3df64837d7d518b45f5aa64d104652c3b80eb5b34a8e3d9eb666cb7cdea59281900390910190a150600380546001600160a01b0319166001600160a01b0392909216919091179055565b60008060008061280886613e9c565b505050935093509350508015612886578161285c576040805162461bcd60e51b815260206004820152600f60248201526e0746f6b656e2072617465206973203608c1b604482015290519081900360640190fd5b61287c83612870878563ffffffff613fc716565b9063ffffffff61402716565b935050505061288e565b600093505050505b92915050565b60085462010000900460ff1681565b6128ac336136f5565b6128eb576040805162461bcd60e51b815260206004820152601660248201526000805160206145f2833981519152604482015290519081900360640190fd5b808061293e576040805162461bcd60e51b815260206004820152601d60248201527f70726f76696465642076616c75652063616e6e6f74206265207a65726f000000604482015290519081900360640190fd5b6001600160a01b038416612999576040805162461bcd60e51b815260206004820181905260248201527f5f746f20616464726573732063616e6e6f742062652073657420746f20307830604482015290519081900360640190fd5b6001600160a01b03841660009081526004602052604090205460ff166129e957816001600160a01b038416156129d6576129d384846127f9565b90505b6129e760098263ffffffff61396d16565b505b6129f4848484614091565b604080516001600160a01b0380871682528516602082015280820184905290517fd1ba4ac2e2a11b5101f6cb4d978f514a155b421e8ec396d2d9abaf0bb02917ee9181900360600190a150505050565b60185490565b60135460ff1690565b612a5c3361377e565b612a9b576040805162461bcd60e51b815260206004820152601a602482015260008051602061463a833981519152604482015290519081900360640190fd5b600854610100900460ff16612ae15760405162461bcd60e51b81526004018080602001828103825260288152602001806146126028913960400191505060405180910390fd5b612b426007805480602002602001604051908101604052809291908181526020018280548015610fb1576020028201919060005260206000209081546001600160a01b03168152600190910190602001808311610f93575050505050612dc8565b8114612b7f5760405162461bcd60e51b81526004018080602001828103825260478152602001806146e06047913960600191505060405180910390fd5b60005b600754811015612d0d576004600060078381548110612b9d57fe5b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff1615612d055760006004600060078481548110612bdd57fe5b6000918252602080832091909101546001600160a01b031683528201929092526040018120805460ff1916921515929092179091555b600554612c2790600163ffffffff6140f516565b811015612cef5760078281548110612c3b57fe5b600091825260209091200154600580546001600160a01b039092169183908110612c6157fe5b6000918252602090912001546001600160a01b03161415612ce757600580546000198101908110612c8e57fe5b600091825260209091200154600580546001600160a01b039092169183908110612cb457fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550612cef565b600101612c13565b506005805490612d039060001983016144cb565b505b600101612b82565b507fd218c430fa348f4ce67791021b6b89c0c3eacd4ead1d8f5b83c60038ec28249b33600760405180836001600160a01b03166001600160a01b03168152602001806020018281038252838181548152602001915080548015612d9957602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612d7b575b5050935050505060405180910390a1612db46007600061444a565b506008805461ff0019169055565b60125490565b60008160405160200180828051906020019060200280838360005b83811015612dfb578181015183820152602001612de3565b50505050905001915050604051602081830303815290604052805190602001209050919050565b612e2b336136f5565b80612e3a5750612e3a3361377e565b612e88576040805162461bcd60e51b815260206004820152601a60248201527932b4ba3432b91037bbb732b91037b91031b7b73a3937b63632b960311b604482015290519081900360640190fd5b600854610100900460ff16612ece5760405162461bcd60e51b81526004018080602001828103825260288152602001806146126028913960400191505060405180910390fd5b612f2f6007805480602002602001604051908101604052809291908181526020018280548015610fb1576020028201919060005260206000209081546001600160a01b03168152600190910190602001808311610f93575050505050612dc8565b8114612f6c5760405162461bcd60e51b81526004018080602001828103825260328152602001806148756032913960400191505060405180910390fd5b612f786007600061444a565b6008805461ff0019169055604080513381526020810183905281517f13c935eb475aa0f6e931fece83e2ac44569ce2d53460d29a6dedab40b965c8a3929181900390910190a150565b60058181548110612fce57fe5b6000918252602090912001546001600160a01b0316905081565b60155490565b600854610100900460ff1681565b60025490565b8080613055576040805162461bcd60e51b815260206004820152601d60248201527f70726f76696465642076616c75652063616e6e6f74206265207a65726f000000604482015290519081900360640190fd5b61305e336136f5565b8061306d575061306d3361377e565b6130bb576040805162461bcd60e51b815260206004820152601a60248201527932b4ba3432b91037bbb732b91037b91031b7b73a3937b63632b960311b604482015290519081900360640190fd5b6130cc600f8363ffffffff61396d16565b6130d4612552565b6001600160a01b03166108fc839081150290604051600060405180830381858888f1935050505015801561310c573d6000803e3d6000fd5b507f611b7c0d84fda988026215bef9b3e4d81cbceced7e679be6d5e044b588467c0e33613137612552565b604080516001600160a01b03938416815291909216602082015280820185905290519081900360600190a15050565b61316f3361377e565b6131ae576040805162461bcd60e51b815260206004820152601a602482015260008051602061463a833981519152604482015290519081900360640190fd5b61169f60098263ffffffff61415216565b60006131c96141a6565b6001600160a01b0316836001600160a01b031614156131e957508061288e565b816001600160a01b038416156132ba57600080600061320787613e9c565b505050935093509350508061325c576040805162461bcd60e51b8152602060048201526016602482015275746f6b656e206973206e6f7420617661696c61626c6560501b604482015290519081900360640190fd5b816132a0576040805162461bcd60e51b815260206004820152600f60248201526e0746f6b656e2072617465206973203608c1b604482015290519081900360640190fd5b6132b483612870888563ffffffff613fc716565b93505050505b60008060006132c761421c565b505050935093509350508061331c576040805162461bcd60e51b8152602060048201526016602482015275746f6b656e206973206e6f7420617661696c61626c6560501b604482015290519081900360640190fd5b81613365576040805162461bcd60e51b81526020600482015260146024820152730737461626c65636f696e207261746520697320360641b604482015290519081900360640190fd5b61337982612870868663ffffffff613fc716565b979650505050505050565b61338d3361377e565b6133cc576040805162461bcd60e51b815260206004820152601a602482015260008051602061463a833981519152604482015290519081900360640190fd5b61160860158263ffffffff61415216565b6133e63361377e565b613425576040805162461bcd60e51b815260206004820152601a602482015260008051602061463a833981519152604482015290519081900360640190fd5b610e73600f8263ffffffff61415216565b61343f336136f5565b61347e576040805162461bcd60e51b815260206004820152601660248201526000805160206145f2833981519152604482015290519081900360640190fd5b8181808060200260200160405190810160405280939291908181526020018383602002808284376000920182905250925050505b8151811015613573576134ca82828151811061234d57fe5b156135065760405162461bcd60e51b815260040180806020018281038252602d815260200180614771602d913960400191505060405180910390fd5b60006001600160a01b031682828151811061351d57fe5b60200260200101516001600160a01b0316141561356b5760405162461bcd60e51b815260040180806020018281038252602c81526020018061452a602c913960400191505060405180910390fd5b6001016134b2565b5060085462010000900460ff16156135bc5760405162461bcd60e51b81526004018080602001828103825260268152602001806146ba6026913960400191505060405180910390fd5b60005b82811015613671576001600460008686858181106135d957fe5b905060200201356001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff021916908315150217905550600584848381811061362e57fe5b835460018181018655600095865260209586902090910180546001600160a01b0319166001600160a01b03969093029490940135949094161790915550016135bf565b506008805462ff0000191662010000179055604080513380825260208083018481529383018690527fb2f6cccee7a369e23e293c25aa19bef80af11eb26deba3ea0f2a02783f752e4a9391928792879260608301908590850280828437600083820152604051601f909101601f1916909201829003965090945050505050a1505050565b6003546001600160a01b0390811691161490565b600482015460ff1615613763576040805162461bcd60e51b815260206004820152601a60248201527f6461696c79206c696d6974206e6f742075706461746561626c65000000000000604482015290519081900360640190fd5b61376d8282614322565b50600401805460ff19166001179055565b600061378b6002546139da565b6001600160a01b031663b429afeb836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156137e057600080fd5b505afa1580156137f4573d6000803e3d6000fd5b505050506040513d602081101561380a57600080fd5b505192915050565b60006001600160a01b038216156138ac57816001600160a01b03166370a08231846040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561387957600080fd5b505afa15801561388d573d6000803e3d6000fd5b505050506040513d60208110156138a357600080fd5b5051905061288e565b506001600160a01b0382163161288e565b60028101546000906138d8906201518063ffffffff61434516565b4211156138e757508054610db4565b506001810154610db4565b600482015460ff1661394b576040805162461bcd60e51b815260206004820152601f60248201527f6461696c79206c696d6974206973207374696c6c2075706461746561626c6500604482015290519081900360640190fd5b600390910155565b60008061395f83613e9c565b509098975050505050505050565b6139768261439f565b80826001015410156139b95760405162461bcd60e51b81526004018080602001828103825260328152602001806146886032913960400191505060405180910390fd5b60018201546139ce908263ffffffff6140f516565b82600101819055505050565b6000805460408051630178b8bf60e01b81526004810185905290516001600160a01b0390921691630178b8bf91602480820192602092909190829003018186803b158015613a2757600080fd5b505afa158015613a3b573d6000803e3d6000fd5b505050506040513d6020811015613a5157600080fd5b505160408051631d9dabef60e11b81526004810185905290516001600160a01b0390921691633b3b57de91602480820192602092909190829003018186803b1580156137e057600080fd5b801580613b22575060408051636eb1769f60e11b81523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b158015613af457600080fd5b505afa158015613b08573d6000803e3d6000fd5b505050506040513d6020811015613b1e57600080fd5b5051155b613b5d5760405162461bcd60e51b81526004018080602001828103825260368152602001806148a76036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052613baf908490613cde565b505050565b3b151590565b600080613bc683613e9c565b509198975050505050505050565b600080613be2600e546139da565b6001600160a01b031663afc72e9385856040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b83811015613c56578181015183820152602001613c3e565b50505050905090810190601f168015613c835780820380516001836020036101000a031916815260200191505b509350505050604080518083038186803b158015613ca057600080fd5b505afa158015613cb4573d6000803e3d6000fd5b505050506040513d6040811015613cca57600080fd5b508051602090910151909590945092505050565b613cf0826001600160a01b0316613bb4565b613d41576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b60208310613d7f5780518252601f199092019160209182019101613d60565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613de1576040519150601f19603f3d011682016040523d82523d6000602084013e613de6565b606091505b509150915081613e3d576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b805115613e9657808060200190516020811015613e5957600080fd5b5051613e965760405162461bcd60e51b815260040180806020018281038252602a81526020018061484b602a913960400191505060405180910390fd5b50505050565b6060600080600080600080613eb2600e546139da565b6001600160a01b0316631f69565f896040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060006040518083038186803b158015613f0757600080fd5b505afa158015613f1b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260e0811015613f4457600080fd5b810190808051600160201b811115613f5b57600080fd5b82016020810184811115613f6e57600080fd5b8151600160201b811182820187101715613f8757600080fd5b5050602082015160408301516060840151608085015160a086015160c090960151949e50929c50909a509850965090945092505050919395979092949650565b600082613fd65750600061288e565b82820282848281613fe357fe5b04146140205760405162461bcd60e51b81526004018080602001828103825260218152602001806147506021913960400191505060405180910390fd5b9392505050565b600080821161407d576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b600082848161408857fe5b04949350505050565b6001600160a01b0382166140db576040516001600160a01b0384169082156108fc029083906000818181858888f193505050501580156140d5573d6000803e3d6000fd5b50613baf565b613baf6001600160a01b038316848363ffffffff6143f816565b60008282111561414c576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b808260030154146141945760405162461bcd60e51b81526004018080602001828103825260298152602001806145a76029913960400191505060405180910390fd5b6141a2828360030154614322565b5050565b60006141b3600e546139da565b6001600160a01b031663e9cbd8226040518163ffffffff1660e01b815260040160206040518083038186803b1580156141eb57600080fd5b505afa1580156141ff573d6000803e3d6000fd5b505050506040513d602081101561421557600080fd5b5051905090565b6060600080600080600080614232600e546139da565b6001600160a01b0316633efec5e96040518163ffffffff1660e01b815260040160006040518083038186803b15801561426a57600080fd5b505afa15801561427e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260e08110156142a757600080fd5b810190808051600160201b8111156142be57600080fd5b820160208101848111156142d157600080fd5b8151600160201b8111828201871017156142ea57600080fd5b5050602082015160408301516060840151608085015160a086015160c090960151949f939e50919c509a509850919650945092505050565b61432b8261439f565b80825560018201548110156141a257815460018301555050565b600082820183811015614020576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60028101546143b7906201518063ffffffff61434516565b4211156143f557426002820155805460018201556040517fe93bc25276d408d390778e7a8b926f2f67209c43ed540081b951fe128f0d3cd290600090a15b50565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052613baf908490613cde565b50805460008255906000526020600020908101906143f591906144eb565b8280548282559060005260206000209081019282156144bb579160200282015b828111156144bb5781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190614488565b506144c7929150614505565b5090565b815481835581811115613baf57600083815260209020613baf9181019083015b610dbd91905b808211156144c757600081556001016144f1565b610dbd91905b808211156144c75780546001600160a01b031916815560010161450b56fe70726f76696465642077686974656c69737420636f6e7461696e7320746865207a65726f206164647265737370656e64696e672077686974656c697374206164646974696f6e20697320656d70747967617320746f7020757020616d6f756e74206973206f75747369646520746865206d696e2f6d61782072616e6765636f6e6669726d656420616e64207375626d6974746564206c696d69747320646f6e74206d6174636877686974656c69737420686173206e6f74206265656e20696e697469616c697a656473656e646572206973206e6f7420616e206f776e65720000000000000000000077686974656c6973742072656d6f76616c20686173206e6f74206265656e207375626d697474656473656e646572206973206e6f74206120636f6e74726f6c6c657200000000000077686974656c697374206f7065726174696f6e2068617320616c7265616479206265656e207375626d6974746564617661696c61626c652068617320746f2062652067726561746572206f7220657175616c20746f2075736520616d6f756e7477686974656c6973742068617320616c7265616479206265656e20696e697469616c697a656468617368206f66207468652070656e64696e672077686974656c6973742072656d6f76616c20646f6573206e6f74206d617463682074686520636f6e6669726d6564206861736877686974656c697374206164646974696f6e20686173206e6f74206265656e207375626d6974746564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7770726f76696465642077686974656c69737420636f6e7461696e7320746865206f776e6572206164647265737370656e64696e672077686974656c6973742072656d6f76616c20697320656d70747968617368206f66207468652070656e64696e672077686974656c697374206164646974696f6e20646f6573206e6f74206d6174636868617368206f66207468652070656e64696e672077686974656c697374206164646974696f6e20646f206e6f74206d617463686f776e65722063616e6e6f742062652073657420746f207a65726f20616464726573735361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656468617368206f66207468652070656e64696e672077686974656c6973742072656d6f76616c20646f206e6f74206d617463685361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e636563617264206c6f616420616d6f756e74206973206f75747369646520746865206d696e2f6d61782072616e6765a265627a7a7230582039d1a7c207df4e9874dc1b1a8be5453ec2db2d73fab93e6dc8a826b323ac459264736f6c634300050a0032

Verified Source Code Partial Match

Compiler: v0.5.10+commit.5a6ea5b1 EVM: petersburg Optimization: Yes (200 runs)
Wallet.sol 2954 lines
/**
 *  The Consumer Contract Wallet
 *  Copyright (C) 2019 The Contract Wallet Company Limited
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.

 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.

 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

pragma solidity ^0.5.10;

contract Ownable {
    event TransferredOwnership(address _from, address _to);
    event LockedOwnership(address _locked);

    address payable private _owner;
    bool private _isTransferable;

    /// @notice Constructor sets the original owner of the contract and whether or not it is one time transferable.
    constructor(address payable _account_, bool _transferable_) internal {
        _owner = _account_;
        _isTransferable = _transferable_;
        // Emit the LockedOwnership event if no longer transferable.
        if (!_isTransferable) {
            emit LockedOwnership(_account_);
        }
        emit TransferredOwnership(address(0), _account_);
    }

    /// @notice Reverts if called by any account other than the owner.
    modifier onlyOwner() {
        require(_isOwner(msg.sender), "sender is not an owner");
        _;
    }

    /// @notice Allows the current owner to transfer control of the contract to a new address.
    /// @param _account address to transfer ownership to.
    /// @param _transferable indicates whether to keep the ownership transferable.
    function transferOwnership(address payable _account, bool _transferable) external onlyOwner {
        // Require that the ownership is transferable.
        require(_isTransferable, "ownership is not transferable");
        // Require that the new owner is not the zero address.
        require(_account != address(0), "owner cannot be set to zero address");
        // Set the transferable flag to the value _transferable passed in.
        _isTransferable = _transferable;
        // Emit the LockedOwnership event if no longer transferable.
        if (!_transferable) {
            emit LockedOwnership(_account);
        }
        // Emit the ownership transfer event.
        emit TransferredOwnership(_owner, _account);
        // Set the owner to the provided address.
        _owner = _account;
    }

    /// @notice check if the ownership is transferable.
    /// @return true if the ownership is transferable.
    function isTransferable() external view returns (bool) {
        return _isTransferable;
    }

    /// @notice Allows the current owner to relinquish control of the contract.
    /// @dev Renouncing to ownership will leave the contract without an owner and unusable.
    /// @dev It will not be possible to call the functions with the `onlyOwner` modifier anymore.
    function renounceOwnership() external onlyOwner {
        // Require that the ownership is transferable.
        require(_isTransferable, "ownership is not transferable");
        // note that this could be terminal
        _owner = address(0);

        emit TransferredOwnership(_owner, address(0));
    }

    /// @notice Find out owner address
    /// @return address of the owner.
    function owner() public view returns (address payable) {
        return _owner;
    }

    /// @notice Check if owner address
    /// @return true if sender is the owner of the contract.
    function _isOwner(address _address) internal view returns (bool) {
        return _address == _owner;
    }
}

library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

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

        return c;
    }

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

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

        return c;
    }

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

        return c;
    }

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

contract ResolverBase {
    bytes4 private constant INTERFACE_META_ID = 0x01ffc9a7;

    function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
        return interfaceID == INTERFACE_META_ID;
    }

    function isAuthorised(bytes32 node) internal view returns(bool);

    modifier authorised(bytes32 node) {
        require(isAuthorised(node));
        _;
    }
}

library strings {
    struct slice {
        uint _len;
        uint _ptr;
    }

    function memcpy(uint dest, uint src, uint len) private pure {
        // Copy word-length chunks while possible
        for(; len >= 32; len -= 32) {
            assembly {
                mstore(dest, mload(src))
            }
            dest += 32;
            src += 32;
        }

        // Copy remaining bytes
        uint mask = 256 ** (32 - len) - 1;
        assembly {
            let srcpart := and(mload(src), not(mask))
            let destpart := and(mload(dest), mask)
            mstore(dest, or(destpart, srcpart))
        }
    }

    /*
     * @dev Returns a slice containing the entire string.
     * @param self The string to make a slice from.
     * @return A newly allocated slice containing the entire string.
     */
    function toSlice(string memory self) internal pure returns (slice memory) {
        uint ptr;
        assembly {
            ptr := add(self, 0x20)
        }
        return slice(bytes(self).length, ptr);
    }

    /*
     * @dev Returns the length of a null-terminated bytes32 string.
     * @param self The value to find the length of.
     * @return The length of the string, from 0 to 32.
     */
    function len(bytes32 self) internal pure returns (uint) {
        uint ret;
        if (self == 0)
            return 0;
        if (uint(self) & 0xffffffffffffffffffffffffffffffff == 0) {
            ret += 16;
            self = bytes32(uint(self) / 0x100000000000000000000000000000000);
        }
        if (uint(self) & 0xffffffffffffffff == 0) {
            ret += 8;
            self = bytes32(uint(self) / 0x10000000000000000);
        }
        if (uint(self) & 0xffffffff == 0) {
            ret += 4;
            self = bytes32(uint(self) / 0x100000000);
        }
        if (uint(self) & 0xffff == 0) {
            ret += 2;
            self = bytes32(uint(self) / 0x10000);
        }
        if (uint(self) & 0xff == 0) {
            ret += 1;
        }
        return 32 - ret;
    }

    /*
     * @dev Returns a slice containing the entire bytes32, interpreted as a
     *      null-terminated utf-8 string.
     * @param self The bytes32 value to convert to a slice.
     * @return A new slice containing the value of the input argument up to the
     *         first null.
     */
    function toSliceB32(bytes32 self) internal pure returns (slice memory ret) {
        // Allocate space for `self` in memory, copy it there, and point ret at it
        assembly {
            let ptr := mload(0x40)
            mstore(0x40, add(ptr, 0x20))
            mstore(ptr, self)
            mstore(add(ret, 0x20), ptr)
        }
        ret._len = len(self);
    }

    /*
     * @dev Returns a new slice containing the same data as the current slice.
     * @param self The slice to copy.
     * @return A new slice containing the same data as `self`.
     */
    function copy(slice memory self) internal pure returns (slice memory) {
        return slice(self._len, self._ptr);
    }

    /*
     * @dev Copies a slice to a new string.
     * @param self The slice to copy.
     * @return A newly allocated string containing the slice's text.
     */
    function toString(slice memory self) internal pure returns (string memory) {
        string memory ret = new string(self._len);
        uint retptr;
        assembly { retptr := add(ret, 32) }

        memcpy(retptr, self._ptr, self._len);
        return ret;
    }

    /*
     * @dev Returns the length in runes of the slice. Note that this operation
     *      takes time proportional to the length of the slice; avoid using it
     *      in loops, and call `slice.empty()` if you only need to know whether
     *      the slice is empty or not.
     * @param self The slice to operate on.
     * @return The length of the slice in runes.
     */
    function len(slice memory self) internal pure returns (uint l) {
        // Starting at ptr-31 means the LSB will be the byte we care about
        uint ptr = self._ptr - 31;
        uint end = ptr + self._len;
        for (l = 0; ptr < end; l++) {
            uint8 b;
            assembly { b := and(mload(ptr), 0xFF) }
            if (b < 0x80) {
                ptr += 1;
            } else if (b < 0xE0) {
                ptr += 2;
            } else if (b < 0xF0) {
                ptr += 3;
            } else if (b < 0xF8) {
                ptr += 4;
            } else if (b < 0xFC) {
                ptr += 5;
            } else {
                ptr += 6;
            }
        }
    }

    /*
     * @dev Returns true if the slice is empty (has a length of 0).
     * @param self The slice to operate on.
     * @return True if the slice is empty, False otherwise.
     */
    function empty(slice memory self) internal pure returns (bool) {
        return self._len == 0;
    }

    /*
     * @dev Returns a positive number if `other` comes lexicographically after
     *      `self`, a negative number if it comes before, or zero if the
     *      contents of the two slices are equal. Comparison is done per-rune,
     *      on unicode codepoints.
     * @param self The first slice to compare.
     * @param other The second slice to compare.
     * @return The result of the comparison.
     */
    function compare(slice memory self, slice memory other) internal pure returns (int) {
        uint shortest = self._len;
        if (other._len < self._len)
            shortest = other._len;

        uint selfptr = self._ptr;
        uint otherptr = other._ptr;
        for (uint idx = 0; idx < shortest; idx += 32) {
            uint a;
            uint b;
            assembly {
                a := mload(selfptr)
                b := mload(otherptr)
            }
            if (a != b) {
                // Mask out irrelevant bytes and check again
                uint256 mask = uint256(-1); // 0xffff...
                if (shortest < 32) {
                    mask = ~(2 ** (8 * (32 - shortest + idx)) - 1);
                }
                uint256 diff = (a & mask) - (b & mask);
                if (diff != 0)
                    return int(diff);
            }
            selfptr += 32;
            otherptr += 32;
        }
        return int(self._len) - int(other._len);
    }

    /*
     * @dev Returns true if the two slices contain the same text.
     * @param self The first slice to compare.
     * @param self The second slice to compare.
     * @return True if the slices are equal, false otherwise.
     */
    function equals(slice memory self, slice memory other) internal pure returns (bool) {
        return compare(self, other) == 0;
    }

    /*
     * @dev Extracts the first rune in the slice into `rune`, advancing the
     *      slice to point to the next rune and returning `self`.
     * @param self The slice to operate on.
     * @param rune The slice that will contain the first rune.
     * @return `rune`.
     */
    function nextRune(slice memory self, slice memory rune) internal pure returns (slice memory) {
        rune._ptr = self._ptr;

        if (self._len == 0) {
            rune._len = 0;
            return rune;
        }

        uint l;
        uint b;
        // Load the first byte of the rune into the LSBs of b
        assembly { b := and(mload(sub(mload(add(self, 32)), 31)), 0xFF) }
        if (b < 0x80) {
            l = 1;
        } else if (b < 0xE0) {
            l = 2;
        } else if (b < 0xF0) {
            l = 3;
        } else {
            l = 4;
        }

        // Check for truncated codepoints
        if (l > self._len) {
            rune._len = self._len;
            self._ptr += self._len;
            self._len = 0;
            return rune;
        }

        self._ptr += l;
        self._len -= l;
        rune._len = l;
        return rune;
    }

    /*
     * @dev Returns the first rune in the slice, advancing the slice to point
     *      to the next rune.
     * @param self The slice to operate on.
     * @return A slice containing only the first rune from `self`.
     */
    function nextRune(slice memory self) internal pure returns (slice memory ret) {
        nextRune(self, ret);
    }

    /*
     * @dev Returns the number of the first codepoint in the slice.
     * @param self The slice to operate on.
     * @return The number of the first codepoint in the slice.
     */
    function ord(slice memory self) internal pure returns (uint ret) {
        if (self._len == 0) {
            return 0;
        }

        uint word;
        uint length;
        uint divisor = 2 ** 248;

        // Load the rune into the MSBs of b
        assembly { word:= mload(mload(add(self, 32))) }
        uint b = word / divisor;
        if (b < 0x80) {
            ret = b;
            length = 1;
        } else if (b < 0xE0) {
            ret = b & 0x1F;
            length = 2;
        } else if (b < 0xF0) {
            ret = b & 0x0F;
            length = 3;
        } else {
            ret = b & 0x07;
            length = 4;
        }

        // Check for truncated codepoints
        if (length > self._len) {
            return 0;
        }

        for (uint i = 1; i < length; i++) {
            divisor = divisor / 256;
            b = (word / divisor) & 0xFF;
            if (b & 0xC0 != 0x80) {
                // Invalid UTF-8 sequence
                return 0;
            }
            ret = (ret * 64) | (b & 0x3F);
        }

        return ret;
    }

    /*
     * @dev Returns the keccak-256 hash of the slice.
     * @param self The slice to hash.
     * @return The hash of the slice.
     */
    function keccak(slice memory self) internal pure returns (bytes32 ret) {
        assembly {
            ret := keccak256(mload(add(self, 32)), mload(self))
        }
    }

    /*
     * @dev Returns true if `self` starts with `needle`.
     * @param self The slice to operate on.
     * @param needle The slice to search for.
     * @return True if the slice starts with the provided text, false otherwise.
     */
    function startsWith(slice memory self, slice memory needle) internal pure returns (bool) {
        if (self._len < needle._len) {
            return false;
        }

        if (self._ptr == needle._ptr) {
            return true;
        }

        bool equal;
        assembly {
            let length := mload(needle)
            let selfptr := mload(add(self, 0x20))
            let needleptr := mload(add(needle, 0x20))
            equal := eq(keccak256(selfptr, length), keccak256(needleptr, length))
        }
        return equal;
    }

    /*
     * @dev If `self` starts with `needle`, `needle` is removed from the
     *      beginning of `self`. Otherwise, `self` is unmodified.
     * @param self The slice to operate on.
     * @param needle The slice to search for.
     * @return `self`
     */
    function beyond(slice memory self, slice memory needle) internal pure returns (slice memory) {
        if (self._len < needle._len) {
            return self;
        }

        bool equal = true;
        if (self._ptr != needle._ptr) {
            assembly {
                let length := mload(needle)
                let selfptr := mload(add(self, 0x20))
                let needleptr := mload(add(needle, 0x20))
                equal := eq(keccak256(selfptr, length), keccak256(needleptr, length))
            }
        }

        if (equal) {
            self._len -= needle._len;
            self._ptr += needle._len;
        }

        return self;
    }

    /*
     * @dev Returns true if the slice ends with `needle`.
     * @param self The slice to operate on.
     * @param needle The slice to search for.
     * @return True if the slice starts with the provided text, false otherwise.
     */
    function endsWith(slice memory self, slice memory needle) internal pure returns (bool) {
        if (self._len < needle._len) {
            return false;
        }

        uint selfptr = self._ptr + self._len - needle._len;

        if (selfptr == needle._ptr) {
            return true;
        }

        bool equal;
        assembly {
            let length := mload(needle)
            let needleptr := mload(add(needle, 0x20))
            equal := eq(keccak256(selfptr, length), keccak256(needleptr, length))
        }

        return equal;
    }

    /*
     * @dev If `self` ends with `needle`, `needle` is removed from the
     *      end of `self`. Otherwise, `self` is unmodified.
     * @param self The slice to operate on.
     * @param needle The slice to search for.
     * @return `self`
     */
    function until(slice memory self, slice memory needle) internal pure returns (slice memory) {
        if (self._len < needle._len) {
            return self;
        }

        uint selfptr = self._ptr + self._len - needle._len;
        bool equal = true;
        if (selfptr != needle._ptr) {
            assembly {
                let length := mload(needle)
                let needleptr := mload(add(needle, 0x20))
                equal := eq(keccak256(selfptr, length), keccak256(needleptr, length))
            }
        }

        if (equal) {
            self._len -= needle._len;
        }

        return self;
    }

    // Returns the memory address of the first byte of the first occurrence of
    // `needle` in `self`, or the first byte after `self` if not found.
    function findPtr(uint selflen, uint selfptr, uint needlelen, uint needleptr) private pure returns (uint) {
        uint ptr = selfptr;
        uint idx;

        if (needlelen <= selflen) {
            if (needlelen <= 32) {
                bytes32 mask = bytes32(~(2 ** (8 * (32 - needlelen)) - 1));

                bytes32 needledata;
                assembly { needledata := and(mload(needleptr), mask) }

                uint end = selfptr + selflen - needlelen;
                bytes32 ptrdata;
                assembly { ptrdata := and(mload(ptr), mask) }

                while (ptrdata != needledata) {
                    if (ptr >= end)
                        return selfptr + selflen;
                    ptr++;
                    assembly { ptrdata := and(mload(ptr), mask) }
                }
                return ptr;
            } else {
                // For long needles, use hashing
                bytes32 hash;
                assembly { hash := keccak256(needleptr, needlelen) }

                for (idx = 0; idx <= selflen - needlelen; idx++) {
                    bytes32 testHash;
                    assembly { testHash := keccak256(ptr, needlelen) }
                    if (hash == testHash)
                        return ptr;
                    ptr += 1;
                }
            }
        }
        return selfptr + selflen;
    }

    // Returns the memory address of the first byte after the last occurrence of
    // `needle` in `self`, or the address of `self` if not found.
    function rfindPtr(uint selflen, uint selfptr, uint needlelen, uint needleptr) private pure returns (uint) {
        uint ptr;

        if (needlelen <= selflen) {
            if (needlelen <= 32) {
                bytes32 mask = bytes32(~(2 ** (8 * (32 - needlelen)) - 1));

                bytes32 needledata;
                assembly { needledata := and(mload(needleptr), mask) }

                ptr = selfptr + selflen - needlelen;
                bytes32 ptrdata;
                assembly { ptrdata := and(mload(ptr), mask) }

                while (ptrdata != needledata) {
                    if (ptr <= selfptr)
                        return selfptr;
                    ptr--;
                    assembly { ptrdata := and(mload(ptr), mask) }
                }
                return ptr + needlelen;
            } else {
                // For long needles, use hashing
                bytes32 hash;
                assembly { hash := keccak256(needleptr, needlelen) }
                ptr = selfptr + (selflen - needlelen);
                while (ptr >= selfptr) {
                    bytes32 testHash;
                    assembly { testHash := keccak256(ptr, needlelen) }
                    if (hash == testHash)
                        return ptr + needlelen;
                    ptr -= 1;
                }
            }
        }
        return selfptr;
    }

    /*
     * @dev Modifies `self` to contain everything from the first occurrence of
     *      `needle` to the end of the slice. `self` is set to the empty slice
     *      if `needle` is not found.
     * @param self The slice to search and modify.
     * @param needle The text to search for.
     * @return `self`.
     */
    function find(slice memory self, slice memory needle) internal pure returns (slice memory) {
        uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr);
        self._len -= ptr - self._ptr;
        self._ptr = ptr;
        return self;
    }

    /*
     * @dev Modifies `self` to contain the part of the string from the start of
     *      `self` to the end of the first occurrence of `needle`. If `needle`
     *      is not found, `self` is set to the empty slice.
     * @param self The slice to search and modify.
     * @param needle The text to search for.
     * @return `self`.
     */
    function rfind(slice memory self, slice memory needle) internal pure returns (slice memory) {
        uint ptr = rfindPtr(self._len, self._ptr, needle._len, needle._ptr);
        self._len = ptr - self._ptr;
        return self;
    }

    /*
     * @dev Splits the slice, setting `self` to everything after the first
     *      occurrence of `needle`, and `token` to everything before it. If
     *      `needle` does not occur in `self`, `self` is set to the empty slice,
     *      and `token` is set to the entirety of `self`.
     * @param self The slice to split.
     * @param needle The text to search for in `self`.
     * @param token An output parameter to which the first token is written.
     * @return `token`.
     */
    function split(slice memory self, slice memory needle, slice memory token) internal pure returns (slice memory) {
        uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr);
        token._ptr = self._ptr;
        token._len = ptr - self._ptr;
        if (ptr == self._ptr + self._len) {
            // Not found
            self._len = 0;
        } else {
            self._len -= token._len + needle._len;
            self._ptr = ptr + needle._len;
        }
        return token;
    }

    /*
     * @dev Splits the slice, setting `self` to everything after the first
     *      occurrence of `needle`, and returning everything before it. If
     *      `needle` does not occur in `self`, `self` is set to the empty slice,
     *      and the entirety of `self` is returned.
     * @param self The slice to split.
     * @param needle The text to search for in `self`.
     * @return The part of `self` up to the first occurrence of `delim`.
     */
    function split(slice memory self, slice memory needle) internal pure returns (slice memory token) {
        split(self, needle, token);
    }

    /*
     * @dev Splits the slice, setting `self` to everything before the last
     *      occurrence of `needle`, and `token` to everything after it. If
     *      `needle` does not occur in `self`, `self` is set to the empty slice,
     *      and `token` is set to the entirety of `self`.
     * @param self The slice to split.
     * @param needle The text to search for in `self`.
     * @param token An output parameter to which the first token is written.
     * @return `token`.
     */
    function rsplit(slice memory self, slice memory needle, slice memory token) internal pure returns (slice memory) {
        uint ptr = rfindPtr(self._len, self._ptr, needle._len, needle._ptr);
        token._ptr = ptr;
        token._len = self._len - (ptr - self._ptr);
        if (ptr == self._ptr) {
            // Not found
            self._len = 0;
        } else {
            self._len -= token._len + needle._len;
        }
        return token;
    }

    /*
     * @dev Splits the slice, setting `self` to everything before the last
     *      occurrence of `needle`, and returning everything after it. If
     *      `needle` does not occur in `self`, `self` is set to the empty slice,
     *      and the entirety of `self` is returned.
     * @param self The slice to split.
     * @param needle The text to search for in `self`.
     * @return The part of `self` after the last occurrence of `delim`.
     */
    function rsplit(slice memory self, slice memory needle) internal pure returns (slice memory token) {
        rsplit(self, needle, token);
    }

    /*
     * @dev Counts the number of nonoverlapping occurrences of `needle` in `self`.
     * @param self The slice to search.
     * @param needle The text to search for in `self`.
     * @return The number of occurrences of `needle` found in `self`.
     */
    function count(slice memory self, slice memory needle) internal pure returns (uint cnt) {
        uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr) + needle._len;
        while (ptr <= self._ptr + self._len) {
            cnt++;
            ptr = findPtr(self._len - (ptr - self._ptr), ptr, needle._len, needle._ptr) + needle._len;
        }
    }

    /*
     * @dev Returns True if `self` contains `needle`.
     * @param self The slice to search.
     * @param needle The text to search for in `self`.
     * @return True if `needle` is found in `self`, false otherwise.
     */
    function contains(slice memory self, slice memory needle) internal pure returns (bool) {
        return rfindPtr(self._len, self._ptr, needle._len, needle._ptr) != self._ptr;
    }

    /*
     * @dev Returns a newly allocated string containing the concatenation of
     *      `self` and `other`.
     * @param self The first slice to concatenate.
     * @param other The second slice to concatenate.
     * @return The concatenation of the two strings.
     */
    function concat(slice memory self, slice memory other) internal pure returns (string memory) {
        string memory ret = new string(self._len + other._len);
        uint retptr;
        assembly { retptr := add(ret, 32) }
        memcpy(retptr, self._ptr, self._len);
        memcpy(retptr + self._len, other._ptr, other._len);
        return ret;
    }

    /*
     * @dev Joins an array of slices, using `self` as a delimiter, returning a
     *      newly allocated string.
     * @param self The delimiter to use.
     * @param parts A list of slices to join.
     * @return A newly allocated string containing all the slices in `parts`,
     *         joined with `self`.
     */
    function join(slice memory self, slice[] memory parts) internal pure returns (string memory) {
        if (parts.length == 0)
            return "";

        uint length = self._len * (parts.length - 1);
        for (uint i = 0; i < parts.length; i++) {
            length += parts[i]._len;
        }

        string memory ret = new string(length);
        uint retptr;
        assembly { retptr := add(ret, 32) }

        for (uint i = 0; i < parts.length; i++) {
            memcpy(retptr, parts[i]._ptr, parts[i]._len);
            retptr += parts[i]._len;
            if (i < parts.length - 1) {
                memcpy(retptr, self._ptr, self._len);
                retptr += self._len;
            }
        }

        return ret;
    }
}

interface ERC165 {
    function supportsInterface(bytes4) external view returns (bool);
}

interface ENS {

    // Logged when the owner of a node assigns a new owner to a subnode.
    event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);

    // Logged when the owner of a node transfers ownership to a new account.
    event Transfer(bytes32 indexed node, address owner);

    // Logged when the resolver for a node changes.
    event NewResolver(bytes32 indexed node, address resolver);

    // Logged when the TTL of a node changes
    event NewTTL(bytes32 indexed node, uint64 ttl);


    function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external;
    function setResolver(bytes32 node, address resolver) external;
    function setOwner(bytes32 node, address owner) external;
    function setTTL(bytes32 node, uint64 ttl) external;
    function owner(bytes32 node) external view returns (address);
    function resolver(bytes32 node) external view returns (address);
    function ttl(bytes32 node) external view returns (uint64);

}

library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * This test is non-exhaustive, and there may be false-negatives: during the
     * execution of a contract's constructor, its address will be reported as
     * not containing a contract.
     *
     * > It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies in extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }
}

interface ERC20 {
    function allowance(address _owner, address _spender) external view returns (uint256);
    function approve(address _spender, uint256 _value) external returns (bool);
    function balanceOf(address _who) external view returns (uint256);
    function totalSupply() external view returns (uint256);
    function transfer(address _to, uint256 _value) external returns (bool);
    function transferFrom(address _from, address _to, uint256 _value) external returns (bool);
}

contract AddrResolver is ResolverBase {
    bytes4 constant private ADDR_INTERFACE_ID = 0x3b3b57de;

    event AddrChanged(bytes32 indexed node, address a);

    mapping(bytes32=>address) addresses;

    /**
     * Sets the address associated with an ENS node.
     * May only be called by the owner of that node in the ENS registry.
     * @param node The node to update.
     * @param addr The address to set.
     */
    function setAddr(bytes32 node, address addr) external authorised(node) {
        addresses[node] = addr;
        emit AddrChanged(node, addr);
    }

    /**
     * Returns the address associated with an ENS node.
     * @param node The ENS node to query.
     * @return The associated address.
     */
    function addr(bytes32 node) public view returns (address) {
        return addresses[node];
    }

    function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
        return interfaceID == ADDR_INTERFACE_ID || super.supportsInterface(interfaceID);
    }
}

contract ContentHashResolver is ResolverBase {
    bytes4 constant private CONTENT_HASH_INTERFACE_ID = 0xbc1c58d1;

    event ContenthashChanged(bytes32 indexed node, bytes hash);

    mapping(bytes32=>bytes) hashes;

    /**
     * Sets the contenthash associated with an ENS node.
     * May only be called by the owner of that node in the ENS registry.
     * @param node The node to update.
     * @param hash The contenthash to set
     */
    function setContenthash(bytes32 node, bytes calldata hash) external authorised(node) {
        hashes[node] = hash;
        emit ContenthashChanged(node, hash);
    }

    /**
     * Returns the contenthash associated with an ENS node.
     * @param node The ENS node to query.
     * @return The associated contenthash.
     */
    function contenthash(bytes32 node) external view returns (bytes memory) {
        return hashes[node];
    }

    function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
        return interfaceID == CONTENT_HASH_INTERFACE_ID || super.supportsInterface(interfaceID);
    }
}

contract NameResolver is ResolverBase {
    bytes4 constant private NAME_INTERFACE_ID = 0x691f3431;

    event NameChanged(bytes32 indexed node, string name);

    mapping(bytes32=>string) names;

    /**
     * Sets the name associated with an ENS node, for reverse records.
     * May only be called by the owner of that node in the ENS registry.
     * @param node The node to update.
     * @param name The name to set.
     */
    function setName(bytes32 node, string calldata name) external authorised(node) {
        names[node] = name;
        emit NameChanged(node, name);
    }

    /**
     * Returns the name associated with an ENS node, for reverse records.
     * Defined in EIP181.
     * @param node The ENS node to query.
     * @return The associated name.
     */
    function name(bytes32 node) external view returns (string memory) {
        return names[node];
    }

    function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
        return interfaceID == NAME_INTERFACE_ID || super.supportsInterface(interfaceID);
    }
}

contract ABIResolver is ResolverBase {
    bytes4 constant private ABI_INTERFACE_ID = 0x2203ab56;

    event ABIChanged(bytes32 indexed node, uint256 indexed contentType);

    mapping(bytes32=>mapping(uint256=>bytes)) abis;

    /**
     * Sets the ABI associated with an ENS node.
     * Nodes may have one ABI of each content type. To remove an ABI, set it to
     * the empty string.
     * @param node The node to update.
     * @param contentType The content type of the ABI
     * @param data The ABI data.
     */
    function setABI(bytes32 node, uint256 contentType, bytes calldata data) external authorised(node) {
        // Content types must be powers of 2
        require(((contentType - 1) & contentType) == 0);

        abis[node][contentType] = data;
        emit ABIChanged(node, contentType);
    }

    /**
     * Returns the ABI associated with an ENS node.
     * Defined in EIP205.
     * @param node The ENS node to query
     * @param contentTypes A bitwise OR of the ABI formats accepted by the caller.
     * @return contentType The content type of the return value
     * @return data The ABI data
     */
    function ABI(bytes32 node, uint256 contentTypes) external view returns (uint256, bytes memory) {
        mapping(uint256=>bytes) storage abiset = abis[node];

        for (uint256 contentType = 1; contentType <= contentTypes; contentType <<= 1) {
            if ((contentType & contentTypes) != 0 && abiset[contentType].length > 0) {
                return (contentType, abiset[contentType]);
            }
        }

        return (0, bytes(""));
    }

    function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
        return interfaceID == ABI_INTERFACE_ID || super.supportsInterface(interfaceID);
    }
}

library SafeERC20 {
    using SafeMath for uint256;
    using Address for address;

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

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

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

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

    function safeDecreaseAllowance(ERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value);
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

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

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

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

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

library BytesUtils {

    using SafeMath for uint256;

    /// @dev This function converts to an address
    /// @param _bts bytes
    /// @param _from start position
    function _bytesToAddress(bytes memory _bts, uint _from) internal pure returns (address) {

        require(_bts.length >= _from.add(20), "slicing out of range");

        bytes20 convertedAddress;
        uint startByte = _from.add(32); //first 32 bytes denote the array length

        assembly {
            convertedAddress := mload(add(_bts, startByte))
        }

        return address(convertedAddress);
    }

    /// @dev This function slices bytes into bytes4
    /// @param _bts some bytes
    /// @param _from start position
    function _bytesToBytes4(bytes memory _bts, uint _from) internal pure returns (bytes4) {
        require(_bts.length >= _from.add(4), "slicing out of range");

        bytes4 slicedBytes4;
        uint startByte = _from.add(32); //first 32 bytes denote the array length

        assembly {
            slicedBytes4 := mload(add(_bts, startByte))
        }

        return slicedBytes4;

    }

    /// @dev This function slices a uint
    /// @param _bts some bytes
    /// @param _from start position
    // credit to https://ethereum.stackexchange.com/questions/51229/how-to-convert-bytes-to-uint-in-solidity
    // and Nick Johnson https://ethereum.stackexchange.com/questions/4170/how-to-convert-a-uint-to-bytes-in-solidity/4177#4177
    function _bytesToUint256(bytes memory _bts, uint _from) internal pure returns (uint) {
        require(_bts.length >= _from.add(32), "slicing out of range");

        uint convertedUint256;
        uint startByte = _from.add(32); //first 32 bytes denote the array length
        
        assembly {
            convertedUint256 := mload(add(_bts, startByte))
        }

        return convertedUint256;
    }
}

contract Balanceable {

    /// @dev This function is used to get a balance
    /// @param _address of which balance we are trying to ascertain
    /// @param _asset is the address of an ERC20 token or 0x0 for ether.
    /// @return balance associated with an address, for any token, in the wei equivalent
    function _balance(address _address, address _asset) internal view returns (uint) {
        if (_asset != address(0)) {
            return ERC20(_asset).balanceOf(_address);
        } else {
            return _address.balance;
        }
    }
}

contract PubkeyResolver is ResolverBase {
    bytes4 constant private PUBKEY_INTERFACE_ID = 0xc8690233;

    event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y);

    struct PublicKey {
        bytes32 x;
        bytes32 y;
    }

    mapping(bytes32=>PublicKey) pubkeys;

    /**
     * Sets the SECP256k1 public key associated with an ENS node.
     * @param node The ENS node to query
     * @param x the X coordinate of the curve point for the public key.
     * @param y the Y coordinate of the curve point for the public key.
     */
    function setPubkey(bytes32 node, bytes32 x, bytes32 y) external authorised(node) {
        pubkeys[node] = PublicKey(x, y);
        emit PubkeyChanged(node, x, y);
    }

    /**
     * Returns the SECP256k1 public key associated with an ENS node.
     * Defined in EIP 619.
     * @param node The ENS node to query
     * @return x, y the X and Y coordinates of the curve point for the public key.
     */
    function pubkey(bytes32 node) external view returns (bytes32 x, bytes32 y) {
        return (pubkeys[node].x, pubkeys[node].y);
    }

    function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
        return interfaceID == PUBKEY_INTERFACE_ID || super.supportsInterface(interfaceID);
    }
}

contract TextResolver is ResolverBase {
    bytes4 constant private TEXT_INTERFACE_ID = 0x59d1d43c;

    event TextChanged(bytes32 indexed node, string indexedKey, string key);

    mapping(bytes32=>mapping(string=>string)) texts;

    /**
     * Sets the text data associated with an ENS node and key.
     * May only be called by the owner of that node in the ENS registry.
     * @param node The node to update.
     * @param key The key to set.
     * @param value The text data value to set.
     */
    function setText(bytes32 node, string calldata key, string calldata value) external authorised(node) {
        texts[node][key] = value;
        emit TextChanged(node, key, key);
    }

    /**
     * Returns the text data associated with an ENS node and key.
     * @param node The ENS node to query.
     * @param key The text data key to query.
     * @return The associated text data.
     */
    function text(bytes32 node, string calldata key) external view returns (string memory) {
        return texts[node][key];
    }

    function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
        return interfaceID == TEXT_INTERFACE_ID || super.supportsInterface(interfaceID);
    }
}

contract Transferrable {

    using SafeERC20 for ERC20;


    /// @dev This function is used to move tokens sent accidentally to this contract method.
    /// @dev The owner can chose the new destination address
    /// @param _to is the recipient's address.
    /// @param _asset is the address of an ERC20 token or 0x0 for ether.
    /// @param _amount is the amount to be transferred in base units.
    function _safeTransfer(address payable _to, address _asset, uint _amount) internal {
        // address(0) is used to denote ETH
        if (_asset == address(0)) {
            _to.transfer(_amount);
        } else {
            ERC20(_asset).safeTransfer(_to, _amount);
        }
    }
}

contract InterfaceResolver is ResolverBase, AddrResolver {
    bytes4 constant private INTERFACE_INTERFACE_ID = bytes4(keccak256("interfaceImplementer(bytes32,bytes4)"));
    bytes4 private constant INTERFACE_META_ID = 0x01ffc9a7;

    event InterfaceChanged(bytes32 indexed node, bytes4 indexed interfaceID, address implementer);

    mapping(bytes32=>mapping(bytes4=>address)) interfaces;

    /**
     * Sets an interface associated with a name.
     * Setting the address to 0 restores the default behaviour of querying the contract at `addr()` for interface support.
     * @param node The node to update.
     * @param interfaceID The EIP 168 interface ID.
     * @param implementer The address of a contract that implements this interface for this node.
     */
    function setInterface(bytes32 node, bytes4 interfaceID, address implementer) external authorised(node) {
        interfaces[node][interfaceID] = implementer;
        emit InterfaceChanged(node, interfaceID, implementer);
    }

    /**
     * Returns the address of a contract that implements the specified interface for this name.
     * If an implementer has not been set for this interfaceID and name, the resolver will query
     * the contract at `addr()`. If `addr()` is set, a contract exists at that address, and that
     * contract implements EIP168 and returns `true` for the specified interfaceID, its address
     * will be returned.
     * @param node The ENS node to query.
     * @param interfaceID The EIP 168 interface ID to check for.
     * @return The address that implements this interface, or 0 if the interface is unsupported.
     */
    function interfaceImplementer(bytes32 node, bytes4 interfaceID) external view returns (address) {
        address implementer = interfaces[node][interfaceID];
        if(implementer != address(0)) {
            return implementer;
        }

        address a = addr(node);
        if...

// [truncated — 124178 bytes total]

Read Contract

WALLET_VERSION 0x1127b57e → string
calculateHash 0xcd7958dd → bytes32
controllerNode 0xe2b4ce97 → bytes32
convertToEther 0xb87e21ef → uint256
convertToStablecoin 0xf36febda → uint256
ensRegistry 0x7d73b231 → address
gasTopUpLimitAvailable 0x7d7d0046 → uint256
gasTopUpLimitPending 0xcc0e7e56 → uint256
gasTopUpLimitUpdateable 0xc7851418 → bool
gasTopUpLimitValue 0x2587a6a2 → uint256
isSetWhitelist 0xbe40ba79 → bool
isTransferable 0x2121dc75 → bool
licenceNode 0x747c31d6 → bytes32
loadLimitAvailable 0x1efd0299 → uint256
loadLimitPending 0xc4856cd9 → uint256
loadLimitUpdateable 0x227149a3 → bool
loadLimitValue 0xda84b1ed → uint256
owner 0x8da5cb5b → address
pendingWhitelistAddition 0x47b55a9d → address[]
pendingWhitelistRemoval 0x294f4025 → address[]
spendLimitAvailable 0x5d2362a8 → uint256
spendLimitPending 0x027ef3eb → uint256
spendLimitUpdateable 0x4aa46fde → bool
spendLimitValue 0x9b0dfd27 → uint256
submittedWhitelistAddition 0x26d05ab2 → bool
submittedWhitelistRemoval 0xde212bf3 → bool
supportsInterface 0x01ffc9a7 → bool
tokenWhitelistNode 0x877337b0 → bytes32
whitelistArray 0xd251fefc → address
whitelistMap 0x32531c3c → bool

Write Contract 23 functions

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

bulkTransfer 0x1aa21fba
address _to
address[] _assets
cancelWhitelistAddition 0x100f23fd
bytes32 _hash
cancelWhitelistRemoval 0xce0b5bd5
bytes32 _hash
confirmGasTopUpLimitUpdate 0xf41c4319
uint256 _amount
confirmLoadLimitUpdate 0xf40b51f8
uint256 _amount
confirmSpendLimitUpdate 0xeadd3cea
uint256 _amount
confirmWhitelistAddition 0x5adc02ab
bytes32 _hash
confirmWhitelistRemoval 0xcbd2ac68
bytes32 _hash
executeTransaction 0x3f579f42
address _destination
uint256 _value
bytes _data
returns: bytes
loadTokenCard 0x3a43199f
address _asset
uint256 _amount
renounceOwnership 0x715018a6
No parameters
setGasTopUpLimit 0x0f3a85d8
uint256 _amount
setLoadLimit 0x3bfec254
uint256 _amount
setSpendLimit 0x3c672eb7
uint256 _amount
setWhitelist 0xf4217648
address[] _addresses
submitGasTopUpLimitUpdate 0x74624c55
uint256 _amount
submitLoadLimitUpdate 0xb221f316
uint256 _amount
submitSpendLimitUpdate 0x21ce918d
uint256 _amount
submitWhitelistAddition 0x7fd004fa
address[] _addresses
submitWhitelistRemoval 0x6137d670
address[] _addresses
topUpGas 0xe61c51ca
uint256 _amount
transfer 0xbeabacc8
address _to
address _asset
uint256 _amount
transferOwnership 0xb242e534
address _account
bool _transferable

Recent Transactions

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