Address Contract Partially Verified
Address
0xa7053782dC3523D2C82B439Acf3f9344Fb47b97f
Balance
0 ETH
Nonce
1
Code Size
23006 bytes
Creator
0xd5eA7898...6BA1 at tx 0x327768c1...a95f63
Indexed Transactions
0 (1 on-chain, 1.5% indexed)
Contract Bytecode
23006 bytes
0x608060405234801561001057600080fd5b50600436106102895760003560e01c806370a082311161015c578063d0c93a7c116100ce578063e1c7392a11610087578063e1c7392a14610510578063eb3221b414610518578063ef095f8d14610520578063f39c38a014610528578063f56408ed14610530578063fa461e331461054357610289565b8063d0c93a7c146104bf578063d21220a7146104c7578063d3487997146104cf578063d505accf146104e2578063da486721146104f5578063dd62ed3e146104fd57610289565b80638dbdbe6d116101205780638dbdbe6d1461045457806395d89b4114610476578063a457c2d71461047e578063a8c62e7614610491578063a9059cbb14610499578063ab033ea9146104ac57610289565b806370a08231146104165780637d7c2a1c146104295780637ecebe001461043157806380814ffb146104445780638456cb591461044c57610289565b8063242cae9f1161020057806347d792c5116101b957806347d792c5146103ce57806355b812a8146103d657806359c4f905146103eb5780635aa6e675146103f35780636a2a507b146103fb5780636d70f7ae1461040357610289565b8063242cae9f14610370578063313ce5671461038357806333a100ca146103985780633644e515146103ab57806339509351146103b35780633f4ba83a146103c657610289565b806314c04c4f1161025257806314c04c4f1461031b578063158ef93e1461033057806316f0115b1461033857806318160ddd14610340578063238efcbc1461035557806323b872dd1461035d57610289565b8062f714ce1461028e57806306fdde03146102b857806309218e91146102cd578063095ea7b3146102e65780630dfe168114610306575b600080fd5b6102a161029c3660046150b1565b610556565b6040516102af929190615898565b60405180910390f35b6102c06107f4565b6040516102af9190615433565b6102d561088b565b6040516102af959493929190615866565b6102f96102f4366004614d42565b610950565b6040516102af919061534a565b61030e61096e565b6040516102af91906151ea565b61032e6103293660046150d5565b610992565b005b6102f9610c66565b61030e610c76565b610348610c85565b6040516102af9190615355565b61032e610c8b565b6102f961036b366004614c92565b610d14565b61032e61037e366004614c3e565b610dad565b61038b610dfb565b6040516102af91906158d7565b61032e6103a6366004614c3e565b610e04565b610348610e76565b6102f96103c1366004614d42565b610e85565b61032e610ed3565b610348610f35565b6103de610f3b565b6040516102af91906153dc565b6103de610f4b565b61030e610f5b565b610348610f6a565b6102f9610411366004614c3e565b610f70565b610348610424366004614c3e565b610f92565b61032e610fad565b61034861043f366004614c3e565b61179b565b6103486117bc565b61032e6117c2565b6104676104623660046150f6565b61182b565b6040516102af939291906158a6565b6102c0611baa565b6102f961048c366004614d42565b611c0b565b61030e611c76565b6102f96104a7366004614d42565b611c85565b61032e6104ba366004614c3e565b611c99565b6103de611ce5565b61030e611d09565b61032e6104dd366004614e8e565b611d2d565b61032e6104f0366004614cd2565b611dda565b6102a1611ebc565b61034861050b366004614c5a565b611f23565b61032e611f4e565b61032e612173565b6103486124f2565b61030e6124f8565b61032e61053e366004614c3e565b612507565b61032e610551366004614e8e565b612552565b600080600260075414156105855760405162461bcd60e51b815260040161057c9061580e565b60405180910390fd5b60026007556010546040805163e7c7cb9160e01b815290516106a1926001600160a01b03169163e7c7cb91916004808301926020929190829003018186803b1580156105d057600080fd5b505afa1580156105e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106089190614e51565b601060009054906101000a90046001600160a01b03166001600160a01b03166326d895456040518163ffffffff1660e01b815260040160206040518083038186803b15801561065657600080fd5b505afa15801561066a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061068e919061512e565b6009546001600160a01b03169190612629565b601054600160d81b900460ff16156106cb5760405162461bcd60e51b815260040161057c906155bc565b600084116106eb5760405162461bcd60e51b815260040161057c906156f5565b6001600160a01b0383166107115760405162461bcd60e51b815260040161057c90615463565b6107196126f5565b610721612950565b505060105461075e90600160a01b8104600290810b91600160b81b9004900b610748610c85565b6009546001600160a01b03169291908888612aee565b9092509050811515806107715750600081115b61078d5760405162461bcd60e51b815260040161057c90615780565b6107973385612ca3565b826001600160a01b0316336001600160a01b03167febff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f8685856040516107de939291906158a6565b60405180910390a3600160075590939092509050565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156108805780601f1061085557610100808354040283529160200191610880565b820191906000526020600020905b81548152906001019060200180831161086357829003601f168201915b505050505090505b90565b6000806000806000806108bd30601060149054906101000a900460020b601060179054906101000a900460020b612d88565b60095460405163514ea4bf60e01b81529192506001600160a01b03169063514ea4bf906108ee908490600401615355565b60a06040518083038186803b15801561090657600080fd5b505afa15801561091a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093e9190614f92565b939a9299509097509550909350915050565b600061096461095d612dbe565b8484612dc2565b5060015b92915050565b7f000000000000000000000000bb0e17ef65f82ab018d8edd776e8dd940327b28b81565b600260075414156109b55760405162461bcd60e51b815260040161057c9061580e565b6002600755600e546001600160a01b031633146109e45760405162461bcd60e51b815260040161057c906157d4565b6109ec6126f5565b81600a541015610a0e5760405162461bcd60e51b815260040161057c9061582a565b80600b541015610a305760405162461bcd60e51b815260040161057c9061559f565b6040516370a0823160e01b81526000906001600160a01b037f000000000000000000000000bb0e17ef65f82ab018d8edd776e8dd940327b28b16906370a0823190610a7f9030906004016151ea565b60206040518083038186803b158015610a9757600080fd5b505afa158015610aab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610acf9190615099565b905060007f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610b1f91906151ea565b60206040518083038186803b158015610b3757600080fd5b505afa158015610b4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b6f9190615099565b9050838210158015610b815750828110155b610b8a57600080fd5b8315610bbc57610bbc7f000000000000000000000000bb0e17ef65f82ab018d8edd776e8dd940327b28b303387612e76565b8215610bee57610bee7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2303386612e76565b600a54610bfb9085612ea9565b600a55600b54610c0b9084612ea9565b600b55610c16612950565b5050336001600160a01b03167fd6f2c8500df5b44f11e9e48b91ff9f1b9d81bc496d55570c2b1b75bf65243f518585604051610c53929190615898565b60405180910390a2505060016007555050565b601054600160d01b900460ff1681565b6009546001600160a01b031681565b60025490565b600f546001600160a01b03163314610cb55760405162461bcd60e51b815260040161057c9061552c565b600f54600e546040516001600160a01b0392831692909116907f2276211a3f2c7bc1943fe83cc63f8f970204ff6a4b83c690df2bc54d8f2792ad90600090a3600f80546001600160a01b0319908116909155600e805490911633179055565b6000610d21848484612eb9565b610da284610d2d612dbe565b610d9d856040518060400160405280600381526020016254454160e81b815250600160008b6001600160a01b03166001600160a01b031681526020019081526020016000206000610d7c612dbe565b6001600160a01b031681526020810191909152604001600020549190612fd1565b612dc2565b5060015b9392505050565b600e546001600160a01b03163314610dd75760405162461bcd60e51b815260040161057c906157d4565b6001600160a01b03166000908152600860205260409020805460ff19166001179055565b60055460ff1690565b600e546001600160a01b03163314610e2e5760405162461bcd60e51b815260040161057c906157d4565b6001600160a01b038116610e545760405162461bcd60e51b815260040161057c9061572d565b601080546001600160a01b0319166001600160a01b0392909216919091179055565b6000610e80612ffe565b905090565b6000610964610e92612dbe565b84610d9d8560016000610ea3612dbe565b6001600160a01b03908116825260208083019390935260409182016000908120918c1681529252902054906130c8565b600e546001600160a01b03163314610efd5760405162461bcd60e51b815260040161057c906157d4565b601054600160d81b900460ff16610f265760405162461bcd60e51b815260040161057c90615764565b6010805460ff60d81b19169055565b600a5481565b601054600160b81b900460020b81565b601054600160a01b900460020b81565b600e546001600160a01b031681565b600b5481565b6001600160a01b03811660009081526008602052604090205460ff165b919050565b6001600160a01b031660009081526020819052604090205490565b60026007541415610fd05760405162461bcd60e51b815260040161057c9061580e565b60026007556010546040805163e7c7cb9160e01b8152905161101b926001600160a01b03169163e7c7cb91916004808301926020929190829003018186803b1580156105d057600080fd5b3360009081526008602052604090205460ff1661104a5760405162461bcd60e51b815260040161057c906157b7565b6110526126f5565b601054600954611083916001600160a01b0390911690600160a01b8104600290810b91600160b81b9004900b6130d8565b600080600960009054906101000a90046001600160a01b03166001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e06040518083038186803b1580156110d457600080fd5b505afa1580156110e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110c9190614fe8565b50505050509150915061111d614afb565b6010546040805163145485e160e11b815290516000926001600160a01b0316916328a90bc2916004808301926020929190829003018186803b15801561116257600080fd5b505afa158015611176573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061119a9190614e51565b7f000000000000000000000000000000000000000000000000000000000000003c0290506111e983827f000000000000000000000000000000000000000000000000000000000000003c61320f565b600290810b810b60c085015290810b900b60a083015261120761322c565b82526112116132d6565b602083018190528251604051600080516020615989833981519152926112379291615898565b60405180910390a18151602083015160a084015160c085015160095461126c946001600160a01b03909116939092909161332a565b6001600160801b03166080830181905260a083015160c08401516009546112a0936001600160a01b039091169290916133d0565b6060840181905260408401829052835160208501516000936112c193613479565b90506000816112f5576112f060026112ea86606001518760200151612ea990919063ffffffff16565b906134b4565b61130c565b6040840151845161130c916002916112ea91612ea9565b90506000620f424062ffffff166113c76002601060009054906101000a90046001600160a01b03166001600160a01b0316630a7013236040518163ffffffff1660e01b815260040160206040518083038186803b15801561136c57600080fd5b505afa158015611380573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113a49190615076565b62ffffff16816113b057fe5b6001600160a01b038b169162ffffff9104166134b9565b6001600160a01b0316816113d757fe5b0490506000836113f9576113f46001600160a01b0389168361350b565b61140c565b61140c6001600160a01b03891683613527565b6009546040805160208082018352881515825291519394506001600160a01b039092169263128acb08923092899289928892611448920161585a565b6040516020818303038152906040526040518663ffffffff1660e01b8152600401611477959493929190615222565b6040805180830381600087803b15801561149057600080fd5b505af11580156114a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c89190614e6b565b5050600960009054906101000a90046001600160a01b03166001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e06040518083038186803b15801561151857600080fd5b505afa15801561152c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115509190614fe8565b50949c50929a50611565935061322c92505050565b865261156f6132d6565b602087018190528651604051600080516020615989833981519152926115959291615898565b60405180910390a1855160208701516009546115de926001600160a01b0390911691887f000000000000000000000000000000000000000000000000000000000000003c613543565b6010805462ffffff60b81b1916600160b81b600293840b62ffffff90811682029290921762ffffff60a01b1916600160a01b95850b9290921685029190911791829055895160208b015160095461164e966001600160a01b039091169592949193908204830b929104900b61332a565b6001600160801b03166080870181905260095460105460408051602080820183523080835292516001600160a01b0390951695633c8a7d8d959394600160a01b8104600290810b95600160b81b909204900b9391926116ae929101615847565b6040516020818303038152906040526040518663ffffffff1660e01b81526004016116dd959493929190615268565b6040805180830381600087803b1580156116f657600080fd5b505af115801561170a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061172e9190614e6b565b60608801819052604080890183905260105490517fe8cca0c7750fd7d917d80f8fdf0471f461983adb519dab0c25dc7ebfe828e05f9361178493600160a01b8404600290810b94600160b81b9004900b92615410565b60405180910390a150506001600755505050505050565b6001600160a01b038116600090815260066020526040812061096890613742565b600c5481565b600e546001600160a01b031633146117ec5760405162461bcd60e51b815260040161057c906157d4565b601054600160d81b900460ff16156118165760405162461bcd60e51b815260040161057c906155bc565b6010805460ff60d81b1916600160d81b179055565b6000806000600260075414156118535760405162461bcd60e51b815260040161057c9061580e565b60026007556010546040805163e7c7cb9160e01b8152905161189e926001600160a01b03169163e7c7cb91916004808301926020929190829003018186803b1580156105d057600080fd5b601054600160d81b900460ff16156118c85760405162461bcd60e51b815260040161057c906155bc565b6118d06126f5565b6118d8612950565b505060105460095460009161190c916001600160a01b031690600160a01b8104600290810b91600160b81b9004900b613746565b601054600954919250600091611947916001600160a01b03909116908a908a90600160a01b8104600290810b91600160b81b9004900b61332a565b600954601054604080516020808201835233825291519495506001600160a01b0390931693633c8a7d8d933093600160a01b8104600290810b94600160b81b909204900b92889261199a92909101615847565b6040516020818303038152906040526040518663ffffffff1660e01b81526004016119c9959493929190615268565b6040805180830381600087803b1580156119e257600080fd5b505af11580156119f6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a1a9190614e6b565b90945092508315801590611a2e5750600083115b611a4a5760405162461bcd60e51b815260040161057c90615565565b611a52610c85565b15611a8057611a7b816001600160801b0316611a6c610c85565b846001600160801b03166137e1565b611a90565b6001600160801b03620f42408202165b9450611a9c8686613890565b611aa4610c85565b601060009054906101000a90046001600160a01b03166001600160a01b0316632ab4d0526040518163ffffffff1660e01b815260040160206040518083038186803b158015611af257600080fd5b505afa158015611b06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b2a9190615099565b1015611b485760405162461bcd60e51b815260040161057c9061560f565b856001600160a01b0316336001600160a01b03167f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f6878787604051611b8f939291906158a6565b60405180910390a35050600160078190555093509350939050565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156108805780601f1061085557610100808354040283529160200191610880565b6000610964611c18612dbe565b84610d9d85604051806040016040528060038152602001622222a160e91b81525060016000611c45612dbe565b6001600160a01b03908116825260208083019390935260409182016000908120918d16815292529020549190612fd1565b6010546001600160a01b031681565b6000610964611c92612dbe565b8484612eb9565b600e546001600160a01b03163314611cc35760405162461bcd60e51b815260040161057c906157d4565b600f80546001600160a01b0319166001600160a01b0392909216919091179055565b7f000000000000000000000000000000000000000000000000000000000000003c81565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6009546001600160a01b03163314611d575760405162461bcd60e51b815260040161057c906154d5565b6000611d6582840184614edf565b90508415611d9d57611d9d7f000000000000000000000000bb0e17ef65f82ab018d8edd776e8dd940327b28b82600001513388612e76565b8315611dd357611dd37f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc282600001513387612e76565b5050505050565b83421115611dfa5760405162461bcd60e51b815260040161057c906154b9565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888611e298c613944565b89604051602001611e3f9695949392919061535e565b6040516020818303038152906040528051906020012090506000611e6282613976565b90506000611e7282878787613989565b9050896001600160a01b0316816001600160a01b031614611ea55760405162461bcd60e51b815260040161057c90615682565b611eb08a8a8a612dc2565b50505050505050505050565b6010546009546000918291611ef2916001600160a01b0390911690600160a01b8104600290810b91600160b81b9004900b613a81565b9092509050611f09611f0261322c565b83906130c8565b9150611f1d611f166132d6565b82906130c8565b90509091565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600e546001600160a01b03163314611f785760405162461bcd60e51b815260040161057c906157d4565b601054600160d01b900460ff1615611fa25760405162461bcd60e51b815260040161057c90615749565b6010805460ff60d01b1916600160d01b17908190556040805163145485e160e11b815290516000926001600160a01b0316916328a90bc2916004808301926020929190829003018186803b158015611ff957600080fd5b505afa15801561200d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120319190614e51565b7f000000000000000000000000000000000000000000000000000000000000003c0290506000600960009054906101000a90046001600160a01b03166001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e06040518083038186803b1580156120a557600080fd5b505afa1580156120b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120dd9190614fe8565b50505050509150506000612111827f000000000000000000000000000000000000000000000000000000000000003c613b63565b6010805462ffffff60a01b1916600160a01b868403600290810b62ffffff90811683029390931762ffffff60b81b1916600160b81b868a01830b949094168402179384905593945061216e93908304810b9291909104900b613baf565b505050565b600260075414156121965760405162461bcd60e51b815260040161057c9061580e565b60026007556010546040805163e7c7cb9160e01b815290516121e1926001600160a01b03169163e7c7cb91916004808301926020929190829003018186803b1580156105d057600080fd5b3360009081526008602052604090205460ff166122105760405162461bcd60e51b815260040161057c906157b7565b6122186126f5565b601054600954612249916001600160a01b0390911690600160a01b8104600290810b91600160b81b9004900b6130d8565b600061225361322c565b9050600061225f6132d6565b90506000805160206159898339815191528282604051612280929190615898565b60405180910390a16010546040805163145485e160e11b815290516000926001600160a01b0316916328a90bc2916004808301926020929190829003018186803b1580156122cd57600080fd5b505afa1580156122e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123059190614e51565b6009547f000000000000000000000000000000000000000000000000000000000000003c9182029250612349916001600160a01b0390911690859085908590613543565b6010805462ffffff60b81b1916600160b81b600293840b62ffffff90811682029290921762ffffff60a01b1916600160a01b95850b92909216850291909117918290556009546000946123b5946001600160a01b039092169389938993928204830b929104900b61332a565b600954601054604080516020808201835230808352925195965060009586956001600160a01b031694633c8a7d8d9493600160a01b8204600290810b94600160b81b909304900b928a9261240a929101615847565b6040516020818303038152906040526040518663ffffffff1660e01b8152600401612439959493929190615268565b6040805180830381600087803b15801561245257600080fd5b505af1158015612466573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061248a9190614e6b565b6010546040519294509092507fe8cca0c7750fd7d917d80f8fdf0471f461983adb519dab0c25dc7ebfe828e05f916124dd91600160a01b8104600290810b92600160b81b909204900b9086908690615410565b60405180910390a15050600160075550505050565b600d5481565b600f546001600160a01b031681565b600e546001600160a01b031633146125315760405162461bcd60e51b815260040161057c906157d4565b6001600160a01b03166000908152600860205260409020805460ff19169055565b6009546001600160a01b0316331461257c5760405162461bcd60e51b815260040161057c906154d5565b600084138061258b5750600083135b6125a75760405162461bcd60e51b815260040161057c906156bb565b60006125b582840184614f24565b805190915080156125f1576125ec7f000000000000000000000000bb0e17ef65f82ab018d8edd776e8dd940327b28b303389612e76565b61261d565b61261d7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2303388612e76565b505050505050565b4690565b6000836001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e06040518083038186803b15801561266457600080fd5b505afa158015612678573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061269c9190614fe8565b505050505091505060006126b08584613c27565b905060008160020b8360020b136126c9578282036126cd565b8183035b90508460020b8160020b131561261d5760405162461bcd60e51b815260040161057c906156d8565b601054600954600091612727916001600160a01b031690600160a01b8104600290810b91600160b81b9004900b613746565b6001600160801b031690508061273d575061294e565b60095460105460405163a34123a760e01b81526001600160a01b039092169163a34123a79161278891600160a01b8204600290810b92600160b81b9004900b906000906004016153ea565b6040805180830381600087803b1580156127a157600080fd5b505af11580156127b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d99190614e6b565b50506009546010546040516309e3d67b60e31b815260009283926001600160a01b0390911691634f1eb3d891612836913091600160a01b8104600290810b92600160b81b909204900b906001600160801b039081906004016152aa565b6040805180830381600087803b15801561284f57600080fd5b505af1158015612863573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128879190614f60565b6001600160801b03918216935016905060006128ad620f42406112ea8562030d40613d67565b905060006128c5620f42406112ea8562030d40613d67565b600a549091506128d590836130c8565b600a55600b546128e590826130c8565b600b55600c546128f590856130c8565b600c55600d5461290590846130c8565b600d819055600c546040517f1ac56d7e866e3f5ea9aa92aa11758ead39a0a5f013f3fefb0f47cb9d008edd27926129409288928892906158bc565b60405180910390a150505050505b565b600080600061295d61322c565b905060006129696132d6565b9050600080516020615989833981519152828260405161298a929190615898565b60405180910390a16010546009546000916129c8916001600160a01b03169085908590600160a01b8104600290810b91600160b81b9004900b61332a565b90506001600160801b03811615612ae75760095460105460408051602080820183523080835292516001600160a01b0390951694633c8a7d8d94600160a01b8104600290810b94600160b81b909204900b928892612a27929101615847565b6040516020818303038152906040526040518663ffffffff1660e01b8152600401612a56959493929190615268565b6040805180830381600087803b158015612a6f57600080fd5b505af1158015612a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aa79190614e6b565b60405191965094507f2fb985eb745b9e89bb1ab82e0f8ceb6bf94d4d60aed7e8196540c50161a5fe9190612ade9087908790615898565b60405180910390a15b5050509091565b60008060008511612b115760405162461bcd60e51b815260040161057c9061549d565b6000612b276001600160a01b038a168989613746565b9050600086612b3f6001600160801b03841688613d67565b81612b4657fe5b0490508015612c9657896001600160a01b031663a34123a78a8a612b6985613d8a565b6040518463ffffffff1660e01b8152600401612b87939291906153ea565b6040805180830381600087803b158015612ba057600080fd5b505af1158015612bb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bd89190614e6b565b909450925083151580612beb5750600083115b15612c9657896001600160a01b0316634f1eb3d8868b8b612c0b89613d8a565b612c1489613d8a565b6040518663ffffffff1660e01b8152600401612c349594939291906152aa565b6040805180830381600087803b158015612c4d57600080fd5b505af1158015612c61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c859190614f60565b6001600160801b0391821695501692505b5050965096945050505050565b6001600160a01b038216612cc95760405162461bcd60e51b815260040161057c9061550f565b612cd58260008361216e565b60408051808201825260038152622122a160e91b6020808301919091526001600160a01b0385166000908152908190529190912054612d15918390612fd1565b6001600160a01b038316600090815260208190526040902055600254612d3b9082612ea9565b6002556040516000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612d7c908590615355565b60405180910390a35050565b6000838383604051602001612d9f9392919061517e565b6040516020818303038152906040528051906020012090509392505050565b3390565b6001600160a01b038316612de85760405162461bcd60e51b815260040161057c906154f1565b6001600160a01b038216612e0e5760405162461bcd60e51b815260040161057c906157f0565b6001600160a01b0380841660008181526001602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590612e69908590615355565b60405180910390a3505050565b6001600160a01b038316301415612e9757612e92848383613da0565b612ea3565b612ea384848484613e8e565b50505050565b8082038281111561096857600080fd5b6001600160a01b038316612edf5760405162461bcd60e51b815260040161057c90615582565b6001600160a01b038216612f055760405162461bcd60e51b815260040161057c90615548565b612f1083838361216e565b60408051808201825260038152622a22a160e91b6020808301919091526001600160a01b0386166000908152908190529190912054612f50918390612fd1565b6001600160a01b038085166000908152602081905260408082209390935590841681522054612f7f90826130c8565b6001600160a01b0380841660008181526020819052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612e69908590615355565b8183038184821115612ff65760405162461bcd60e51b815260040161057c9190615433565b509392505050565b60007f0000000000000000000000000000000000000000000000000000000000000001613029612625565b141561305657507fe39a5a1759462322d4f74a9642a27e1b33eb1ea591b2d7da5660edab85c18b28610888565b6130c17f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f8531deb3aa6fc3974e5cc7f622bbb3bb1ef3add45010b881693ada1dd01027bf7fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6613f7e565b9050610888565b8082018281101561096857600080fd5b60006130ee6001600160a01b0385168484613746565b90506001600160801b038116156131835760405163a34123a760e01b81526001600160a01b0385169063a34123a79061312f908690869086906004016153ea565b6040805180830381600087803b15801561314857600080fd5b505af115801561315c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131809190614e6b565b50505b6040516309e3d67b60e31b81526001600160a01b03851690634f1eb3d8906131be903090879087906001600160801b039081906004016152aa565b6040805180830381600087803b1580156131d757600080fd5b505af11580156131eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061261d9190614f60565b600080600061321e8685613b63565b858103979501955050505050565b6000610e80600a547f000000000000000000000000bb0e17ef65f82ab018d8edd776e8dd940327b28b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161328091906151ea565b60206040518083038186803b15801561329857600080fd5b505afa1580156132ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132d09190615099565b90612ea9565b6000610e80600b547f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161328091906151ea565b600080866001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e06040518083038186803b15801561336657600080fd5b505afa15801561337a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061339e9190614fe8565b50505050505090506133c3816133b386613fa0565b6133bc86613fa0565b89896142b9565b9150505b95945050505050565b6000806000866001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e06040518083038186803b15801561340e57600080fd5b505afa158015613422573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134469190614fe8565b505050505050905061346a8161345b87613fa0565b61346487613fa0565b8961437b565b92509250505b94509492505050565b600061348f856134898685612ea9565b90613d67565b61349d856134898887612ea9565b116134a95760006133c7565b600195945050505050565b900490565b60006001600160a01b03831615806135025750816001600160a01b0316836001600160a01b03168385029250826001600160a01b0316816134f657fe5b046001600160a01b0316145b61096857600080fd5b8082016001600160a01b03808416908216101561096857600080fd5b8082036001600160a01b03808416908216111561096857600080fd5b60008060006040518060e00160405280888152602001878152602001600081526020016000815260200160006001600160801b03168152602001600060020b8152602001600060020b8152509050600080896001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e06040518083038186803b1580156135cd57600080fd5b505afa1580156135e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136059190614fe8565b50505050509150915061361981888861320f565b600290810b810b60c0860181905291810b900b60a0850181905284516020860151613646938e9390614416565b606085018190526040850182905260a085015160c086015161366d938e939092909161332a565b6001600160801b03166080840152825160208401516040850151606086015160009361369c9390929091613479565b905080156136e15760006136bb84866080015187600001516000614445565b90506136cf6136c982614536565b89613b63565b600290810b900b60c086015250613714565b60006136f88486608001518760200151600061483c565b90506137066136c982614536565b600290810b900b60a0860152505b6137268460a001518560c00151613baf565b8360a0015195508360c001519450505050509550959350505050565b5490565b600080613754308585612d88565b60405163514ea4bf60e01b81529091506001600160a01b0386169063514ea4bf90613783908490600401615355565b60a06040518083038186803b15801561379b57600080fd5b505afa1580156137af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137d39190614f92565b509298975050505050505050565b6000808060001985870986860292508281109083900303905080613817576000841161380c57600080fd5b508290049050610da6565b80841161382357600080fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b6001600160a01b0382166138b65760405162461bcd60e51b815260040161057c90615710565b6138c26000838361216e565b6002546138cf90826130c8565b6002556001600160a01b0382166000908152602081905260409020546138f590826130c8565b6001600160a01b0383166000818152602081905260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612d7c908590615355565b6001600160a01b038116600090815260066020526040812061396581613742565b915061397081614918565b50919050565b6000610968613983612ffe565b83614921565b60007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08211156139cb5760405162461bcd60e51b815260040161057c90615446565b8360ff16601b14806139e057508360ff16601c145b6139fc5760405162461bcd60e51b815260040161057c906155d7565b600060018686868660405160008152602001604052604051613a2194939291906153be565b6020604051602081039080840390855afa158015613a43573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116613a765760405162461bcd60e51b815260040161057c90615682565b90505b949350505050565b6000806000613a91308686612d88565b90506000806000886001600160a01b031663514ea4bf856040518263ffffffff1660e01b8152600401613ac49190615355565b60a06040518083038186803b158015613adc57600080fd5b505afa158015613af0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b149190614f92565b9450945050509250613b2889848a8a6133d0565b9096509450613b40866001600160801b0384166130c8565b9550613b55856001600160801b0383166130c8565b945050505050935093915050565b6000808260020b8460020b81613b7557fe5b05905060008460020b128015613b9c57508260020b8460020b81613b9557fe5b0760020b15155b15613ba657600019015b90910292915050565b8060020b8260020b12613bd45760405162461bcd60e51b815260040161057c90615480565b620d89e719600283900b1215613bfc5760405162461bcd60e51b815260040161057c90615665565b620d89e8600282900b1315613c235760405162461bcd60e51b815260040161057c90615648565b5050565b6040805160028082526060820183526000928492849290916020830190803683370190505090508181600081518110613c5c57fe5b602002602001019063ffffffff16908163ffffffff1681525050600081600181518110613c8557fe5b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526000906001600160a01b0387169063883bdbfd90613cc9908590600401615300565b60006040518083038186803b158015613ce157600080fd5b505afa158015613cf5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613d1d9190810190614d6d565b5090508263ffffffff1681600081518110613d3457fe5b602002602001015182600181518110613d4957fe5b60200260200101510360060b81613d5c57fe5b059695505050505050565b600082158061350257505081810281838281613d7f57fe5b041461096857600080fd5b806001600160801b0381168114610f8d57600080fd5b600080846001600160a01b031663a9059cbb60e01b8585604051602401613dc89291906152e7565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613e0691906151b3565b6000604051808303816000865af19150503d8060008114613e43576040519150601f19603f3d011682016040523d82523d6000602084013e613e48565b606091505b5091509150818015613e72575080511580613e72575080806020019051810190613e729190614e35565b611dd35760405162461bcd60e51b815260040161057c9061562c565b600080856001600160a01b03166323b872dd60e01b868686604051602401613eb8939291906151fe565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613ef691906151b3565b6000604051808303816000865af19150503d8060008114613f33576040519150601f19603f3d011682016040523d82523d6000602084013e613f38565b606091505b5091509150818015613f62575080511580613f62575080806020019051810190613f629190614e35565b61261d5760405162461bcd60e51b815260040161057c9061569e565b6000838383613f8b612625565b30604051602001612d9f959493929190615392565b60008060008360020b12613fb7578260020b613fbf565b8260020b6000035b9050620d89e8811115613fe45760405162461bcd60e51b815260040161057c906155f4565b600060018216613ff857600160801b61400a565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff169050600282161561403e576ffff97272373d413259a46990580e213a0260801c5b600482161561405d576ffff2e50f5f656932ef12357cf3c7fdcc0260801c5b600882161561407c576fffe5caca7e10e4e61c3624eaa0941cd00260801c5b601082161561409b576fffcb9843d60f6159c9db58835c9266440260801c5b60208216156140ba576fff973b41fa98c081472e6896dfb254c00260801c5b60408216156140d9576fff2ea16466c96a3843ec78b326b528610260801c5b60808216156140f8576ffe5dee046a99a2a811c461f1969c30530260801c5b610100821615614118576ffcbe86c7900a88aedcffc83b479aa3a40260801c5b610200821615614138576ff987a7253ac413176f2b074cf7815e540260801c5b610400821615614158576ff3392b0822b70005940c7a398e4b70f30260801c5b610800821615614178576fe7159475a2c29b7443b29c7fa6e889d90260801c5b611000821615614198576fd097f3bdfd2022b8845ad8f792aa58250260801c5b6120008216156141b8576fa9f746462d870fdf8a65dc1f90e061e50260801c5b6140008216156141d8576f70d869a156d2a1b890bb3df62baf32f70260801c5b6180008216156141f8576f31be135f97d08fd981231505542fcfa60260801c5b62010000821615614219576f09aa508b5b7a84e1c677de54f3e99bc90260801c5b62020000821615614239576e5d6af8dedb81196699c329225ee6040260801c5b62040000821615614258576d2216e584f5fa1ea926041bedfe980260801c5b62080000821615614275576b048a170391f7dc42444e8fa20260801c5b60008460020b131561429057806000198161428c57fe5b0490505b6401000000008106156142a45760016142a7565b60005b60ff16602082901c0192505050919050565b6000836001600160a01b0316856001600160a01b031611156142d9579293925b846001600160a01b0316866001600160a01b031611614304576142fd858585614954565b90506133c7565b836001600160a01b0316866001600160a01b0316101561436657600061432b878686614954565b9050600061433a8789866149b7565b9050806001600160801b0316826001600160801b03161061435b578061435d565b815b925050506133c7565b6143718585846149b7565b9695505050505050565b600080836001600160a01b0316856001600160a01b0316111561439c579293925b846001600160a01b0316866001600160a01b0316116143c7576143c08585856149f4565b9150613470565b836001600160a01b0316866001600160a01b03161015614400576143ec8685856149f4565b91506143f9858785614a5d565b9050613470565b61440b858585614a5d565b905094509492505050565b6000806000614428888888888861332a565b9050614436888287876133d0565b90999098509650505050505050565b600082614453575083613a79565b6fffffffffffffffffffffffffffffffff60601b606085901b1682156144ea576001600160a01b0386168481029085828161448a57fe5b0414156144bb578181018281106144b9576144af83896001600160a01b031683614aa0565b9350505050613a79565b505b6144e1826144dc878a6001600160a01b031686816144d557fe5b04906130c8565b614ada565b92505050613a79565b6001600160a01b0386168481029085828161450157fe5b0414801561450e57508082115b61451757600080fd5b8082036144af614531846001600160a01b038b1684614aa0565b614ae5565b60006401000276a36001600160a01b03831610801590614572575073fffd8963efd1fc6a506488495d951d5263988d266001600160a01b038316105b61458e5760405162461bcd60e51b815260040161057c9061579c565b640100000000600160c01b03602083901b166001600160801b03811160071b81811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c60ff8111600390811b91821c600f811160021b90811c918211600190811b92831c9790881196179094179092171790911717176080811061462257607f810383901c915061462c565b80607f0383901b91505b908002607f81811c60ff83811c9190911c800280831c81831c1c800280841c81841c1c800280851c81851c1c800280861c81861c1c800280871c81871c1c800280881c81881c1c800280891c81891c1c8002808a1c818a1c1c8002808b1c818b1c1c8002808c1c818c1c1c8002808d1c818d1c1c8002808e1c9c81901c9c909c1c80029c8d901c9e9d607f198f0160401b60c09190911c678000000000000000161760c19b909b1c674000000000000000169a909a1760c29990991c672000000000000000169890981760c39790971c671000000000000000169690961760c49590951c670800000000000000169490941760c59390931c670400000000000000169290921760c69190911c670200000000000000161760c79190911c670100000000000000161760c89190911c6680000000000000161760c99190911c6640000000000000161760ca9190911c6620000000000000161760cb9190911c6610000000000000161760cc9190911c6608000000000000161760cd9190911c66040000000000001617693627a301d71055774c8581026f028f6481ab7f045a5af012a19d003aa9198101608090811d906fdb2df09e81959a81455e260799a0632f8301901d600281810b9083900b1461482d57886001600160a01b031661481182613fa0565b6001600160a01b031611156148265781614828565b805b61482f565b815b9998505050505050505050565b600081156148aa5760006001600160a01b038411156148725761486d84600160601b876001600160801b03166137e1565b61488a565b6001600160801b038516606085901b8161488857fe5b045b90506148a26145316001600160a01b038816836130c8565b915050613a79565b60006001600160a01b038411156148d8576148d384600160601b876001600160801b0316614aa0565b6148ef565b6148ef606085901b6001600160801b038716614ada565b905080866001600160a01b03161161490657600080fd5b6001600160a01b038616039050613a79565b80546001019055565b600082826040516020016149369291906151cf565b60405160208183030381529060405280519060200120905092915050565b6000826001600160a01b0316846001600160a01b03161115614974579192915b6000614997856001600160a01b0316856001600160a01b0316600160601b6137e1565b90506133c76149b284838888036001600160a01b03166137e1565b613d8a565b6000826001600160a01b0316846001600160a01b031611156149d7579192915b613a796149b283600160601b8787036001600160a01b03166137e1565b6000826001600160a01b0316846001600160a01b03161115614a14579192915b836001600160a01b0316614a4d606060ff16846001600160801b0316901b8686036001600160a01b0316866001600160a01b03166137e1565b81614a5457fe5b04949350505050565b6000826001600160a01b0316846001600160a01b03161115614a7d579192915b613a79826001600160801b03168585036001600160a01b0316600160601b6137e1565b6000614aad8484846137e1565b905060008280614ab957fe5b8486091115610da6576000198110614ad057600080fd5b6001019392505050565b808204910615150190565b806001600160a01b0381168114610f8d57600080fd5b6040518060e001604052806000815260200160008152602001600081526020016000815260200160006001600160801b03168152602001600060020b8152602001600060020b81525090565b600082601f830112614b57578081fd5b81516020614b6c614b6783615909565b6158e5565b8281528181019085830183850287018401881015614b88578586fd5b855b85811015614baf578151614b9d81615953565b84529284019290840190600101614b8a565b5090979650505050505050565b60008083601f840112614bcd578182fd5b50813567ffffffffffffffff811115614be4578182fd5b602083019150836020828501011115614bfc57600080fd5b9250929050565b8051600281900b8114610f8d57600080fd5b80516001600160801b0381168114610f8d57600080fd5b805161ffff81168114610f8d57600080fd5b600060208284031215614c4f578081fd5b8135610da681615953565b60008060408385031215614c6c578081fd5b8235614c7781615953565b91506020830135614c8781615953565b809150509250929050565b600080600060608486031215614ca6578081fd5b8335614cb181615953565b92506020840135614cc181615953565b929592945050506040919091013590565b600080600080600080600060e0888a031215614cec578283fd5b8735614cf781615953565b96506020880135614d0781615953565b955060408801359450606088013593506080880135614d2581615979565b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215614d54578182fd5b8235614d5f81615953565b946020939093013593505050565b60008060408385031215614d7f578182fd5b825167ffffffffffffffff80821115614d96578384fd5b818501915085601f830112614da9578384fd5b81516020614db9614b6783615909565b82815281810190858301838502870184018b1015614dd5578889fd5b8896505b84871015614e055780518060060b8114614df157898afd5b835260019690960195918301918301614dd9565b5091880151919650909350505080821115614e1e578283fd5b50614e2b85828601614b47565b9150509250929050565b600060208284031215614e46578081fd5b8151610da68161596b565b600060208284031215614e62578081fd5b610da682614c03565b60008060408385031215614e7d578182fd5b505080516020909101519092909150565b60008060008060608587031215614ea3578182fd5b8435935060208501359250604085013567ffffffffffffffff811115614ec7578283fd5b614ed387828801614bbc565b95989497509550505050565b600060208284031215614ef0578081fd5b6040516020810181811067ffffffffffffffff82111715614f0d57fe5b6040528235614f1b81615953565b81529392505050565b600060208284031215614f35578081fd5b6040516020810181811067ffffffffffffffff82111715614f5257fe5b6040528235614f1b8161596b565b60008060408385031215614f72578182fd5b614f7b83614c15565b9150614f8960208401614c15565b90509250929050565b600080600080600060a08688031215614fa9578283fd5b614fb286614c15565b94506020860151935060408601519250614fce60608701614c15565b9150614fdc60808701614c15565b90509295509295909350565b600080600080600080600060e0888a031215615002578081fd5b875161500d81615953565b965061501b60208901614c03565b955061502960408901614c2c565b945061503760608901614c2c565b935061504560808901614c2c565b925060a088015161505581615979565b60c08901519092506150668161596b565b8091505092959891949750929550565b600060208284031215615087578081fd5b815162ffffff81168114610da6578182fd5b6000602082840312156150aa578081fd5b5051919050565b600080604083850312156150c3578182fd5b823591506020830135614c8781615953565b600080604083850312156150e7578182fd5b50508035926020909101359150565b60008060006060848603121561510a578081fd5b8335925060208401359150604084013561512381615953565b809150509250925092565b60006020828403121561513f578081fd5b815163ffffffff81168114610da6578182fd5b6000815180845261516a816020860160208601615927565b601f01601f19169290920160200192915050565b60609390931b6bffffffffffffffffffffffff19168352600291820b60e890811b6014850152910b901b6017820152601a0190565b600082516151c5818460208701615927565b9190910192915050565b61190160f01b81526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0386811682528515156020830152604082018590528316606082015260a06080820181905260009061525d90830184615152565b979650505050505050565b600060018060a01b03871682528560020b60208301528460020b60408301526001600160801b038416606083015260a0608083015261525d60a0830184615152565b6001600160a01b03959095168552600293840b60208601529190920b60408401526001600160801b03918216606084015216608082015260a00190565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b8181101561533e57835163ffffffff168352928401929184019160010161531c565b50909695505050505050565b901515815260200190565b90815260200190565b9586526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b9485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b93845260ff9290921660208401526040830152606082015260800190565b60029190910b815260200190565b600293840b81529190920b60208201526001600160801b03909116604082015260600190565b600294850b81529290930b60208301526040820152606081019190915260800190565b600060208252610da66020830184615152565b60208082526003908201526249535360e81b604082015260600190565b602080825260039082015262575a4160e81b604082015260600190565b602080825260039082015262544c5560e81b604082015260600190565b602080825260029082015261545360f01b604082015260600190565b602080825260029082015261115160f21b604082015260600190565b602080825260029082015261046560f41b604082015260600190565b60208082526004908201526341465a4160e01b604082015260600190565b602080825260039082015262425a4160e81b604082015260600190565b602080825260029082015261504760f01b604082015260600190565b602080825260039082015262545a4160e81b604082015260600190565b60208082526003908201526220a72b60e91b604082015260600190565b602080825260039082015262465a4160e81b604082015260600190565b6020808252600390820152622098a360e91b604082015260600190565b6020808252600190820152600560fc1b604082015260600190565b60208082526003908201526224a9ab60e91b604082015260600190565b6020808252600190820152601560fa1b604082015260600190565b6020808252600390820152624d545360e81b604082015260600190565b60208082526002908201526114d560f21b604082015260600190565b60208082526003908201526254554d60e81b604082015260600190565b602080825260039082015262544c4d60e81b604082015260600190565b602080825260029082015261495360f01b604082015260600190565b60208082526003908201526229aa2360e91b604082015260600190565b6020808252600390820152622622ad60e91b604082015260600190565b60208082526003908201526250534360e81b604082015260600190565b6020808252600190820152605360f81b604082015260600190565b6020808252600390820152624d5a4160e81b604082015260600190565b6020808252600290820152614e4160f01b604082015260600190565b6020808252600190820152602360f91b604082015260600190565b60208082526002908201526104e560f41b604082015260600190565b602080825260029082015261454160f01b604082015260600190565b6020808252600190820152602960f91b604082015260600190565b6020808252600390820152624f4e4160e81b604082015260600190565b6020808252600290820152614f4760f01b604082015260600190565b60208082526004908201526341545a4160e01b604082015260600190565b602080825260029082015261524360f01b604082015260600190565b60208082526003908201526220982360e91b604082015260600190565b90516001600160a01b0316815260200190565b90511515815260200190565b6001600160801b0395861681526020810194909452604084019290925283166060830152909116608082015260a00190565b918252602082015260400190565b9283526020830191909152604082015260600190565b93845260208401929092526040830152606082015260800190565b60ff91909116815260200190565b60405181810167ffffffffffffffff8111828210171561590157fe5b604052919050565b600067ffffffffffffffff82111561591d57fe5b5060209081020190565b60005b8381101561594257818101518382015260200161592a565b83811115612ea35750506000910152565b6001600160a01b038116811461596857600080fd5b50565b801515811461596857600080fd5b60ff8116811461596857600080fdfe492fbd8cfdd942203e99f6bc74253a1e1f5791b0644612279e778349f353b198a2646970667358221220091558bc1672442096ff3b3194c8f232ebf545f47423c8d872b2d83536f5f3ea64736f6c63430007060033
Verified Source Code Partial Match
Compiler: v0.7.6+commit.7338295f
EVM: istanbul
Optimization: Yes (200 runs)
PopsicleV3Optimizer.sol 2655 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
pragma abicoder v2;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
interface IPopsicleV3Optimizer {
/// @notice The first of the two tokens of the pool, sorted by address
/// @return The token contract address
function token0() external view returns (address);
/// @notice The second of the two tokens of the pool, sorted by address
/// @return The token contract address
function token1() external view returns (address);
/// @notice The pool tick spacing
/// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive
/// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ...
/// This value is an int24 to avoid casting even though it is always positive.
/// @return The tick spacing
function tickSpacing() external view returns (int24);
/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform
/// to the ERC20 specification
/// @return The address of the Uniswap V3 Pool
function pool() external view returns (IUniswapV3Pool);
/// @notice The lower tick of the range
function tickLower() external view returns (int24);
/// @notice The upper tick of the range
function tickUpper() external view returns (int24);
/**
* @notice Deposits tokens in proportion to the Optimizer's current ticks.
* @param amount0Desired Max amount of token0 to deposit
* @param amount1Desired Max amount of token1 to deposit
* @param to address that plp should be transfered
* @return shares minted
* @return amount0 Amount of token0 deposited
* @return amount1 Amount of token1 deposited
*/
function deposit(uint256 amount0Desired, uint256 amount1Desired, address to) external returns (uint256 shares, uint256 amount0,uint256 amount1);
/**
* @notice Withdraws tokens in proportion to the Optimizer's holdings.
* @dev Removes proportional amount of liquidity from Uniswap.
* @param shares burned by sender
* @return amount0 Amount of token0 sent to recipient
* @return amount1 Amount of token1 sent to recipient
*/
function withdraw(uint256 shares, address to) external returns (uint256 amount0, uint256 amount1);
/**
* @notice Updates Optimizer's positions.
* @dev Finds base position and limit position for imbalanced token
* mints all amounts to this position(including earned fees)
*/
function rerange() external;
/**
* @notice Updates Optimizer's positions. Can only be called by the governance.
* @dev Swaps imbalanced token. Finds base position and limit position for imbalanced token if
* we don't have balance during swap because of price impact.
* mints all amounts to this position(including earned fees)
*/
function rebalance() external;
}
interface IOptimizerStrategy {
/// @return Maximul PLP value that could be minted
function maxTotalSupply() external view returns (uint256);
/// @notice Period of time that we observe for price slippage
/// @return time in seconds
function twapDuration() external view returns (uint32);
/// @notice Maximum deviation of time waited avarage price in ticks
function maxTwapDeviation() external view returns (int24);
/// @notice Tick multuplier for base range calculation
function tickRangeMultiplier() external view returns (int24);
/// @notice The price impact percentage during swap denominated in hundredths of a bip, i.e. 1e-6
/// @return The max price impact percentage
function priceImpactPercentage() external view returns (uint24);
}
library PositionKey {
/// @dev Returns the key of the position in the core library
function compute(
address owner,
int24 tickLower,
int24 tickUpper
) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(owner, tickLower, tickUpper));
}
}
/// @title Math library for computing sqrt prices from ticks and vice versa
/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports
/// prices between 2**-128 and 2**128
library TickMath {
/// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128
int24 internal constant MIN_TICK = -887272;
/// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128
int24 internal constant MAX_TICK = -MIN_TICK;
/// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
uint160 internal constant MIN_SQRT_RATIO = 4295128739;
/// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;
/// @notice Calculates sqrt(1.0001^tick) * 2^96
/// @dev Throws if |tick| > max tick
/// @param tick The input tick for the above formula
/// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)
/// at the given tick
function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {
uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));
require(absTick <= uint256(MAX_TICK), 'T');
uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;
if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;
if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;
if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;
if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;
if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;
if (tick > 0) ratio = type(uint256).max / ratio;
// this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.
// we then downcast because we know the result always fits within 160 bits due to our tick input constraint
// we round up in the division so getTickAtSqrtRatio of the output price is always consistent
sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));
}
/// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio
/// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may
/// ever return.
/// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96
/// @return tick The greatest tick for which the ratio is less than or equal to the input ratio
function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) {
// second inequality must be < because the price can never reach the price at the max tick
require(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, 'R');
uint256 ratio = uint256(sqrtPriceX96) << 32;
uint256 r = ratio;
uint256 msb = 0;
assembly {
let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(5, gt(r, 0xFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(4, gt(r, 0xFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(3, gt(r, 0xFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(2, gt(r, 0xF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(1, gt(r, 0x3))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := gt(r, 0x1)
msb := or(msb, f)
}
if (msb >= 128) r = ratio >> (msb - 127);
else r = ratio << (127 - msb);
int256 log_2 = (int256(msb) - 128) << 64;
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(63, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(62, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(61, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(60, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(59, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(58, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(57, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(56, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(55, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(54, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(53, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(52, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(51, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(50, f))
}
int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number
int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128);
int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128);
tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow;
}
}
/// @title Liquidity amount functions
/// @notice Provides functions for computing liquidity amounts from token amounts and prices
library LiquidityAmounts {
/// @notice Downcasts uint256 to uint128
/// @param x The uint258 to be downcasted
/// @return y The passed value, downcasted to uint128
function toUint128(uint256 x) private pure returns (uint128 y) {
require((y = uint128(x)) == x);
}
/// @notice Computes the amount of liquidity received for a given amount of token0 and price range
/// @dev Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower))
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary
/// @param amount0 The amount0 being sent in
/// @return liquidity The amount of returned liquidity
function getLiquidityForAmount0(
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint256 amount0
) internal pure returns (uint128 liquidity) {
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
uint256 intermediate = FullMath.mulDiv(sqrtRatioAX96, sqrtRatioBX96, FixedPoint96.Q96);
return toUint128(FullMath.mulDiv(amount0, intermediate, sqrtRatioBX96 - sqrtRatioAX96));
}
/// @notice Computes the amount of liquidity received for a given amount of token1 and price range
/// @dev Calculates amount1 / (sqrt(upper) - sqrt(lower)).
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary
/// @param amount1 The amount1 being sent in
/// @return liquidity The amount of returned liquidity
function getLiquidityForAmount1(
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint256 amount1
) internal pure returns (uint128 liquidity) {
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
return toUint128(FullMath.mulDiv(amount1, FixedPoint96.Q96, sqrtRatioBX96 - sqrtRatioAX96));
}
/// @notice Computes the maximum amount of liquidity received for a given amount of token0, token1, the current
/// pool prices and the prices at the tick boundaries
/// @param sqrtRatioX96 A sqrt price representing the current pool prices
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary
/// @param amount0 The amount of token0 being sent in
/// @param amount1 The amount of token1 being sent in
/// @return liquidity The maximum amount of liquidity received
function getLiquidityForAmounts(
uint160 sqrtRatioX96,
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint256 amount0,
uint256 amount1
) internal pure returns (uint128 liquidity) {
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
if (sqrtRatioX96 <= sqrtRatioAX96) {
liquidity = getLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, amount0);
} else if (sqrtRatioX96 < sqrtRatioBX96) {
uint128 liquidity0 = getLiquidityForAmount0(sqrtRatioX96, sqrtRatioBX96, amount0);
uint128 liquidity1 = getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioX96, amount1);
liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1;
} else {
liquidity = getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1);
}
}
/// @notice Computes the amount of token0 for a given amount of liquidity and a price range
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary
/// @param liquidity The liquidity being valued
/// @return amount0 The amount of token0
function getAmount0ForLiquidity(
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint128 liquidity
) internal pure returns (uint256 amount0) {
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
return
FullMath.mulDiv(
uint256(liquidity) << FixedPoint96.RESOLUTION,
sqrtRatioBX96 - sqrtRatioAX96,
sqrtRatioBX96
) / sqrtRatioAX96;
}
/// @notice Computes the amount of token1 for a given amount of liquidity and a price range
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary
/// @param liquidity The liquidity being valued
/// @return amount1 The amount of token1
function getAmount1ForLiquidity(
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint128 liquidity
) internal pure returns (uint256 amount1) {
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
return FullMath.mulDiv(liquidity, sqrtRatioBX96 - sqrtRatioAX96, FixedPoint96.Q96);
}
/// @notice Computes the token0 and token1 value for a given amount of liquidity, the current
/// pool prices and the prices at the tick boundaries
/// @param sqrtRatioX96 A sqrt price representing the current pool prices
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary
/// @param liquidity The liquidity being valued
/// @return amount0 The amount of token0
/// @return amount1 The amount of token1
function getAmountsForLiquidity(
uint160 sqrtRatioX96,
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint128 liquidity
) internal pure returns (uint256 amount0, uint256 amount1) {
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
if (sqrtRatioX96 <= sqrtRatioAX96) {
amount0 = getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);
} else if (sqrtRatioX96 < sqrtRatioBX96) {
amount0 = getAmount0ForLiquidity(sqrtRatioX96, sqrtRatioBX96, liquidity);
amount1 = getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioX96, liquidity);
} else {
amount1 = getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);
}
}
}
/// @title Liquidity and ticks functions
/// @notice Provides functions for computing liquidity and ticks for token amounts and prices
library PoolVariables {
using LowGasSafeMath for uint256;
using LowGasSafeMath for uint128;
// Cache struct for calculations
struct Info {
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0;
uint256 amount1;
uint128 liquidity;
int24 tickLower;
int24 tickUpper;
}
/// @dev Wrapper around `LiquidityAmounts.getAmountsForLiquidity()`.
/// @param pool Uniswap V3 pool
/// @param liquidity The liquidity being valued
/// @param _tickLower The lower tick of the range
/// @param _tickUpper The upper tick of the range
/// @return amounts of token0 and token1 that corresponds to liquidity
function amountsForLiquidity(
IUniswapV3Pool pool,
uint128 liquidity,
int24 _tickLower,
int24 _tickUpper
) internal view returns (uint256, uint256) {
//Get current price from the pool
(uint160 sqrtRatioX96, , , , , , ) = pool.slot0();
return
LiquidityAmounts.getAmountsForLiquidity(
sqrtRatioX96,
TickMath.getSqrtRatioAtTick(_tickLower),
TickMath.getSqrtRatioAtTick(_tickUpper),
liquidity
);
}
/// @dev Wrapper around `LiquidityAmounts.getLiquidityForAmounts()`.
/// @param pool Uniswap V3 pool
/// @param amount0 The amount of token0
/// @param amount1 The amount of token1
/// @param _tickLower The lower tick of the range
/// @param _tickUpper The upper tick of the range
/// @return The maximum amount of liquidity that can be held amount0 and amount1
function liquidityForAmounts(
IUniswapV3Pool pool,
uint256 amount0,
uint256 amount1,
int24 _tickLower,
int24 _tickUpper
) internal view returns (uint128) {
//Get current price from the pool
(uint160 sqrtRatioX96, , , , , , ) = pool.slot0();
return
LiquidityAmounts.getLiquidityForAmounts(
sqrtRatioX96,
TickMath.getSqrtRatioAtTick(_tickLower),
TickMath.getSqrtRatioAtTick(_tickUpper),
amount0,
amount1
);
}
/// @dev Amounts of token0 and token1 held in contract position.
/// @param pool Uniswap V3 pool
/// @param _tickLower The lower tick of the range
/// @param _tickUpper The upper tick of the range
/// @return amount0 The amount of token0 held in position
/// @return amount1 The amount of token1 held in position
function usersAmounts(IUniswapV3Pool pool, int24 _tickLower, int24 _tickUpper)
internal
view
returns (uint256 amount0, uint256 amount1)
{
//Compute position key
bytes32 positionKey = PositionKey.compute(address(this), _tickLower, _tickUpper);
//Get Position.Info for specified ticks
(uint128 liquidity, , , uint128 tokensOwed0, uint128 tokensOwed1) =
pool.positions(positionKey);
// Calc amounts of token0 and token1 including fees
(amount0, amount1) = amountsForLiquidity(pool, liquidity, _tickLower, _tickUpper);
amount0 = amount0.add(tokensOwed0);
amount1 = amount1.add(tokensOwed1);
}
/// @dev Amount of liquidity in contract position.
/// @param pool Uniswap V3 pool
/// @param _tickLower The lower tick of the range
/// @param _tickUpper The upper tick of the range
/// @return liquidity stored in position
function positionLiquidity(IUniswapV3Pool pool, int24 _tickLower, int24 _tickUpper)
internal
view
returns (uint128 liquidity)
{
//Compute position key
bytes32 positionKey = PositionKey.compute(address(this), _tickLower, _tickUpper);
//Get liquidity stored in position
(liquidity, , , , ) = pool.positions(positionKey);
}
/// @dev Common checks for valid tick inputs.
/// @param tickLower The lower tick of the range
/// @param tickUpper The upper tick of the range
function checkRange(int24 tickLower, int24 tickUpper) internal pure {
require(tickLower < tickUpper, "TLU");
require(tickLower >= TickMath.MIN_TICK, "TLM");
require(tickUpper <= TickMath.MAX_TICK, "TUM");
}
/// @dev Rounds tick down towards negative infinity so that it's a multiple
/// of `tickSpacing`.
function floor(int24 tick, int24 tickSpacing) internal pure returns (int24) {
int24 compressed = tick / tickSpacing;
if (tick < 0 && tick % tickSpacing != 0) compressed--;
return compressed * tickSpacing;
}
/// @dev Gets ticks with proportion equivalent to desired amount
/// @param pool Uniswap V3 pool
/// @param amount0Desired The desired amount of token0
/// @param amount1Desired The desired amount of token1
/// @param baseThreshold The range for upper and lower ticks
/// @param tickSpacing The pool tick spacing
/// @return tickLower The lower tick of the range
/// @return tickUpper The upper tick of the range
function getPositionTicks(IUniswapV3Pool pool, uint256 amount0Desired, uint256 amount1Desired, int24 baseThreshold, int24 tickSpacing) internal view returns(int24 tickLower, int24 tickUpper) {
Info memory cache =
Info(amount0Desired, amount1Desired, 0, 0, 0, 0, 0);
// Get current price and tick from the pool
( uint160 sqrtPriceX96, int24 currentTick, , , , , ) = pool.slot0();
//Calc base ticks
(cache.tickLower, cache.tickUpper) = baseTicks(currentTick, baseThreshold, tickSpacing);
//Calc amounts of token0 and token1 that can be stored in base range
(cache.amount0, cache.amount1) = amountsForTicks(pool, cache.amount0Desired, cache.amount1Desired, cache.tickLower, cache.tickUpper);
//Liquidity that can be stored in base range
cache.liquidity = liquidityForAmounts(pool, cache.amount0, cache.amount1, cache.tickLower, cache.tickUpper);
//Get imbalanced token
bool zeroGreaterOne = amountsDirection(cache.amount0Desired, cache.amount1Desired, cache.amount0, cache.amount1);
//Calc new tick(upper or lower) for imbalanced token
if ( zeroGreaterOne) {
uint160 nextSqrtPrice0 = SqrtPriceMath.getNextSqrtPriceFromAmount0RoundingUp(sqrtPriceX96, cache.liquidity, cache.amount0Desired, false);
cache.tickUpper = PoolVariables.floor(TickMath.getTickAtSqrtRatio(nextSqrtPrice0), tickSpacing);
}
else{
uint160 nextSqrtPrice1 = SqrtPriceMath.getNextSqrtPriceFromAmount1RoundingDown(sqrtPriceX96, cache.liquidity, cache.amount1Desired, false);
cache.tickLower = PoolVariables.floor(TickMath.getTickAtSqrtRatio(nextSqrtPrice1), tickSpacing);
}
checkRange(cache.tickLower, cache.tickUpper);
tickLower = cache.tickLower;
tickUpper = cache.tickUpper;
}
/// @dev Gets amounts of token0 and token1 that can be stored in range of upper and lower ticks
/// @param pool Uniswap V3 pool
/// @param amount0Desired The desired amount of token0
/// @param amount1Desired The desired amount of token1
/// @param _tickLower The lower tick of the range
/// @param _tickUpper The upper tick of the range
/// @return amount0 amounts of token0 that can be stored in range
/// @return amount1 amounts of token1 that can be stored in range
function amountsForTicks(IUniswapV3Pool pool, uint256 amount0Desired, uint256 amount1Desired, int24 _tickLower, int24 _tickUpper) internal view returns(uint256 amount0, uint256 amount1) {
uint128 liquidity = liquidityForAmounts(pool, amount0Desired, amount1Desired, _tickLower, _tickUpper);
(amount0, amount1) = amountsForLiquidity(pool, liquidity, _tickLower, _tickUpper);
}
/// @dev Calc base ticks depending on base threshold and tickspacing
function baseTicks(int24 currentTick, int24 baseThreshold, int24 tickSpacing) internal pure returns(int24 tickLower, int24 tickUpper) {
int24 tickFloor = floor(currentTick, tickSpacing);
tickLower = tickFloor - baseThreshold;
tickUpper = tickFloor + baseThreshold;
}
/// @dev Get imbalanced token
/// @param amount0Desired The desired amount of token0
/// @param amount1Desired The desired amount of token1
/// @param amount0 Amounts of token0 that can be stored in base range
/// @param amount1 Amounts of token1 that can be stored in base range
/// @return zeroGreaterOne true if token0 is imbalanced. False if token1 is imbalanced
function amountsDirection(uint256 amount0Desired, uint256 amount1Desired, uint256 amount0, uint256 amount1) internal pure returns (bool zeroGreaterOne) {
zeroGreaterOne = amount0Desired.sub(amount0).mul(amount1Desired) > amount1Desired.sub(amount1).mul(amount0Desired) ? true : false;
}
// Check price has not moved a lot recently. This mitigates price
// manipulation during rebalance and also prevents placing orders
// when it's too volatile.
function checkDeviation(IUniswapV3Pool pool, int24 maxTwapDeviation, uint32 twapDuration) internal view {
(, int24 currentTick, , , , , ) = pool.slot0();
int24 twap = getTwap(pool, twapDuration);
int24 deviation = currentTick > twap ? currentTick - twap : twap - currentTick;
require(deviation <= maxTwapDeviation, "PSC");
}
/// @dev Fetches time-weighted average price in ticks from Uniswap pool for specified duration
function getTwap(IUniswapV3Pool pool, uint32 twapDuration) internal view returns (int24) {
uint32 _twapDuration = twapDuration;
uint32[] memory secondsAgo = new uint32[](2);
secondsAgo[0] = _twapDuration;
secondsAgo[1] = 0;
(int56[] memory tickCumulatives, ) = pool.observe(secondsAgo);
return int24((tickCumulatives[1] - tickCumulatives[0]) / _twapDuration);
}
}
/// @title Permissionless pool actions
/// @notice Contains pool methods that can be called by anyone
interface IUniswapV3PoolActions {
/// @notice Adds liquidity for the given recipient/tickLower/tickUpper position
/// @dev The caller of this method receives a callback in the form of IUniswapV3MintCallback#uniswapV3MintCallback
/// in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends
/// on tickLower, tickUpper, the amount of liquidity, and the current price.
/// @param recipient The address for which the liquidity will be created
/// @param tickLower The lower tick of the position in which to add liquidity
/// @param tickUpper The upper tick of the position in which to add liquidity
/// @param amount The amount of liquidity to mint
/// @param data Any data that should be passed through to the callback
/// @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback
/// @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback
function mint(
address recipient,
int24 tickLower,
int24 tickUpper,
uint128 amount,
bytes calldata data
) external returns (uint256 amount0, uint256 amount1);
/// @notice Collects tokens owed to a position
/// @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity.
/// Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or
/// amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the
/// actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity.
/// @param recipient The address which should receive the fees collected
/// @param tickLower The lower tick of the position for which to collect fees
/// @param tickUpper The upper tick of the position for which to collect fees
/// @param amount0Requested How much token0 should be withdrawn from the fees owed
/// @param amount1Requested How much token1 should be withdrawn from the fees owed
/// @return amount0 The amount of fees collected in token0
/// @return amount1 The amount of fees collected in token1
function collect(
address recipient,
int24 tickLower,
int24 tickUpper,
uint128 amount0Requested,
uint128 amount1Requested
) external returns (uint128 amount0, uint128 amount1);
/// @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position
/// @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0
/// @dev Fees must be collected separately via a call to #collect
/// @param tickLower The lower tick of the position for which to burn liquidity
/// @param tickUpper The upper tick of the position for which to burn liquidity
/// @param amount How much liquidity to burn
/// @return amount0 The amount of token0 sent to the recipient
/// @return amount1 The amount of token1 sent to the recipient
function burn(
int24 tickLower,
int24 tickUpper,
uint128 amount
) external returns (uint256 amount0, uint256 amount1);
/// @notice Swap token0 for token1, or token1 for token0
/// @dev The caller of this method receives a callback in the form of IUniswapV3SwapCallback#uniswapV3SwapCallback
/// @param recipient The address to receive the output of the swap
/// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0
/// @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
/// @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this
/// value after the swap. If one for zero, the price cannot be greater than this value after the swap
/// @param data Any data to be passed through to the callback
/// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive
/// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive
function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96,
bytes calldata data
) external returns (int256 amount0, int256 amount1);
}
/// @title Pool state that is not stored
/// @notice Contains view functions to provide information about the pool that is computed rather than stored on the
/// blockchain. The functions here may have variable gas costs.
interface IUniswapV3PoolDerivedState {
/// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp
/// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing
/// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick,
/// you must call it with secondsAgos = [3600, 0].
/// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in
/// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio.
/// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned
/// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp
/// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block
/// timestamp
function observe(uint32[] calldata secondsAgos)
external
view
returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s);
}
/// @title Pool state that can change
/// @notice These methods compose the pool's state, and can change with any frequency including multiple times
/// per transaction
interface IUniswapV3PoolState {
/// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas
/// when accessed externally.
/// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value
/// tick The current tick of the pool, i.e. according to the last tick transition that was run.
/// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick
/// boundary.
/// observationIndex The index of the last oracle observation that was written,
/// observationCardinality The current maximum number of observations stored in the pool,
/// observationCardinalityNext The next maximum number of observations, to be updated when the observation.
/// feeProtocol The protocol fee for both tokens of the pool.
/// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0
/// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee.
/// unlocked Whether the pool is currently locked to reentrancy
function slot0()
external
view
returns (
uint160 sqrtPriceX96,
int24 tick,
uint16 observationIndex,
uint16 observationCardinality,
uint16 observationCardinalityNext,
uint8 feeProtocol,
bool unlocked
);
/// @notice Returns the information about a position by the position's key
/// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper
/// @return _liquidity The amount of liquidity in the position,
/// Returns feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke,
/// Returns feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke,
/// Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke,
/// Returns tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke
function positions(bytes32 key)
external
view
returns (
uint128 _liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
uint128 tokensOwed0,
uint128 tokensOwed1
);
}
/// @title Pool state that never changes
/// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values
interface IUniswapV3PoolImmutables {
/// @notice The first of the two tokens of the pool, sorted by address
/// @return The token contract address
function token0() external view returns (address);
/// @notice The second of the two tokens of the pool, sorted by address
/// @return The token contract address
function token1() external view returns (address);
/// @notice The pool tick spacing
/// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive
/// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ...
/// This value is an int24 to avoid casting even though it is always positive.
/// @return The tick spacing
function tickSpacing() external view returns (int24);
}
/// @title The interface for a Uniswap V3 Pool
/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform
/// to the ERC20 specification
/// @dev The pool interface is broken up into many smaller pieces
interface IUniswapV3Pool is
IUniswapV3PoolImmutables,
IUniswapV3PoolState,
IUniswapV3PoolDerivedState,
IUniswapV3PoolActions
{
}
/// @title This library is created to conduct a variety of burn liquidity methods
library PoolActions {
using PoolVariables for IUniswapV3Pool;
using LowGasSafeMath for uint256;
using SafeCast for uint256;
/**
* @notice Withdraws liquidity in share proportion to the Optimizer's totalSupply.
* @param pool Uniswap V3 pool
* @param tickLower The lower tick of the range
* @param tickUpper The upper tick of the range
* @param totalSupply The amount of total shares in existence
* @param share to burn
* @param to Recipient of amounts
* @return amount0 Amount of token0 withdrawed
* @return amount1 Amount of token1 withdrawed
*/
function burnLiquidityShare(
IUniswapV3Pool pool,
int24 tickLower,
int24 tickUpper,
uint256 totalSupply,
uint256 share,
address to
) internal returns (uint256 amount0, uint256 amount1) {
require(totalSupply > 0, "TS");
uint128 liquidityInPool = pool.positionLiquidity(tickLower, tickUpper);
uint256 liquidity = uint256(liquidityInPool).mul(share) / totalSupply;
if (liquidity > 0) {
(amount0, amount1) = pool.burn(tickLower, tickUpper, liquidity.toUint128());
if (amount0 > 0 || amount1 > 0) {
// collect liquidity share
(amount0, amount1) = pool.collect(
to,
tickLower,
tickUpper,
amount0.toUint128(),
amount1.toUint128()
);
}
}
}
/**
* @notice Withdraws all liquidity in a range from Uniswap pool
* @param pool Uniswap V3 pool
* @param tickLower The lower tick of the range
* @param tickUpper The upper tick of the range
*/
function burnAllLiquidity(
IUniswapV3Pool pool,
int24 tickLower,
int24 tickUpper
) internal {
// Burn all liquidity in this range
uint128 liquidity = pool.positionLiquidity(tickLower, tickUpper);
if (liquidity > 0) {
pool.burn(tickLower, tickUpper, liquidity);
}
// Collect all owed tokens
pool.collect(
address(this),
tickLower,
tickUpper,
type(uint128).max,
type(uint128).max
);
}
}
/**
* @title Counters
* @author Matt Condon (@shrugs)
* @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number
* of elements in a mapping, issuing ERC721 ids, or counting request ids.
*
* Include with `using Counters for Counters.Counter;`
* Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {LowGasSafeMAth}
* overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never
* directly accessed.
*/
library Counters {
using LowGasSafeMath for uint256;
struct Counter {
// This variable should never be directly accessed by users of the library: interactions must be restricted to
// the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
// this feature: see https://github.com/ethereum/solidity/issues/4637
uint256 _value; // default: 0
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
// The {LowGasSafeMath} overflow check can be skipped here, see the comment at the top
counter._value += 1;
}
}
/// @title Function for getting the current chain ID
library ChainId {
/// @dev Gets the current chain ID
/// @return chainId The current chain ID
function get() internal pure returns (uint256 chainId) {
assembly {
chainId := chainid()
}
}
}
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "ISS");
require(v == 27 || v == 28, "ISV");
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
require(signer != address(0), "IS");
return signer;
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
* thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
* they need in their contracts using a combination of `abi.encode` and `keccak256`.
*
* Th...
// [truncated — 113646 bytes total]
Read Contract
DOMAIN_SEPARATOR 0x3644e515 → bytes32
allowance 0xdd62ed3e → uint256
balanceOf 0x70a08231 → uint256
decimals 0x313ce567 → uint8
governance 0x5aa6e675 → address
initialized 0x158ef93e → bool
isOperator 0x6d70f7ae → bool
name 0x06fdde03 → string
nonces 0x7ecebe00 → uint256
pendingGovernance 0xf39c38a0 → address
pool 0x16f0115b → address
position 0x09218e91 → uint128, uint256, uint256, uint128, uint128
protocolFees0 0x47d792c5 → uint256
protocolFees1 0x6a2a507b → uint256
strategy 0xa8c62e76 → address
symbol 0x95d89b41 → string
tickLower 0x59c4f905 → int24
tickSpacing 0xd0c93a7c → int24
tickUpper 0x55b812a8 → int24
token0 0x0dfe1681 → address
token1 0xd21220a7 → address
totalFees0 0x80814ffb → uint256
totalFees1 0xef095f8d → uint256
totalSupply 0x18160ddd → uint256
usersAmounts 0xda486721 → uint256, uint256
Write Contract 21 functions
These functions modify contract state and require a wallet transaction to execute.
acceptGovernance 0x238efcbc
No parameters
approve 0x095ea7b3
address spender
uint256 amount
returns: bool
approveOperator 0x242cae9f
address _operator
collectProtocolFees 0x14c04c4f
uint256 amount0
uint256 amount1
decreaseAllowance 0xa457c2d7
address spender
uint256 subtractedValue
returns: bool
deposit 0x8dbdbe6d
uint256 amount0Desired
uint256 amount1Desired
address to
returns: uint256, uint256, uint256
disableOperator 0xf56408ed
address _operator
increaseAllowance 0x39509351
address spender
uint256 addedValue
returns: bool
init 0xe1c7392a
No parameters
pause 0x8456cb59
No parameters
permit 0xd505accf
address owner
address spender
uint256 value
uint256 deadline
uint8 v
bytes32 r
bytes32 s
rebalance 0x7d7c2a1c
No parameters
rerange 0xeb3221b4
No parameters
setGovernance 0xab033ea9
address _governance
setStrategy 0x33a100ca
address _strategy
transfer 0xa9059cbb
address recipient
uint256 amount
returns: bool
transferFrom 0x23b872dd
address sender
address recipient
uint256 amount
returns: bool
uniswapV3MintCallback 0xd3487997
uint256 amount0
uint256 amount1
bytes data
uniswapV3SwapCallback 0xfa461e33
int256 amount0
int256 amount1
bytes _data
unpause 0x3f4ba83a
No parameters
withdraw 0x00f714ce
uint256 shares
address to
returns: uint256, uint256
Token Balances (1) $3,222.16
View Transfers →| Token | Balance | Price | Value |
|---|---|---|---|
| WETH | 1.6355 | $1,970.14 | $3,222.16 |
Recent Transactions
This address has 1 on-chain transactions, but only 1.5% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →