diff --git a/.gitleaksignore b/.gitleaksignore index ecaf64d8..d8e0189d 100644 --- a/.gitleaksignore +++ b/.gitleaksignore @@ -135,4 +135,58 @@ f78d4539c80abb33ea04dce4d561af5302033235:scripts/deployment/staking/globals_sepo 9fa4b1fb81ba553ed48ef4a9b22c53ecdf4d2242:scripts/deployment/staking/globals_sepolia.json:generic-api-key:1 9fa4b1fb81ba553ed48ef4a9b22c53ecdf4d2242:scripts/deployment/staking/globals_sepolia.json:generic-api-key:2 001d71fc7c216c593faebdd3d6f353efaf80605f:scripts/deployment/staking/globals_sepolia.json:generic-api-key:1 -001d71fc7c216c593faebdd3d6f353efaf80605f:scripts/deployment/staking/globals_sepolia.json:generic-api-key:2 \ No newline at end of file +001d71fc7c216c593faebdd3d6f353efaf80605f:scripts/deployment/staking/globals_sepolia.json:generic-api-key:2 +ea6713128995ac18f3911c0214163e2b82896a7f:scripts/deployment/globals_mainnet.json:generic-api-key:1 +ea6713128995ac18f3911c0214163e2b82896a7f:scripts/deployment/globals_mainnet.json:generic-api-key:2 +1a7a855a853d2bc21e1e9178754a22dae54439f3:scripts/deployment/staking/globals_mainnet.json:generic-api-key:1 +1a7a855a853d2bc21e1e9178754a22dae54439f3:scripts/deployment/staking/globals_mainnet.json:generic-api-key:2 +3c5c0643bfa60605d7b91eb4b7a4b80c6f7a1b43:scripts/deployment/staking/globals_mainnet.json:generic-api-key:1 +3c5c0643bfa60605d7b91eb4b7a4b80c6f7a1b43:scripts/deployment/staking/globals_mainnet.json:generic-api-key:2 +b17bdd0ebae90b769b8756da81d831a70fcb4af3:scripts/deployment/globals_mainnet.json:generic-api-key:1 +b17bdd0ebae90b769b8756da81d831a70fcb4af3:scripts/deployment/staking/globals_mainnet.json:generic-api-key:1 +b17bdd0ebae90b769b8756da81d831a70fcb4af3:scripts/deployment/globals_mainnet.json:generic-api-key:2 +b17bdd0ebae90b769b8756da81d831a70fcb4af3:scripts/deployment/staking/globals_mainnet.json:generic-api-key:2 +c5ba11d1b46a6fa9644c0de28b4b0f7b154156ee:scripts/deployment/globals_mainnet.json:generic-api-key:1 +c5ba11d1b46a6fa9644c0de28b4b0f7b154156ee:scripts/deployment/globals_mainnet.json:generic-api-key:2 +c5ba11d1b46a6fa9644c0de28b4b0f7b154156ee:scripts/deployment/staking/globals_mainnet.json:generic-api-key:1 +c5ba11d1b46a6fa9644c0de28b4b0f7b154156ee:scripts/deployment/staking/globals_mainnet.json:generic-api-key:2 +7cf3cd1c5fa705f82f0f33c90538fa6e6892af5b:scripts/deployment/globals_mainnet.json:generic-api-key:1 +7cf3cd1c5fa705f82f0f33c90538fa6e6892af5b:scripts/deployment/staking/globals_mainnet.json:generic-api-key:1 +7cf3cd1c5fa705f82f0f33c90538fa6e6892af5b:scripts/deployment/globals_mainnet.json:generic-api-key:2 +7cf3cd1c5fa705f82f0f33c90538fa6e6892af5b:scripts/deployment/staking/globals_mainnet.json:generic-api-key:2 +38ff93e8e51ef86b6c46872b12e27f67152ec07a:scripts/deployment/staking/wormhole/test/globals_celo_mainnet.json:generic-api-key:1 +38ff93e8e51ef86b6c46872b12e27f67152ec07a:scripts/deployment/staking/wormhole/test/globals_celo_mainnet.json:generic-api-key:2 +38ff93e8e51ef86b6c46872b12e27f67152ec07a:scripts/deployment/staking/wormhole/globals_celo_mainnet.json:generic-api-key:1 +38ff93e8e51ef86b6c46872b12e27f67152ec07a:scripts/deployment/staking/wormhole/globals_celo_mainnet.json:generic-api-key:2 +cfe4b8064bfda91d83bd5bdc5af44f2155859ef3:scripts/deployment/staking/wormhole/test/globals_celo_mainnet.json:generic-api-key:1 +cfe4b8064bfda91d83bd5bdc5af44f2155859ef3:scripts/deployment/staking/wormhole/test/globals_celo_mainnet.json:generic-api-key:2 +cfe4b8064bfda91d83bd5bdc5af44f2155859ef3:scripts/deployment/staking/wormhole/globals_celo_mainnet.json:generic-api-key:1 +cfe4b8064bfda91d83bd5bdc5af44f2155859ef3:scripts/deployment/staking/wormhole/globals_celo_mainnet.json:generic-api-key:2 +e09cdb5c34a402545d5a67d65ea31760f7c0fd19:scripts/deployment/globals_mainnet.json:generic-api-key:1 +e09cdb5c34a402545d5a67d65ea31760f7c0fd19:scripts/deployment/globals_mainnet.json:generic-api-key:2 +02f626605f59ee89a44152d2d8723c848174e44:scripts/deployment/staking/globals_sepolia.json:generic-api-key:2 +f02f626605f59ee89a44152d2d8723c848174e44:scripts/deployment/globals_mainnet.json:generic-api-key:2 +a1fb94f332608c58c44aed99a08fea5fb08fc6ed:scripts/deployment/staking/globals_mainnet.json:generic-api-key:1 +b92c814bbbab19139c4d40d31f7d0394e2796d0f:scripts/deployment/staking/celo/globals_celo_mainnet.json:generic-api-key:1 +d3c5ea3ef6d62f5cfb51d2485b74133f84d40f7d:scripts/deployment/staking/globals_mainnet.json:generic-api-key:1 +d79d6210c89d103448e32b7c915903c8a8b8d87a:scripts/deployment/staking/celo/globals_celo_mainnet.json:generic-api-key:1 +d79d6210c89d103448e32b7c915903c8a8b8d87a:scripts/deployment/staking/globals_mainnet.json:generic-api-key:1 +e9945cd0dd6c8c0dc0fefda76d7f60e7ef56511b:scripts/deployment/globals_mainnet.json:generic-api-key:1 +e9945cd0dd6c8c0dc0fefda76d7f60e7ef56511b:scripts/deployment/staking/celo/globals_celo_mainnet.json:generic-api-key:1 +e9945cd0dd6c8c0dc0fefda76d7f60e7ef56511b:scripts/deployment/staking/globals_mainnet.json:generic-api-key:1 +e9945cd0dd6c8c0dc0fefda76d7f60e7ef56511b:scripts/deployment/staking/globals_sepolia.json:generic-api-key:1 +a1fb94f332608c58c44aed99a08fea5fb08fc6ed:scripts/deployment/staking/globals_mainnet.json:generic-api-key:2 +b92c814bbbab19139c4d40d31f7d0394e2796d0f:scripts/deployment/staking/celo/globals_celo_mainnet.json:generic-api-key:2 +d3c5ea3ef6d62f5cfb51d2485b74133f84d40f7d:scripts/deployment/staking/globals_mainnet.json:generic-api-key:2 +d79d6210c89d103448e32b7c915903c8a8b8d87a:scripts/deployment/staking/celo/globals_celo_mainnet.json:generic-api-key:2 +d79d6210c89d103448e32b7c915903c8a8b8d87a:scripts/deployment/staking/globals_mainnet.json:generic-api-key:2 +e9945cd0dd6c8c0dc0fefda76d7f60e7ef56511b:scripts/deployment/globals_mainnet.json:generic-api-key:2 +e9945cd0dd6c8c0dc0fefda76d7f60e7ef56511b:scripts/deployment/staking/celo/globals_celo_mainnet.json:generic-api-key:2 +e9945cd0dd6c8c0dc0fefda76d7f60e7ef56511b:scripts/deployment/staking/globals_mainnet.json:generic-api-key:2 +e9945cd0dd6c8c0dc0fefda76d7f60e7ef56511b:scripts/deployment/staking/globals_sepolia.json:generic-api-key:2 +3068b0eefad400612f18c193fa62e11974c0fbd5:scripts/deployment/staking/celo/globals_celo_mainnet.json:generic-api-key:1 +3068b0eefad400612f18c193fa62e11974c0fbd5:scripts/deployment/staking/celo/globals_celo_mainnet.json:generic-api-key:2 +b616524545db2768fb9a3772ffd05c6e0a7f2d8b:scripts/deployment/staking/celo/globals_celo_mainnet.json:generic-api-key:1 +b616524545db2768fb9a3772ffd05c6e0a7f2d8b:scripts/deployment/staking/celo/globals_celo_mainnet.json:generic-api-key:2 +5e43d545806f8e2d6e8ffd8190d7d704bf663d5f:scripts/deployment/staking/celo/globals_celo_mainnet.json:generic-api-key:1 +5e43d545806f8e2d6e8ffd8190d7d704bf663d5f:scripts/deployment/staking/celo/globals_celo_mainnet.json:generic-api-key:2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 259faf48..2913eb37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,21 @@ All notable changes to this project will be documented in this file. The format is based on [Common Changelog](https://common-changelog.org). +[1.2.2]: https://github.com/valory-xyz/autonolas-tokenomics/compare/v1.0.3...v1.2.2 [1.0.3]: https://github.com/valory-xyz/autonolas-tokenomics/compare/v1.0.2...v1.0.3 [1.0.2]: https://github.com/valory-xyz/autonolas-tokenomics/compare/v1.0.1...v1.0.2 [1.0.1]: https://github.com/valory-xyz/autonolas-tokenomics/compare/v1.0.0...v1.0.1 [1.0.0]: https://github.com/valory-xyz/autonolas-tokenomics/releases/tag/v1.0.0 +## [1.2.2] - 2024-07-29 + +### Changed + +- Introducing Service Staking according to [PoAA Whitepaper](https://staking.olas.network/poaa-whitepaper.pdf) +- Refactored and re-deployed `Tokenomics.sol` and `Dispenser.sol` to address service staking inflation and claiming capability ([#156](https://github.com/valory-xyz/autonolas-registries/pull/156)), with the subsequent internal audit ([#168](https://github.com/valory-xyz/autonolas-registries/pull/168)) +- Created and deployed `ArbitrumDepositProcessorL1.sol`, `ArbitrumTargetDispenserL2.sol`, `DefaultDepositProcessorL1.sol`, `DefaultTargetDispenserL2.sol`, `EthereumDepositProcessor.sol`, `GnosisDepositProcessorL1.sol` , `GnosisTargetDispenserL2.sol`, `OptimismDepositProcessorL1.sol`, `OptimismTargetDispenserL2.sol`, `PolygonDepositProcessorL1.sol`, `PolygonTargetDispenserL2.sol`, `WormholeDepositProcessorL1.sol`, and `WormholeTargetDispenserL2.sol` contracts +- Participated in a complete [C4R audit competition](https://github.com/code-423n4/2024-05-olas-findings) and addressed findings + ## [1.0.3] - 2023-10-05 _No bytecode changes_. diff --git a/abis/0.8.25/Dispenser.json b/abis/0.8.25/Dispenser.json index 7088a562..475842a3 100644 --- a/abis/0.8.25/Dispenser.json +++ b/abis/0.8.25/Dispenser.json @@ -213,6 +213,19 @@ "name": "ZeroValue", "type": "error" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "nomineeHash", + "type": "bytes32" + } + ], + "name": "AddNomineeHash", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -233,6 +246,18 @@ "internalType": "uint256", "name": "topUp", "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "unitTypes", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "unitIds", + "type": "uint256[]" } ], "name": "IncentivesClaimed", @@ -264,6 +289,19 @@ "name": "PauseDispenser", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "nomineeHash", + "type": "bytes32" + } + ], + "name": "RemoveNomineeHash", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -311,6 +349,67 @@ "name": "account", "type": "address" }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "chainIds", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "bytes32[][]", + "name": "stakingTargets", + "type": "bytes32[][]" + }, + { + "indexed": false, + "internalType": "uint256[][]", + "name": "stakingIncentives", + "type": "uint256[][]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "totalStakingIncentive", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "totalTransferAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "totalReturnAmount", + "type": "uint256" + } + ], + "name": "StakingIncentivesBatchClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "stakingTarget", + "type": "bytes32" + }, { "indexed": false, "internalType": "uint256", @@ -990,8 +1089,8 @@ "type": "function" } ], - "bytecode": "0x610120604052348015610010575f80fd5b50604051614b01380380614b0183398101604081905261002f91610226565b6002805460ff60a01b1933166001600160a81b031990911617600160a01b1760ff60a81b1916600160a91b1790556001600160a01b038916158061007a57506001600160a01b038816155b8061008c57506001600160a01b038716155b8061009e57506001600160a01b038616155b806100a7575084155b156100c55760405163d92e233d60e01b815260040160405180910390fd5b8315806100d0575082155b806100d9575081155b806100e2575080155b1561010057604051637c946ed760e01b815260040160405180910390fd5b61ffff82111561013357604051637ae5968560e01b81526004810183905261ffff60248201526044015b60405180910390fd5b6001600160601b0381111561016b57604051637ae5968560e01b8152600481018290526001600160601b03602482015260440161012a565b6001600160a01b0398891660c05260038054988a166001600160a01b0319998a1617905560048054978a16978916979097179096556005805495909816949096169390931790955560e0819052604080518082018252828152466020918201908152825180830194909452518383015281518084038301815260609093019091528151910120610100525f9390935560019290925560805260a0526102a5565b80516001600160a01b0381168114610221575f80fd5b919050565b5f805f805f805f805f6101208a8c03121561023f575f80fd5b6102488a61020b565b985061025660208b0161020b565b975061026460408b0161020b565b965061027260608b0161020b565b955060808a0151945060a08a0151935060c08a0151925060e08a015191506101008a015190509295985092959850929598565b60805160a05160c05160e0516101005161479361036e5f395f81816103450152818161141401528181611cf50152611d9c01525f8181610671015281816114470152818161169b015281816116cf01528181611d2c01528181611ec60152818161318e01526131f401525f81816101ef015281816109c201528181610ac901528181610e4901528181610f98015281816126a3015281816127b001528181612ae4015261354c01525f818161063e01526118a401525f818161029c015261187001526147935ff3fe6080604052600436106101da575f3560e01c806379bc81dd116100fd578063bc7d5c5c11610092578063dcb5ccc411610062578063dcb5ccc4146105f9578063e09177781461062d578063e6be59e714610660578063f4da12ba14610693575f80fd5b8063bc7d5c5c14610568578063d529779314610587578063d7accbcc146105a6578063d8bf69bf146105da575f80fd5b80639649a35c116100cd5780639649a35c146104eb578063a5edd4fc146104ff578063a6f9dae11461051e578063bb78678f1461053d575f80fd5b806379bc81dd1461046e5780638513e77d1461048d5780638833c205146104b85780638da5cb5b146104cc575f80fd5b80633c18d1dd1161017357806361d027b31161014357806361d027b3146103d257806363096509146103f157806363c4d28e14610410578063777e49c91461042f575f80fd5b80633c18d1dd146103345780634ac7251d146103675780635a55a482146103865780635c975abb146103a5575f80fd5b80632ad923dc116101ae5780632ad923dc146102cc5780632c0f3f29146102f757806334be5af41461030c5780633907196c14610321575f80fd5b806231d115146101de5780630d17db111461022e5780630d3241ee1461026c5780632a3bb6931461028b575b5f80fd5b3480156101e9575f80fd5b506102117f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610239575f80fd5b5061025c610248366004613c36565b600a6020525f908152604090205460ff1681565b6040519015158152602001610225565b348015610277575f80fd5b50600554610211906001600160a01b031681565b348015610296575f80fd5b506102be7f000000000000000000000000000000000000000000000000000000000000000081565b604051908152602001610225565b3480156102d7575f80fd5b506102be6102e6366004613c36565b60066020525f908152604090205481565b61030a610305366004613cfe565b6106a7565b005b348015610317575f80fd5b506102be60015481565b61030a61032f366004613e5e565b610be6565b34801561033f575f80fd5b506102be7f000000000000000000000000000000000000000000000000000000000000000081565b348015610372575f80fd5b50600354610211906001600160a01b031681565b348015610391575f80fd5b5061030a6103a0366004613fde565b611148565b3480156103b0575f80fd5b506002546103c590600160a81b900460ff1681565b604051610225919061401b565b3480156103dd575f80fd5b50600454610211906001600160a01b031681565b3480156103fc575f80fd5b5061030a61040b366004614041565b611312565b34801561041b575f80fd5b5061030a61042a366004613c36565b6113d1565b34801561043a575f80fd5b5061044e610449366004614066565b611654565b604080519485526020850193909352918301526060820152608001610225565b348015610479575f80fd5b5061030a610488366004613fde565b611b99565b348015610498575f80fd5b506102be6104a7366004613c36565b60076020525f908152604090205481565b3480156104c3575f80fd5b506102be5f5481565b3480156104d7575f80fd5b50600254610211906001600160a01b031681565b3480156104f6575f80fd5b5061030a611ca8565b34801561050a575f80fd5b5061030a610519366004613c36565b61204a565b348015610529575f80fd5b5061030a6105383660046140b0565b6121ed565b348015610548575f80fd5b506102be610557366004613c36565b60096020525f908152604090205481565b348015610573575f80fd5b5061030a6105823660046140c9565b6122aa565b348015610592575f80fd5b5061030a6105a13660046140e9565b61235a565b3480156105b1575f80fd5b506105c56105c0366004614129565b6124c8565b60408051928352602083019190915201610225565b3480156105e5575f80fd5b5061030a6105f4366004614189565b6128f9565b348015610604575f80fd5b50610211610613366004613c36565b60086020525f90815260409020546001600160a01b031681565b348015610638575f80fd5b506102be7f000000000000000000000000000000000000000000000000000000000000000081565b34801561066b575f80fd5b506102be7f000000000000000000000000000000000000000000000000000000000000000081565b34801561069e575f80fd5b506102be612a5c565b6002546001600160a01b90910460ff1611156106d6576040516345f5ce8b60e11b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790555f83900361070a57604051637c946ed760e01b815260040160405180910390fd5b5f82900361072b5760405163d92e233d60e01b815260040160405180910390fd5b5f548085111561075d57604051637ae5968560e01b815260048101869052602481018290526044015b60405180910390fd5b60028054600160a81b900460ff169081600381111561077e5761077e614007565b148061079b5750600381600381111561079957610799614007565b145b8061081257506004805460408051635c975abb60e01b815290516001600160a01b0390921692635c975abb92828201926020929082900301815f875af11580156107e7573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061080b919061423c565b60ff166002145b15610830576040516313d0ff5960e31b815260040160405180910390fd5b5f8581526008602090815260408083205481517fa8b2ae0200000000000000000000000000000000000000000000000000000000815291516001600160a01b039091169392849263a8b2ae0292600480830193928290030181865afa15801561089b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108bf9190614255565b90505f805f806108d18c8c8c88611654565b5f81815260066020526040902082905592965090945092509050821561094b57600354604051635e148f0960e11b8152600481018590526001600160a01b039091169063bc291e12906024015f604051808303815f87803b158015610934575f80fd5b505af1158015610946573d5f803e3d5ffd5b505050505b5f8415610b8157505f8b815260096020526040902054849080156109a5578181106109845761097a8282614280565b90505f9150610994565b61098e8183614280565b91505f90505b5f8d81526009602052604090208190555b8115610b72576040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610a0f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a339190614255565b60048054604051637ff796ab60e01b815230928101929092525f6024830152604482018690529192506001600160a01b0390911690637ff796ab906064016020604051808303815f875af1158015610a8d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ab19190614299565b506040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610b16573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b3a9190614255565b610b449190614280565b9050828114610b705760405163312b003360e01b81526004810182905260248101849052604401610754565b505b610b7f8d8d888e86612a88565b505b604080518681526020810183905290810185905233907f02b21954a7bf2d6a171db9a87b430a3723605c554db00adcb95b26ce8464f2809060600160405180910390a250506002805460ff60a01b1916600160a01b1790555050505050505050505050565b6002546001600160a01b90910460ff161115610c15576040516345f5ce8b60e11b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b179055610c3484848484612c86565b5f5480861115610c6157604051637ae5968560e01b81526004810187905260248101829052604401610754565b60028054600160a81b900460ff1690816003811115610c8257610c82614007565b1480610c9f57506003816003811115610c9d57610c9d614007565b145b80610d1657506004805460408051635c975abb60e01b815290516001600160a01b0390921692635c975abb92828201926020929082900301815f875af1158015610ceb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d0f919061423c565b60ff166002145b15610d34576040516313d0ff5960e31b815260040160405180910390fd5b6060806060610d448a8a8a612f84565b825192955090935091505f9084906002908110610d6357610d636142b8565b60200260200101511115610def5760035483516001600160a01b039091169063bc291e129085906002908110610d9b57610d9b6142b8565b60200260200101516040518263ffffffff1660e01b8152600401610dc191815260200190565b5f604051808303815f87803b158015610dd8575f80fd5b505af1158015610dea573d5f803e3d5ffd5b505050505b5f835f81518110610e0257610e026142b8565b60200260200101511115611086575f83600181518110610e2457610e246142b8565b60200260200101511115611078576040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610e96573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610eba9190614255565b60045485519192506001600160a01b031690637ff796ab9030905f9088906001908110610ee957610ee96142b8565b60209081029190910101516040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b039093166004840152602483019190915260448201526064016020604051808303815f875af1158015610f5c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f809190614299565b506040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610fe5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110099190614255565b6110139190614280565b905083600181518110611028576110286142b8565b6020026020010151811461107657808460018151811061104a5761104a6142b8565b602002602001015160405163312b003360e01b8152600401610754929190918252602082015260400190565b505b6110868989848a858b6134de565b336001600160a01b03167f02b21954a7bf2d6a171db9a87b430a3723605c554db00adcb95b26ce8464f280845f815181106110c3576110c36142b8565b6020026020010151856001815181106110de576110de6142b8565b6020026020010151866002815181106110f9576110f96142b8565b6020026020010151604051611121939291909283526020830191909152604082015260600190565b60405180910390a250506002805460ff60a01b1916600160a01b1790555050505050505050565b6002546001600160a01b031633146111885760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b821580611193575081155b8061119c575080155b156111ba57604051637c946ed760e01b815260040160405180910390fd5b4683036111dd57604051633881b68960e01b815260048101849052602401610754565b5f838152600960205260408120546111f69084906142cc565b90506bffffffffffffffffffffffff81111561123a57604051637ae5968560e01b8152600481018290526bffffffffffffffffffffffff6024820152604401610754565b5f8481526009602090815260408083208490556008909152908190205490517fac65ded2000000000000000000000000000000000000000000000000000000008152600481018490526001600160a01b0390911690819063ac65ded2906024015f604051808303815f87803b1580156112b1575f80fd5b505af11580156112c3573d5f803e3d5ffd5b505060408051888152602081018890529081018590528592507f2192822efd68ddf583804c65675b73a59694e672cab1758eb6714613f932a97591506060015b60405180910390a25050505050565b6002546001600160a01b031633146113525760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b600280548291907fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16600160a81b83600381111561139257611392614007565b02179055507fa814f27828c0243d429ea8c7033cb10f0c825b9466fdc04f63e0cca26c28eb8a816040516113c6919061401b565b60405180910390a150565b6005546001600160a01b031633146114115760055460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610754565b807f00000000000000000000000000000000000000000000000000000000000000000361147357604051636aba776560e11b81527f00000000000000000000000000000000000000000000000000000000000000006004820152602401610754565b600354604080517f14b19c5a00000000000000000000000000000000000000000000000000000000815290515f926001600160a01b0316916314b19c5a9160048083019260209291908290030181865afa1580156114d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114f791906142df565b60035463ffffffff9190911691505f906001600160a01b031663d4ee9f8d611520600185614280565b6040518263ffffffff1660e01b815260040161153e91815260200190565b602060405180830381865afa158015611559573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061157d9190614255565b90505f60035f9054906101000a90046001600160a01b03166001600160a01b031663d2b3996f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115d0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115f491906142df565b63ffffffff1690505f62093a8061160b83856142cc565b6116159190614280565b905080421061164057604051637ae5968560e01b815242600482015260248101829052604401610754565b5050505f9182526007602052604090912055565b5f805f80865f0361167857604051637c946ed760e01b815260040160405180910390fd5b5f8690036116995760405163d92e233d60e01b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000086036116fb57604051636aba776560e11b81527f00000000000000000000000000000000000000000000000000000000000000006004820152602401610754565b5060408051808201825286815260209081018881528251808301899052905181840152825180820384018152606090910190925281519101205f61173f828a613ae7565b6005546040516317d5e89d60e31b8152600481018b9052602481018c90529195509192506001600160a01b039091169063beaf44e8906044015f604051808303815f87803b15801561178f575f80fd5b505af11580156117a1573d5f803e3d5ffd5b5083925050505b83811015611b8c575f818152600a602052604090205460ff16611b8457600354604051631ddf133560e01b8152600481018390525f916001600160a01b031690631ddf133590602401608060405180830381865afa15801561180c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611830919061431d565b606081015190915060ff16156118cf57604081015161ffff16158015611866575060208101516bffffffffffffffffffffffff16155b156118ca5761ffff7f00000000000000000000000000000000000000000000000000000000000000001660408201526bffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660208201525b6118d5565b50611b84565b60035460405163d4ee9f8d60e01b8152600481018490525f916001600160a01b03169063d4ee9f8d90602401602060405180830381865afa15801561191c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119409190614255565b600554604051630c88d47f60e41b8152600481018d9052602481018e9052604481018390529192505f9182916001600160a01b03169063c88d47f0906064016040805180830381865afa158015611999573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119bd91906143a0565b91509150805f03611a05575f858152600a60205260409020805460ff1916600117905583516119fa906bffffffffffffffffffffffff168a6142cc565b985050505050611b84565b83515f9081906bffffffffffffffffffffffff168184821115611a3257611a2c8583614280565b90508491505b6040880151611a4b9061ffff16655af3107a40006143c2565b861015611a8157670de0b6b3a764000086611a6684846142cc565b611a7091906143c2565b611a7a91906143ed565b9250611b6f565b670de0b6b3a7640000611a9487846143c2565b611a9e91906143ed565b9350670de0b6b3a7640000611ab387836143c2565b611abd91906143ed565b925087602001516bffffffffffffffffffffffff16915081841115611af657611ae68285614280565b611af090846142cc565b92508193505b60128f1015611b62575f8f6012611b0d9190614280565b611b1890600a6144e0565b611b2290866143ed565b90508f6012611b319190614280565b611b3c90600a6144e0565b611b4690826143c2565b9050611b528186614280565b611b5c90856142cc565b90945092505b611b6c848f6142cc565b9d505b611b79838e6142cc565b9c5050505050505050505b6001016117a8565b5050945094509450949050565b5f838152600860205260409020546001600160a01b0316338114611bfa576040517fdeeeedec0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0382166024820152604401610754565b5f84815260096020526040812054611c139085906142cc565b90506bffffffffffffffffffffffff811115611c5757604051637ae5968560e01b8152600481018290526bffffffffffffffffffffffff6024820152604401610754565b5f85815260096020908152604091829020839055815187815290810186905290810182905283907f2192822efd68ddf583804c65675b73a59694e672cab1758eb6714613f932a97590606001611303565b6002546001600160a01b90910460ff161115611cd7576040516345f5ce8b60e11b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790555f80548190611d1a907f000000000000000000000000000000000000000000000000000000000000000090613ae7565b6005546040516317d5e89d60e31b81527f000000000000000000000000000000000000000000000000000000000000000060048201524660248201529294509092506001600160a01b03169063beaf44e8906044015f604051808303815f87803b158015611d86575f80fd5b505af1158015611d98573d5f803e3d5ffd5b50507f00000000000000000000000000000000000000000000000000000000000000005f90815260066020526040812084905591508390505b82811015611f8857600354604051631ddf133560e01b8152600481018390525f916001600160a01b031690631ddf133590602401608060405180830381865afa158015611e20573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e44919061431d565b60035460405163d4ee9f8d60e01b8152600481018590529192505f916001600160a01b039091169063d4ee9f8d90602401602060405180830381865afa158015611e90573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611eb49190614255565b600554604051630c88d47f60e41b81527f00000000000000000000000000000000000000000000000000000000000000006004820152466024820152604481018390529192505f916001600160a01b039091169063c88d47f0906064016040805180830381865afa158015611f2b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f4f91906143a0565b508351909150611f6e9082906bffffffffffffffffffffffff166143c2565b611f7890866142cc565b9450505050806001019050611dd1565b50611f9b670de0b6b3a7640000826143ed565b90508015611ffd57600354604051635e148f0960e11b8152600481018390526001600160a01b039091169063bc291e12906024015f604051808303815f87803b158015611fe6575f80fd5b505af1158015611ff8573d5f803e3d5ffd5b505050505b60405181815233907f2a8de497d698d6869cb0844411788378e76214d03a541eec6ba514b795d9f42e9060200160405180910390a250506002805460ff60a01b1916600160a01b17905550565b6005546001600160a01b0316331461208a5760055460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610754565b60028054600160a81b900460ff16908160038111156120ab576120ab614007565b14806120c8575060038160038111156120c6576120c6614007565b145b8061213f57506004805460408051635c975abb60e01b815290516001600160a01b0390921692635c975abb92828201926020929082900301815f875af1158015612114573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612138919061423c565b60ff166002145b1561215d576040516313d0ff5960e31b815260040160405180910390fd5b60035f9054906101000a90046001600160a01b03166001600160a01b03166314b19c5a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121ad573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121d191906142df565b5f9283526006602052604090922063ffffffff90921690915550565b6002546001600160a01b0316331461222d5760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b6001600160a01b0381166122545760405163d92e233d60e01b815260040160405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f4ffd725fc4a22075e9ec71c59edf9c38cdeb588a91b24fc5b61388c5be41282b905f90a250565b6002546001600160a01b031633146122ea5760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b8115806122f5575080155b1561231357604051637c946ed760e01b815260040160405180910390fd5b5f829055600181905560408051838152602081018390527f61f6c4cc9665a257352c0b46189ffc2ae6fbbc11e155ff20901217ff203a517e91015b60405180910390a15050565b6002546001600160a01b0316331461239a5760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b6001600160a01b038316156123fd576003805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0385169081179091556040517f4672fe7e13cfb163442d0b729b5733fb3efafc66cbe3677eac9940eb41c284c2905f90a25b6001600160a01b03821615612460576004805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0384169081179091556040517f7dae230f18360d76a040c81f050aa14eb9d6dc7901b20fc5d855e2a20fe814d1905f90a25b6001600160a01b038116156124c3576005805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f04a606379838ed6fc83fd189eea9d1835b5eff05035c4b74622911ea2ae6b217905f90a25b505050565b5f806001600260149054906101000a900460ff1660ff1611156124fe576040516345f5ce8b60e11b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b179081905560ff600160a81b90910416600181600381111561253257612532614007565b148061254f5750600381600381111561254d5761254d614007565b145b806125c657506004805460408051635c975abb60e01b815290516001600160a01b0390921692635c975abb92828201926020929082900301815f875af115801561259b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125bf919061423c565b60ff166002145b156125e4576040516313d0ff5960e31b815260040160405180910390fd5b6003546040517f2e070f540000000000000000000000000000000000000000000000000000000081526001600160a01b0390911690632e070f549061263190339089908990600401614525565b60408051808303815f875af115801561264c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061267091906143a0565b90935091505f8061268184866142cc565b1115612859575f8315612717576040516370a0823160e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156126f0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127149190614255565b90505b60048054604051637ff796ab60e01b8152339281019290925260248201879052604482018690526001600160a01b031690637ff796ab906064016020604051808303815f875af115801561276d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127919190614299565b91508315612857576040516370a0823160e01b815233600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156127fd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128219190614255565b61282b9190614280565b90508381146128575760405163312b003360e01b81526004810182905260248101859052604401610754565b505b806128a0576040517f942dc9da0000000000000000000000000000000000000000000000000000000081523360048201526024810185905260448101849052606401610754565b604080518581526020810185905233917f928890dff971de1394b7440848938a868d83445d2f7fb4b07938ae626c7cb130910160405180910390a250506002805460ff60a01b1916600160a01b17905590939092509050565b6002546001600160a01b031633146129395760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b8151158061294957508051825114155b1561297457815181516040516308151c1160e41b815260048101929092526024820152604401610754565b5f5b8151811015612a2a57818181518110612991576129916142b8565b60200260200101515f036129b857604051637c946ed760e01b815260040160405180910390fd5b8281815181106129ca576129ca6142b8565b602002602001015160085f8484815181106129e7576129e76142b8565b602002602001015181526020019081526020015f205f6101000a8154816001600160a01b0302191690836001600160a01b03160217905550806001019050612976565b507fe87460f6c400fa0166984512586d7bdf03a3230bbadf9651f27f08716dd77fa5828260405161234e92919061459a565b6024612a71600267ffffffffffffffff6145c7565b612a7b91906145ed565b67ffffffffffffffff1681565b5f858152600860205260409020546001600160a01b03168115612b50576040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b038281166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303815f875af1158015612b2a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b4e9190614299565b505b6024612b65600267ffffffffffffffff6145c7565b612b6f91906145ed565b67ffffffffffffffff168611612c02576040517fb2267a7b00000000000000000000000000000000000000000000000000000000815285906001600160a01b0383169063b2267a7b903490612bce9085908a908a908a90600401614643565b5f604051808303818588803b158015612be5575f80fd5b505af1158015612bf7573d5f803e3d5ffd5b505050505050612c7e565b6040517f6585ecdc0000000000000000000000000000000000000000000000000000000081526001600160a01b03821690636585ecdc903490612c4f90899089908990899060040161467b565b5f604051808303818588803b158015612c66575f80fd5b505af1158015612c78573d5f803e3d5ffd5b50505050505b505050505050565b8251845114612cb557835183516040516308151c1160e41b815260048101929092526024820152604401610754565b8151845114612ce457835182516040516308151c1160e41b815260048101929092526024820152604401610754565b8051845114612d1357835181516040516308151c1160e41b815260048101929092526024820152604401610754565b5f805f5b8651811015612f5a57868181518110612d3257612d326142b8565b60200260200101518310612d7657868181518110612d5257612d526142b8565b6020026020010151604051633881b68960e01b815260040161075491815260200190565b868181518110612d8857612d886142b8565b60200260200101519250858181518110612da457612da46142b8565b6020026020010151515f03612dcc57604051637c946ed760e01b815260040160405180910390fd5b838181518110612dde57612dde6142b8565b602002602001015182612df191906142cc565b91505f600154905080878381518110612e0c57612e0c6142b8565b6020026020010151511115612e5b57868281518110612e2d57612e2d6142b8565b60200260200101515181604051637ae5968560e01b8152600401610754929190918252602082015260400190565b5f805b888481518110612e7057612e706142b8565b602002602001015151811015612f4c57888481518110612e9257612e926142b8565b60200260200101518181518110612eab57612eab6142b8565b60200260200101515f1c825f1c10612f0c57888481518110612ecf57612ecf6142b8565b60200260200101518181518110612ee857612ee86142b8565b6020026020010151604051636aba776560e11b815260040161075491815260200190565b888481518110612f1e57612f1e6142b8565b60200260200101518181518110612f3757612f376142b8565b60200260200101519150806001019050612e5e565b505050806001019050612d17565b50803414612c7e5760405163312b003360e01b815234600482015260248101829052604401610754565b6040805160038082526080820190925260609182918291602082018380368337019050509250845167ffffffffffffffff811115612fc457612fc4613c4d565b604051908082528060200260200182016040528015612ff757816020015b6060815260200190600190039081612fe25790505b509150845167ffffffffffffffff81111561301457613014613c4d565b60405190808252806020026020018201604052801561303d578160200160208202803683370190505b5090505f5b85518110156134d4575f60085f888481518110613061576130616142b8565b602002602001015181526020019081526020015f205f9054906101000a90046001600160a01b031690505f816001600160a01b031663a8b2ae026040518163ffffffff1660e01b8152600401602060405180830381865afa1580156130c8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130ec9190614255565b9050868381518110613100576131006142b8565b60200260200101515167ffffffffffffffff81111561312157613121613c4d565b60405190808252806020026020018201604052801561314a578160200160208202803683370190505b5085848151811061315d5761315d6142b8565b60200260200101819052505f5b87848151811061317c5761317c6142b8565b602002602001015151811015613363577f00000000000000000000000000000000000000000000000000000000000000008885815181106131bf576131bf6142b8565b602002602001015182815181106131d8576131d86142b8565b60200260200101510361322057604051636aba776560e11b81527f00000000000000000000000000000000000000000000000000000000000000006004820152602401610754565b5f805f8061327b8e8e8a8151811061323a5761323a6142b8565b60200260200101518e8b81518110613254576132546142b8565b6020026020010151888151811061326d5761326d6142b8565b602002602001015189611654565b5f8181526006602052604090208290558d519397509195509350915084908b908a9081106132ab576132ab6142b8565b602002602001015186815181106132c4576132c46142b8565b602002602001018181525050838989815181106132e3576132e36142b8565b602002602001018181516132f791906142cc565b9052508a5184908c905f9061330e5761330e6142b8565b6020026020010181815161332291906142cc565b9052508a5183908c90600290811061333c5761333c6142b8565b6020026020010181815161335091906142cc565b905250506001909301925061316a915050565b505f848481518110613377576133776142b8565b60200260200101511115613486575f60095f8a868151811061339b5761339b6142b8565b602002602001015181526020019081526020015f205490505f811115613484578484815181106133cd576133cd6142b8565b60200260200101518110613426578484815181106133ed576133ed6142b8565b6020026020010151816134009190614280565b90505f858581518110613415576134156142b8565b602002602001018181525050613454565b80858581518110613439576134396142b8565b6020026020010181815161344d9190614280565b9052505f90505b8060095f8b878151811061346a5761346a6142b8565b602002602001015181526020019081526020015f20819055505b505b838381518110613498576134986142b8565b6020026020010151866001815181106134b3576134b36142b8565b602002602001018181516134c791906142cc565b9052505050600101613042565b5093509350939050565b5f5b8651811015613ade575f60085f8984815181106134ff576134ff6142b8565b602002602001015181526020019081526020015f205f9054906101000a90046001600160a01b031690505f84838151811061353c5761353c6142b8565b60200260200101511115613607577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb8286858151811061358c5761358c6142b8565b60200260200101516040518363ffffffff1660e01b81526004016135c59291906001600160a01b03929092168252602082015260400190565b6020604051808303815f875af11580156135e1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136059190614299565b505b5f8088848151811061361b5761361b6142b8565b60200260200101515167ffffffffffffffff81111561363c5761363c613c4d565b604051908082528060200260200182016040528015613665578160200160208202803683370190505b5090505f5b89858151811061367c5761367c6142b8565b6020026020010151518110156136fe575f89868151811061369f5761369f6142b8565b602002602001015182815181106136b8576136b86142b8565b602002602001015111156136f65760018282815181106136da576136da6142b8565b911515602092830291909101909101526136f383614699565b92505b60010161366a565b505f8267ffffffffffffffff81111561371957613719613c4d565b604051908082528060200260200182016040528015613742578160200160208202803683370190505b5090505f8367ffffffffffffffff81111561375f5761375f613c4d565b604051908082528060200260200182016040528015613788578160200160208202803683370190505b5090505f805b8c88815181106137a0576137a06142b8565b602002602001015151811015613884578481815181106137c2576137c26142b8565b60200260200101511561387c578c88815181106137e1576137e16142b8565b602002602001015181815181106137fa576137fa6142b8565b6020026020010151848381518110613814576138146142b8565b6020026020010181815250508b8881518110613832576138326142b8565b6020026020010151818151811061384b5761384b6142b8565b6020026020010151838381518110613865576138656142b8565b602090810291909101015261387982614699565b91505b60010161378e565b50602461389a600267ffffffffffffffff6145c7565b6138a491906145ed565b67ffffffffffffffff168d88815181106138c0576138c06142b8565b602002602001015111613a20575f835167ffffffffffffffff8111156138e8576138e8613c4d565b604051908082528060200260200182016040528015613911578160200160208202803683370190505b5090505f5b845181101561396d57848181518110613931576139316142b8565b60200260200101515f1c82828151811061394d5761394d6142b8565b6001600160a01b0390921660209283029190910190910152600101613916565b50866001600160a01b031663bde526618a8a8151811061398f5761398f6142b8565b602002602001015183868f8d815181106139ab576139ab6142b8565b60200260200101518f8e815181106139c5576139c56142b8565b60200260200101516040518663ffffffff1660e01b81526004016139ec94939291906146b1565b5f604051808303818588803b158015613a03575f80fd5b505af1158015613a15573d5f803e3d5ffd5b505050505050613acd565b856001600160a01b03166355442b59898981518110613a4157613a416142b8565b602002602001015185858e8c81518110613a5d57613a5d6142b8565b60200260200101518e8d81518110613a7757613a776142b8565b60200260200101516040518663ffffffff1660e01b8152600401613a9e94939291906146fb565b5f604051808303818588803b158015613ab5575f80fd5b505af1158015613ac7573d5f803e3d5ffd5b50505050505b5050505050508060010190506134e0565b50505050505050565b5f805f60035f9054906101000a90046001600160a01b03166001600160a01b03166314b19c5a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613b3a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b5e91906142df565b5f86815260066020526040812054945063ffffffff919091169150839003613b9957604051637c946ed760e01b815260040160405180910390fd5b808303613bce5782613bac600183614280565b604051637ae5968560e01b815260048101929092526024820152604401610754565b5f85815260076020526040902054600181118015613bec5750808410155b15613bfd5783613bac600183614280565b613c0785856142cc565b9250600181118015613c1857508083115b15613c21578092505b81831115613c2d578192505b50509250929050565b5f60208284031215613c46575f80fd5b5035919050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff81118282101715613c8a57613c8a613c4d565b604052919050565b5f82601f830112613ca1575f80fd5b813567ffffffffffffffff811115613cbb57613cbb613c4d565b613cce601f8201601f1916602001613c61565b818152846020838601011115613ce2575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f8060808587031215613d11575f80fd5b843593506020850135925060408501359150606085013567ffffffffffffffff811115613d3c575f80fd5b613d4887828801613c92565b91505092959194509250565b5f67ffffffffffffffff821115613d6d57613d6d613c4d565b5060051b60200190565b5f82601f830112613d86575f80fd5b81356020613d9b613d9683613d54565b613c61565b8083825260208201915060208460051b870101935086841115613dbc575f80fd5b602086015b84811015613dd85780358352918301918301613dc1565b509695505050505050565b5f82601f830112613df2575f80fd5b81356020613e02613d9683613d54565b82815260059290921b84018101918181019086841115613e20575f80fd5b8286015b84811015613dd857803567ffffffffffffffff811115613e42575f80fd5b613e508986838b0101613c92565b845250918301918301613e24565b5f805f805f60a08688031215613e72575f80fd5b8535945067ffffffffffffffff8060208801351115613e8f575f80fd5b613e9f8860208901358901613d77565b94508060408801351115613eb1575f80fd5b6040870135870188601f820112613ec6575f80fd5b613ed3613d968235613d54565b81358082526020808301929160051b8401018b1015613ef0575f80fd5b602083015b6020843560051b850101811015613f8a578481351115613f13575f80fd5b803584018c603f820112613f25575f80fd5b613f35613d966020830135613d54565b602082810135808352908201919060051b83016040018f811115613f57575f80fd5b6040840193505b80841015613f79578335835260209384019390920191613f5e565b508552505060209283019201613ef5565b50955050506060870135811015613f9f575f80fd5b613faf8860608901358901613de3565b92508060808801351115613fc1575f80fd5b50613fd28760808801358801613d77565b90509295509295909350565b5f805f60608486031215613ff0575f80fd5b505081359360208301359350604090920135919050565b634e487b7160e01b5f52602160045260245ffd5b602081016004831061403b57634e487b7160e01b5f52602160045260245ffd5b91905290565b5f60208284031215614051575f80fd5b81356004811061405f575f80fd5b9392505050565b5f805f8060808587031215614079575f80fd5b5050823594602084013594506040840135936060013592509050565b80356001600160a01b03811681146140ab575f80fd5b919050565b5f602082840312156140c0575f80fd5b61405f82614095565b5f80604083850312156140da575f80fd5b50508035926020909101359150565b5f805f606084860312156140fb575f80fd5b61410484614095565b925061411260208501614095565b915061412060408501614095565b90509250925092565b5f806040838503121561413a575f80fd5b823567ffffffffffffffff80821115614151575f80fd5b61415d86838701613d77565b93506020850135915080821115614172575f80fd5b5061417f85828601613d77565b9150509250929050565b5f806040838503121561419a575f80fd5b823567ffffffffffffffff808211156141b1575f80fd5b818501915085601f8301126141c4575f80fd5b813560206141d4613d9683613d54565b82815260059290921b840181019181810190898411156141f2575f80fd5b948201945b838610156142175761420886614095565b825294820194908201906141f7565b96505086013592505080821115614172575f80fd5b805160ff811681146140ab575f80fd5b5f6020828403121561424c575f80fd5b61405f8261422c565b5f60208284031215614265575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b818103818111156142935761429361426c565b92915050565b5f602082840312156142a9575f80fd5b8151801515811461405f575f80fd5b634e487b7160e01b5f52603260045260245ffd5b808201808211156142935761429361426c565b5f602082840312156142ef575f80fd5b815163ffffffff8116811461405f575f80fd5b80516bffffffffffffffffffffffff811681146140ab575f80fd5b5f6080828403121561432d575f80fd5b6040516080810181811067ffffffffffffffff8211171561435057614350613c4d565b60405261435c83614302565b815261436a60208401614302565b6020820152604083015161ffff81168114614383575f80fd5b60408201526143946060840161422c565b60608201529392505050565b5f80604083850312156143b1575f80fd5b505080516020909101519092909150565b80820281158282048414176142935761429361426c565b634e487b7160e01b5f52601260045260245ffd5b5f826143fb576143fb6143d9565b500490565b600181815b8085111561443a57815f19048211156144205761442061426c565b8085161561442d57918102915b93841c9390800290614405565b509250929050565b5f8261445057506001614293565b8161445c57505f614293565b8160018114614472576002811461447c57614498565b6001915050614293565b60ff84111561448d5761448d61426c565b50506001821b614293565b5060208310610133831016604e8410600b84101617156144bb575081810a614293565b6144c58383614400565b805f19048211156144d8576144d861426c565b029392505050565b5f61405f8383614442565b5f815180845260208085019450602084015f5b8381101561451a578151875295820195908201906001016144fe565b509495945050505050565b6001600160a01b0384168152606060208201525f61454660608301856144eb565b828103604084015261455881856144eb565b9695505050505050565b5f815180845260208085019450602084015f5b8381101561451a5781516001600160a01b031687529582019590820190600101614575565b604081525f6145ac6040830185614562565b82810360208401526145be81856144eb565b95945050505050565b5f67ffffffffffffffff808416806145e1576145e16143d9565b92169190910492915050565b67ffffffffffffffff82811682821603908082111561460e5761460e61426c565b5092915050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b0385168152836020820152608060408201525f61466a6080830185614615565b905082606083015295945050505050565b848152836020820152608060408201525f61466a6080830185614615565b5f600182016146aa576146aa61426c565b5060010190565b608081525f6146c36080830187614562565b82810360208401526146d581876144eb565b905082810360408401526146e98186614615565b91505082606083015295945050505050565b608080825285519082018190525f9060209060a0840190828901845b8281101561473357815184529284019290840190600101614717565b505050838103602085015261474881886144eb565b91505082810360408401526146e9818661461556fea2646970667358221220d5ad21b1e3c7f46f079be5de02f8abed25c59cb8c181f76db5750438335cf60864736f6c63430008190033", - "deployedBytecode": "0x6080604052600436106101da575f3560e01c806379bc81dd116100fd578063bc7d5c5c11610092578063dcb5ccc411610062578063dcb5ccc4146105f9578063e09177781461062d578063e6be59e714610660578063f4da12ba14610693575f80fd5b8063bc7d5c5c14610568578063d529779314610587578063d7accbcc146105a6578063d8bf69bf146105da575f80fd5b80639649a35c116100cd5780639649a35c146104eb578063a5edd4fc146104ff578063a6f9dae11461051e578063bb78678f1461053d575f80fd5b806379bc81dd1461046e5780638513e77d1461048d5780638833c205146104b85780638da5cb5b146104cc575f80fd5b80633c18d1dd1161017357806361d027b31161014357806361d027b3146103d257806363096509146103f157806363c4d28e14610410578063777e49c91461042f575f80fd5b80633c18d1dd146103345780634ac7251d146103675780635a55a482146103865780635c975abb146103a5575f80fd5b80632ad923dc116101ae5780632ad923dc146102cc5780632c0f3f29146102f757806334be5af41461030c5780633907196c14610321575f80fd5b806231d115146101de5780630d17db111461022e5780630d3241ee1461026c5780632a3bb6931461028b575b5f80fd5b3480156101e9575f80fd5b506102117f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610239575f80fd5b5061025c610248366004613c36565b600a6020525f908152604090205460ff1681565b6040519015158152602001610225565b348015610277575f80fd5b50600554610211906001600160a01b031681565b348015610296575f80fd5b506102be7f000000000000000000000000000000000000000000000000000000000000000081565b604051908152602001610225565b3480156102d7575f80fd5b506102be6102e6366004613c36565b60066020525f908152604090205481565b61030a610305366004613cfe565b6106a7565b005b348015610317575f80fd5b506102be60015481565b61030a61032f366004613e5e565b610be6565b34801561033f575f80fd5b506102be7f000000000000000000000000000000000000000000000000000000000000000081565b348015610372575f80fd5b50600354610211906001600160a01b031681565b348015610391575f80fd5b5061030a6103a0366004613fde565b611148565b3480156103b0575f80fd5b506002546103c590600160a81b900460ff1681565b604051610225919061401b565b3480156103dd575f80fd5b50600454610211906001600160a01b031681565b3480156103fc575f80fd5b5061030a61040b366004614041565b611312565b34801561041b575f80fd5b5061030a61042a366004613c36565b6113d1565b34801561043a575f80fd5b5061044e610449366004614066565b611654565b604080519485526020850193909352918301526060820152608001610225565b348015610479575f80fd5b5061030a610488366004613fde565b611b99565b348015610498575f80fd5b506102be6104a7366004613c36565b60076020525f908152604090205481565b3480156104c3575f80fd5b506102be5f5481565b3480156104d7575f80fd5b50600254610211906001600160a01b031681565b3480156104f6575f80fd5b5061030a611ca8565b34801561050a575f80fd5b5061030a610519366004613c36565b61204a565b348015610529575f80fd5b5061030a6105383660046140b0565b6121ed565b348015610548575f80fd5b506102be610557366004613c36565b60096020525f908152604090205481565b348015610573575f80fd5b5061030a6105823660046140c9565b6122aa565b348015610592575f80fd5b5061030a6105a13660046140e9565b61235a565b3480156105b1575f80fd5b506105c56105c0366004614129565b6124c8565b60408051928352602083019190915201610225565b3480156105e5575f80fd5b5061030a6105f4366004614189565b6128f9565b348015610604575f80fd5b50610211610613366004613c36565b60086020525f90815260409020546001600160a01b031681565b348015610638575f80fd5b506102be7f000000000000000000000000000000000000000000000000000000000000000081565b34801561066b575f80fd5b506102be7f000000000000000000000000000000000000000000000000000000000000000081565b34801561069e575f80fd5b506102be612a5c565b6002546001600160a01b90910460ff1611156106d6576040516345f5ce8b60e11b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790555f83900361070a57604051637c946ed760e01b815260040160405180910390fd5b5f82900361072b5760405163d92e233d60e01b815260040160405180910390fd5b5f548085111561075d57604051637ae5968560e01b815260048101869052602481018290526044015b60405180910390fd5b60028054600160a81b900460ff169081600381111561077e5761077e614007565b148061079b5750600381600381111561079957610799614007565b145b8061081257506004805460408051635c975abb60e01b815290516001600160a01b0390921692635c975abb92828201926020929082900301815f875af11580156107e7573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061080b919061423c565b60ff166002145b15610830576040516313d0ff5960e31b815260040160405180910390fd5b5f8581526008602090815260408083205481517fa8b2ae0200000000000000000000000000000000000000000000000000000000815291516001600160a01b039091169392849263a8b2ae0292600480830193928290030181865afa15801561089b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108bf9190614255565b90505f805f806108d18c8c8c88611654565b5f81815260066020526040902082905592965090945092509050821561094b57600354604051635e148f0960e11b8152600481018590526001600160a01b039091169063bc291e12906024015f604051808303815f87803b158015610934575f80fd5b505af1158015610946573d5f803e3d5ffd5b505050505b5f8415610b8157505f8b815260096020526040902054849080156109a5578181106109845761097a8282614280565b90505f9150610994565b61098e8183614280565b91505f90505b5f8d81526009602052604090208190555b8115610b72576040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610a0f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a339190614255565b60048054604051637ff796ab60e01b815230928101929092525f6024830152604482018690529192506001600160a01b0390911690637ff796ab906064016020604051808303815f875af1158015610a8d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ab19190614299565b506040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610b16573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b3a9190614255565b610b449190614280565b9050828114610b705760405163312b003360e01b81526004810182905260248101849052604401610754565b505b610b7f8d8d888e86612a88565b505b604080518681526020810183905290810185905233907f02b21954a7bf2d6a171db9a87b430a3723605c554db00adcb95b26ce8464f2809060600160405180910390a250506002805460ff60a01b1916600160a01b1790555050505050505050505050565b6002546001600160a01b90910460ff161115610c15576040516345f5ce8b60e11b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b179055610c3484848484612c86565b5f5480861115610c6157604051637ae5968560e01b81526004810187905260248101829052604401610754565b60028054600160a81b900460ff1690816003811115610c8257610c82614007565b1480610c9f57506003816003811115610c9d57610c9d614007565b145b80610d1657506004805460408051635c975abb60e01b815290516001600160a01b0390921692635c975abb92828201926020929082900301815f875af1158015610ceb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d0f919061423c565b60ff166002145b15610d34576040516313d0ff5960e31b815260040160405180910390fd5b6060806060610d448a8a8a612f84565b825192955090935091505f9084906002908110610d6357610d636142b8565b60200260200101511115610def5760035483516001600160a01b039091169063bc291e129085906002908110610d9b57610d9b6142b8565b60200260200101516040518263ffffffff1660e01b8152600401610dc191815260200190565b5f604051808303815f87803b158015610dd8575f80fd5b505af1158015610dea573d5f803e3d5ffd5b505050505b5f835f81518110610e0257610e026142b8565b60200260200101511115611086575f83600181518110610e2457610e246142b8565b60200260200101511115611078576040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610e96573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610eba9190614255565b60045485519192506001600160a01b031690637ff796ab9030905f9088906001908110610ee957610ee96142b8565b60209081029190910101516040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b039093166004840152602483019190915260448201526064016020604051808303815f875af1158015610f5c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f809190614299565b506040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610fe5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110099190614255565b6110139190614280565b905083600181518110611028576110286142b8565b6020026020010151811461107657808460018151811061104a5761104a6142b8565b602002602001015160405163312b003360e01b8152600401610754929190918252602082015260400190565b505b6110868989848a858b6134de565b336001600160a01b03167f02b21954a7bf2d6a171db9a87b430a3723605c554db00adcb95b26ce8464f280845f815181106110c3576110c36142b8565b6020026020010151856001815181106110de576110de6142b8565b6020026020010151866002815181106110f9576110f96142b8565b6020026020010151604051611121939291909283526020830191909152604082015260600190565b60405180910390a250506002805460ff60a01b1916600160a01b1790555050505050505050565b6002546001600160a01b031633146111885760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b821580611193575081155b8061119c575080155b156111ba57604051637c946ed760e01b815260040160405180910390fd5b4683036111dd57604051633881b68960e01b815260048101849052602401610754565b5f838152600960205260408120546111f69084906142cc565b90506bffffffffffffffffffffffff81111561123a57604051637ae5968560e01b8152600481018290526bffffffffffffffffffffffff6024820152604401610754565b5f8481526009602090815260408083208490556008909152908190205490517fac65ded2000000000000000000000000000000000000000000000000000000008152600481018490526001600160a01b0390911690819063ac65ded2906024015f604051808303815f87803b1580156112b1575f80fd5b505af11580156112c3573d5f803e3d5ffd5b505060408051888152602081018890529081018590528592507f2192822efd68ddf583804c65675b73a59694e672cab1758eb6714613f932a97591506060015b60405180910390a25050505050565b6002546001600160a01b031633146113525760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b600280548291907fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16600160a81b83600381111561139257611392614007565b02179055507fa814f27828c0243d429ea8c7033cb10f0c825b9466fdc04f63e0cca26c28eb8a816040516113c6919061401b565b60405180910390a150565b6005546001600160a01b031633146114115760055460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610754565b807f00000000000000000000000000000000000000000000000000000000000000000361147357604051636aba776560e11b81527f00000000000000000000000000000000000000000000000000000000000000006004820152602401610754565b600354604080517f14b19c5a00000000000000000000000000000000000000000000000000000000815290515f926001600160a01b0316916314b19c5a9160048083019260209291908290030181865afa1580156114d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114f791906142df565b60035463ffffffff9190911691505f906001600160a01b031663d4ee9f8d611520600185614280565b6040518263ffffffff1660e01b815260040161153e91815260200190565b602060405180830381865afa158015611559573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061157d9190614255565b90505f60035f9054906101000a90046001600160a01b03166001600160a01b031663d2b3996f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115d0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115f491906142df565b63ffffffff1690505f62093a8061160b83856142cc565b6116159190614280565b905080421061164057604051637ae5968560e01b815242600482015260248101829052604401610754565b5050505f9182526007602052604090912055565b5f805f80865f0361167857604051637c946ed760e01b815260040160405180910390fd5b5f8690036116995760405163d92e233d60e01b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000086036116fb57604051636aba776560e11b81527f00000000000000000000000000000000000000000000000000000000000000006004820152602401610754565b5060408051808201825286815260209081018881528251808301899052905181840152825180820384018152606090910190925281519101205f61173f828a613ae7565b6005546040516317d5e89d60e31b8152600481018b9052602481018c90529195509192506001600160a01b039091169063beaf44e8906044015f604051808303815f87803b15801561178f575f80fd5b505af11580156117a1573d5f803e3d5ffd5b5083925050505b83811015611b8c575f818152600a602052604090205460ff16611b8457600354604051631ddf133560e01b8152600481018390525f916001600160a01b031690631ddf133590602401608060405180830381865afa15801561180c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611830919061431d565b606081015190915060ff16156118cf57604081015161ffff16158015611866575060208101516bffffffffffffffffffffffff16155b156118ca5761ffff7f00000000000000000000000000000000000000000000000000000000000000001660408201526bffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660208201525b6118d5565b50611b84565b60035460405163d4ee9f8d60e01b8152600481018490525f916001600160a01b03169063d4ee9f8d90602401602060405180830381865afa15801561191c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119409190614255565b600554604051630c88d47f60e41b8152600481018d9052602481018e9052604481018390529192505f9182916001600160a01b03169063c88d47f0906064016040805180830381865afa158015611999573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119bd91906143a0565b91509150805f03611a05575f858152600a60205260409020805460ff1916600117905583516119fa906bffffffffffffffffffffffff168a6142cc565b985050505050611b84565b83515f9081906bffffffffffffffffffffffff168184821115611a3257611a2c8583614280565b90508491505b6040880151611a4b9061ffff16655af3107a40006143c2565b861015611a8157670de0b6b3a764000086611a6684846142cc565b611a7091906143c2565b611a7a91906143ed565b9250611b6f565b670de0b6b3a7640000611a9487846143c2565b611a9e91906143ed565b9350670de0b6b3a7640000611ab387836143c2565b611abd91906143ed565b925087602001516bffffffffffffffffffffffff16915081841115611af657611ae68285614280565b611af090846142cc565b92508193505b60128f1015611b62575f8f6012611b0d9190614280565b611b1890600a6144e0565b611b2290866143ed565b90508f6012611b319190614280565b611b3c90600a6144e0565b611b4690826143c2565b9050611b528186614280565b611b5c90856142cc565b90945092505b611b6c848f6142cc565b9d505b611b79838e6142cc565b9c5050505050505050505b6001016117a8565b5050945094509450949050565b5f838152600860205260409020546001600160a01b0316338114611bfa576040517fdeeeedec0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0382166024820152604401610754565b5f84815260096020526040812054611c139085906142cc565b90506bffffffffffffffffffffffff811115611c5757604051637ae5968560e01b8152600481018290526bffffffffffffffffffffffff6024820152604401610754565b5f85815260096020908152604091829020839055815187815290810186905290810182905283907f2192822efd68ddf583804c65675b73a59694e672cab1758eb6714613f932a97590606001611303565b6002546001600160a01b90910460ff161115611cd7576040516345f5ce8b60e11b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790555f80548190611d1a907f000000000000000000000000000000000000000000000000000000000000000090613ae7565b6005546040516317d5e89d60e31b81527f000000000000000000000000000000000000000000000000000000000000000060048201524660248201529294509092506001600160a01b03169063beaf44e8906044015f604051808303815f87803b158015611d86575f80fd5b505af1158015611d98573d5f803e3d5ffd5b50507f00000000000000000000000000000000000000000000000000000000000000005f90815260066020526040812084905591508390505b82811015611f8857600354604051631ddf133560e01b8152600481018390525f916001600160a01b031690631ddf133590602401608060405180830381865afa158015611e20573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e44919061431d565b60035460405163d4ee9f8d60e01b8152600481018590529192505f916001600160a01b039091169063d4ee9f8d90602401602060405180830381865afa158015611e90573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611eb49190614255565b600554604051630c88d47f60e41b81527f00000000000000000000000000000000000000000000000000000000000000006004820152466024820152604481018390529192505f916001600160a01b039091169063c88d47f0906064016040805180830381865afa158015611f2b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f4f91906143a0565b508351909150611f6e9082906bffffffffffffffffffffffff166143c2565b611f7890866142cc565b9450505050806001019050611dd1565b50611f9b670de0b6b3a7640000826143ed565b90508015611ffd57600354604051635e148f0960e11b8152600481018390526001600160a01b039091169063bc291e12906024015f604051808303815f87803b158015611fe6575f80fd5b505af1158015611ff8573d5f803e3d5ffd5b505050505b60405181815233907f2a8de497d698d6869cb0844411788378e76214d03a541eec6ba514b795d9f42e9060200160405180910390a250506002805460ff60a01b1916600160a01b17905550565b6005546001600160a01b0316331461208a5760055460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610754565b60028054600160a81b900460ff16908160038111156120ab576120ab614007565b14806120c8575060038160038111156120c6576120c6614007565b145b8061213f57506004805460408051635c975abb60e01b815290516001600160a01b0390921692635c975abb92828201926020929082900301815f875af1158015612114573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612138919061423c565b60ff166002145b1561215d576040516313d0ff5960e31b815260040160405180910390fd5b60035f9054906101000a90046001600160a01b03166001600160a01b03166314b19c5a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121ad573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121d191906142df565b5f9283526006602052604090922063ffffffff90921690915550565b6002546001600160a01b0316331461222d5760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b6001600160a01b0381166122545760405163d92e233d60e01b815260040160405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f4ffd725fc4a22075e9ec71c59edf9c38cdeb588a91b24fc5b61388c5be41282b905f90a250565b6002546001600160a01b031633146122ea5760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b8115806122f5575080155b1561231357604051637c946ed760e01b815260040160405180910390fd5b5f829055600181905560408051838152602081018390527f61f6c4cc9665a257352c0b46189ffc2ae6fbbc11e155ff20901217ff203a517e91015b60405180910390a15050565b6002546001600160a01b0316331461239a5760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b6001600160a01b038316156123fd576003805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0385169081179091556040517f4672fe7e13cfb163442d0b729b5733fb3efafc66cbe3677eac9940eb41c284c2905f90a25b6001600160a01b03821615612460576004805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0384169081179091556040517f7dae230f18360d76a040c81f050aa14eb9d6dc7901b20fc5d855e2a20fe814d1905f90a25b6001600160a01b038116156124c3576005805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f04a606379838ed6fc83fd189eea9d1835b5eff05035c4b74622911ea2ae6b217905f90a25b505050565b5f806001600260149054906101000a900460ff1660ff1611156124fe576040516345f5ce8b60e11b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b179081905560ff600160a81b90910416600181600381111561253257612532614007565b148061254f5750600381600381111561254d5761254d614007565b145b806125c657506004805460408051635c975abb60e01b815290516001600160a01b0390921692635c975abb92828201926020929082900301815f875af115801561259b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125bf919061423c565b60ff166002145b156125e4576040516313d0ff5960e31b815260040160405180910390fd5b6003546040517f2e070f540000000000000000000000000000000000000000000000000000000081526001600160a01b0390911690632e070f549061263190339089908990600401614525565b60408051808303815f875af115801561264c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061267091906143a0565b90935091505f8061268184866142cc565b1115612859575f8315612717576040516370a0823160e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156126f0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127149190614255565b90505b60048054604051637ff796ab60e01b8152339281019290925260248201879052604482018690526001600160a01b031690637ff796ab906064016020604051808303815f875af115801561276d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127919190614299565b91508315612857576040516370a0823160e01b815233600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156127fd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128219190614255565b61282b9190614280565b90508381146128575760405163312b003360e01b81526004810182905260248101859052604401610754565b505b806128a0576040517f942dc9da0000000000000000000000000000000000000000000000000000000081523360048201526024810185905260448101849052606401610754565b604080518581526020810185905233917f928890dff971de1394b7440848938a868d83445d2f7fb4b07938ae626c7cb130910160405180910390a250506002805460ff60a01b1916600160a01b17905590939092509050565b6002546001600160a01b031633146129395760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b8151158061294957508051825114155b1561297457815181516040516308151c1160e41b815260048101929092526024820152604401610754565b5f5b8151811015612a2a57818181518110612991576129916142b8565b60200260200101515f036129b857604051637c946ed760e01b815260040160405180910390fd5b8281815181106129ca576129ca6142b8565b602002602001015160085f8484815181106129e7576129e76142b8565b602002602001015181526020019081526020015f205f6101000a8154816001600160a01b0302191690836001600160a01b03160217905550806001019050612976565b507fe87460f6c400fa0166984512586d7bdf03a3230bbadf9651f27f08716dd77fa5828260405161234e92919061459a565b6024612a71600267ffffffffffffffff6145c7565b612a7b91906145ed565b67ffffffffffffffff1681565b5f858152600860205260409020546001600160a01b03168115612b50576040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b038281166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303815f875af1158015612b2a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b4e9190614299565b505b6024612b65600267ffffffffffffffff6145c7565b612b6f91906145ed565b67ffffffffffffffff168611612c02576040517fb2267a7b00000000000000000000000000000000000000000000000000000000815285906001600160a01b0383169063b2267a7b903490612bce9085908a908a908a90600401614643565b5f604051808303818588803b158015612be5575f80fd5b505af1158015612bf7573d5f803e3d5ffd5b505050505050612c7e565b6040517f6585ecdc0000000000000000000000000000000000000000000000000000000081526001600160a01b03821690636585ecdc903490612c4f90899089908990899060040161467b565b5f604051808303818588803b158015612c66575f80fd5b505af1158015612c78573d5f803e3d5ffd5b50505050505b505050505050565b8251845114612cb557835183516040516308151c1160e41b815260048101929092526024820152604401610754565b8151845114612ce457835182516040516308151c1160e41b815260048101929092526024820152604401610754565b8051845114612d1357835181516040516308151c1160e41b815260048101929092526024820152604401610754565b5f805f5b8651811015612f5a57868181518110612d3257612d326142b8565b60200260200101518310612d7657868181518110612d5257612d526142b8565b6020026020010151604051633881b68960e01b815260040161075491815260200190565b868181518110612d8857612d886142b8565b60200260200101519250858181518110612da457612da46142b8565b6020026020010151515f03612dcc57604051637c946ed760e01b815260040160405180910390fd5b838181518110612dde57612dde6142b8565b602002602001015182612df191906142cc565b91505f600154905080878381518110612e0c57612e0c6142b8565b6020026020010151511115612e5b57868281518110612e2d57612e2d6142b8565b60200260200101515181604051637ae5968560e01b8152600401610754929190918252602082015260400190565b5f805b888481518110612e7057612e706142b8565b602002602001015151811015612f4c57888481518110612e9257612e926142b8565b60200260200101518181518110612eab57612eab6142b8565b60200260200101515f1c825f1c10612f0c57888481518110612ecf57612ecf6142b8565b60200260200101518181518110612ee857612ee86142b8565b6020026020010151604051636aba776560e11b815260040161075491815260200190565b888481518110612f1e57612f1e6142b8565b60200260200101518181518110612f3757612f376142b8565b60200260200101519150806001019050612e5e565b505050806001019050612d17565b50803414612c7e5760405163312b003360e01b815234600482015260248101829052604401610754565b6040805160038082526080820190925260609182918291602082018380368337019050509250845167ffffffffffffffff811115612fc457612fc4613c4d565b604051908082528060200260200182016040528015612ff757816020015b6060815260200190600190039081612fe25790505b509150845167ffffffffffffffff81111561301457613014613c4d565b60405190808252806020026020018201604052801561303d578160200160208202803683370190505b5090505f5b85518110156134d4575f60085f888481518110613061576130616142b8565b602002602001015181526020019081526020015f205f9054906101000a90046001600160a01b031690505f816001600160a01b031663a8b2ae026040518163ffffffff1660e01b8152600401602060405180830381865afa1580156130c8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130ec9190614255565b9050868381518110613100576131006142b8565b60200260200101515167ffffffffffffffff81111561312157613121613c4d565b60405190808252806020026020018201604052801561314a578160200160208202803683370190505b5085848151811061315d5761315d6142b8565b60200260200101819052505f5b87848151811061317c5761317c6142b8565b602002602001015151811015613363577f00000000000000000000000000000000000000000000000000000000000000008885815181106131bf576131bf6142b8565b602002602001015182815181106131d8576131d86142b8565b60200260200101510361322057604051636aba776560e11b81527f00000000000000000000000000000000000000000000000000000000000000006004820152602401610754565b5f805f8061327b8e8e8a8151811061323a5761323a6142b8565b60200260200101518e8b81518110613254576132546142b8565b6020026020010151888151811061326d5761326d6142b8565b602002602001015189611654565b5f8181526006602052604090208290558d519397509195509350915084908b908a9081106132ab576132ab6142b8565b602002602001015186815181106132c4576132c46142b8565b602002602001018181525050838989815181106132e3576132e36142b8565b602002602001018181516132f791906142cc565b9052508a5184908c905f9061330e5761330e6142b8565b6020026020010181815161332291906142cc565b9052508a5183908c90600290811061333c5761333c6142b8565b6020026020010181815161335091906142cc565b905250506001909301925061316a915050565b505f848481518110613377576133776142b8565b60200260200101511115613486575f60095f8a868151811061339b5761339b6142b8565b602002602001015181526020019081526020015f205490505f811115613484578484815181106133cd576133cd6142b8565b60200260200101518110613426578484815181106133ed576133ed6142b8565b6020026020010151816134009190614280565b90505f858581518110613415576134156142b8565b602002602001018181525050613454565b80858581518110613439576134396142b8565b6020026020010181815161344d9190614280565b9052505f90505b8060095f8b878151811061346a5761346a6142b8565b602002602001015181526020019081526020015f20819055505b505b838381518110613498576134986142b8565b6020026020010151866001815181106134b3576134b36142b8565b602002602001018181516134c791906142cc565b9052505050600101613042565b5093509350939050565b5f5b8651811015613ade575f60085f8984815181106134ff576134ff6142b8565b602002602001015181526020019081526020015f205f9054906101000a90046001600160a01b031690505f84838151811061353c5761353c6142b8565b60200260200101511115613607577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb8286858151811061358c5761358c6142b8565b60200260200101516040518363ffffffff1660e01b81526004016135c59291906001600160a01b03929092168252602082015260400190565b6020604051808303815f875af11580156135e1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136059190614299565b505b5f8088848151811061361b5761361b6142b8565b60200260200101515167ffffffffffffffff81111561363c5761363c613c4d565b604051908082528060200260200182016040528015613665578160200160208202803683370190505b5090505f5b89858151811061367c5761367c6142b8565b6020026020010151518110156136fe575f89868151811061369f5761369f6142b8565b602002602001015182815181106136b8576136b86142b8565b602002602001015111156136f65760018282815181106136da576136da6142b8565b911515602092830291909101909101526136f383614699565b92505b60010161366a565b505f8267ffffffffffffffff81111561371957613719613c4d565b604051908082528060200260200182016040528015613742578160200160208202803683370190505b5090505f8367ffffffffffffffff81111561375f5761375f613c4d565b604051908082528060200260200182016040528015613788578160200160208202803683370190505b5090505f805b8c88815181106137a0576137a06142b8565b602002602001015151811015613884578481815181106137c2576137c26142b8565b60200260200101511561387c578c88815181106137e1576137e16142b8565b602002602001015181815181106137fa576137fa6142b8565b6020026020010151848381518110613814576138146142b8565b6020026020010181815250508b8881518110613832576138326142b8565b6020026020010151818151811061384b5761384b6142b8565b6020026020010151838381518110613865576138656142b8565b602090810291909101015261387982614699565b91505b60010161378e565b50602461389a600267ffffffffffffffff6145c7565b6138a491906145ed565b67ffffffffffffffff168d88815181106138c0576138c06142b8565b602002602001015111613a20575f835167ffffffffffffffff8111156138e8576138e8613c4d565b604051908082528060200260200182016040528015613911578160200160208202803683370190505b5090505f5b845181101561396d57848181518110613931576139316142b8565b60200260200101515f1c82828151811061394d5761394d6142b8565b6001600160a01b0390921660209283029190910190910152600101613916565b50866001600160a01b031663bde526618a8a8151811061398f5761398f6142b8565b602002602001015183868f8d815181106139ab576139ab6142b8565b60200260200101518f8e815181106139c5576139c56142b8565b60200260200101516040518663ffffffff1660e01b81526004016139ec94939291906146b1565b5f604051808303818588803b158015613a03575f80fd5b505af1158015613a15573d5f803e3d5ffd5b505050505050613acd565b856001600160a01b03166355442b59898981518110613a4157613a416142b8565b602002602001015185858e8c81518110613a5d57613a5d6142b8565b60200260200101518e8d81518110613a7757613a776142b8565b60200260200101516040518663ffffffff1660e01b8152600401613a9e94939291906146fb565b5f604051808303818588803b158015613ab5575f80fd5b505af1158015613ac7573d5f803e3d5ffd5b50505050505b5050505050508060010190506134e0565b50505050505050565b5f805f60035f9054906101000a90046001600160a01b03166001600160a01b03166314b19c5a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613b3a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b5e91906142df565b5f86815260066020526040812054945063ffffffff919091169150839003613b9957604051637c946ed760e01b815260040160405180910390fd5b808303613bce5782613bac600183614280565b604051637ae5968560e01b815260048101929092526024820152604401610754565b5f85815260076020526040902054600181118015613bec5750808410155b15613bfd5783613bac600183614280565b613c0785856142cc565b9250600181118015613c1857508083115b15613c21578092505b81831115613c2d578192505b50509250929050565b5f60208284031215613c46575f80fd5b5035919050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff81118282101715613c8a57613c8a613c4d565b604052919050565b5f82601f830112613ca1575f80fd5b813567ffffffffffffffff811115613cbb57613cbb613c4d565b613cce601f8201601f1916602001613c61565b818152846020838601011115613ce2575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f8060808587031215613d11575f80fd5b843593506020850135925060408501359150606085013567ffffffffffffffff811115613d3c575f80fd5b613d4887828801613c92565b91505092959194509250565b5f67ffffffffffffffff821115613d6d57613d6d613c4d565b5060051b60200190565b5f82601f830112613d86575f80fd5b81356020613d9b613d9683613d54565b613c61565b8083825260208201915060208460051b870101935086841115613dbc575f80fd5b602086015b84811015613dd85780358352918301918301613dc1565b509695505050505050565b5f82601f830112613df2575f80fd5b81356020613e02613d9683613d54565b82815260059290921b84018101918181019086841115613e20575f80fd5b8286015b84811015613dd857803567ffffffffffffffff811115613e42575f80fd5b613e508986838b0101613c92565b845250918301918301613e24565b5f805f805f60a08688031215613e72575f80fd5b8535945067ffffffffffffffff8060208801351115613e8f575f80fd5b613e9f8860208901358901613d77565b94508060408801351115613eb1575f80fd5b6040870135870188601f820112613ec6575f80fd5b613ed3613d968235613d54565b81358082526020808301929160051b8401018b1015613ef0575f80fd5b602083015b6020843560051b850101811015613f8a578481351115613f13575f80fd5b803584018c603f820112613f25575f80fd5b613f35613d966020830135613d54565b602082810135808352908201919060051b83016040018f811115613f57575f80fd5b6040840193505b80841015613f79578335835260209384019390920191613f5e565b508552505060209283019201613ef5565b50955050506060870135811015613f9f575f80fd5b613faf8860608901358901613de3565b92508060808801351115613fc1575f80fd5b50613fd28760808801358801613d77565b90509295509295909350565b5f805f60608486031215613ff0575f80fd5b505081359360208301359350604090920135919050565b634e487b7160e01b5f52602160045260245ffd5b602081016004831061403b57634e487b7160e01b5f52602160045260245ffd5b91905290565b5f60208284031215614051575f80fd5b81356004811061405f575f80fd5b9392505050565b5f805f8060808587031215614079575f80fd5b5050823594602084013594506040840135936060013592509050565b80356001600160a01b03811681146140ab575f80fd5b919050565b5f602082840312156140c0575f80fd5b61405f82614095565b5f80604083850312156140da575f80fd5b50508035926020909101359150565b5f805f606084860312156140fb575f80fd5b61410484614095565b925061411260208501614095565b915061412060408501614095565b90509250925092565b5f806040838503121561413a575f80fd5b823567ffffffffffffffff80821115614151575f80fd5b61415d86838701613d77565b93506020850135915080821115614172575f80fd5b5061417f85828601613d77565b9150509250929050565b5f806040838503121561419a575f80fd5b823567ffffffffffffffff808211156141b1575f80fd5b818501915085601f8301126141c4575f80fd5b813560206141d4613d9683613d54565b82815260059290921b840181019181810190898411156141f2575f80fd5b948201945b838610156142175761420886614095565b825294820194908201906141f7565b96505086013592505080821115614172575f80fd5b805160ff811681146140ab575f80fd5b5f6020828403121561424c575f80fd5b61405f8261422c565b5f60208284031215614265575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b818103818111156142935761429361426c565b92915050565b5f602082840312156142a9575f80fd5b8151801515811461405f575f80fd5b634e487b7160e01b5f52603260045260245ffd5b808201808211156142935761429361426c565b5f602082840312156142ef575f80fd5b815163ffffffff8116811461405f575f80fd5b80516bffffffffffffffffffffffff811681146140ab575f80fd5b5f6080828403121561432d575f80fd5b6040516080810181811067ffffffffffffffff8211171561435057614350613c4d565b60405261435c83614302565b815261436a60208401614302565b6020820152604083015161ffff81168114614383575f80fd5b60408201526143946060840161422c565b60608201529392505050565b5f80604083850312156143b1575f80fd5b505080516020909101519092909150565b80820281158282048414176142935761429361426c565b634e487b7160e01b5f52601260045260245ffd5b5f826143fb576143fb6143d9565b500490565b600181815b8085111561443a57815f19048211156144205761442061426c565b8085161561442d57918102915b93841c9390800290614405565b509250929050565b5f8261445057506001614293565b8161445c57505f614293565b8160018114614472576002811461447c57614498565b6001915050614293565b60ff84111561448d5761448d61426c565b50506001821b614293565b5060208310610133831016604e8410600b84101617156144bb575081810a614293565b6144c58383614400565b805f19048211156144d8576144d861426c565b029392505050565b5f61405f8383614442565b5f815180845260208085019450602084015f5b8381101561451a578151875295820195908201906001016144fe565b509495945050505050565b6001600160a01b0384168152606060208201525f61454660608301856144eb565b828103604084015261455881856144eb565b9695505050505050565b5f815180845260208085019450602084015f5b8381101561451a5781516001600160a01b031687529582019590820190600101614575565b604081525f6145ac6040830185614562565b82810360208401526145be81856144eb565b95945050505050565b5f67ffffffffffffffff808416806145e1576145e16143d9565b92169190910492915050565b67ffffffffffffffff82811682821603908082111561460e5761460e61426c565b5092915050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b0385168152836020820152608060408201525f61466a6080830185614615565b905082606083015295945050505050565b848152836020820152608060408201525f61466a6080830185614615565b5f600182016146aa576146aa61426c565b5060010190565b608081525f6146c36080830187614562565b82810360208401526146d581876144eb565b905082810360408401526146e98186614615565b91505082606083015295945050505050565b608080825285519082018190525f9060209060a0840190828901845b8281101561473357815184529284019290840190600101614717565b505050838103602085015261474881886144eb565b91505082810360408401526146e9818661461556fea2646970667358221220d5ad21b1e3c7f46f079be5de02f8abed25c59cb8c181f76db5750438335cf60864736f6c63430008190033", + "bytecode": "0x610120604052348015610010575f80fd5b50604051614c6a380380614c6a83398101604081905261002f91610226565b6002805460ff60a01b1933166001600160a81b031990911617600160a01b1760ff60a81b1916600160a91b1790556001600160a01b038916158061007a57506001600160a01b038816155b8061008c57506001600160a01b038716155b8061009e57506001600160a01b038616155b806100a7575084155b156100c55760405163d92e233d60e01b815260040160405180910390fd5b8315806100d0575082155b806100d9575081155b806100e2575080155b1561010057604051637c946ed760e01b815260040160405180910390fd5b61ffff82111561013357604051637ae5968560e01b81526004810183905261ffff60248201526044015b60405180910390fd5b6001600160601b0381111561016b57604051637ae5968560e01b8152600481018290526001600160601b03602482015260440161012a565b6001600160a01b0398891660c05260038054988a166001600160a01b0319998a1617905560048054978a16978916979097179096556005805495909816949096169390931790955560e0819052604080518082018252828152466020918201908152825180830194909452518383015281518084038301815260609093019091528151910120610100525f9390935560019290925560805260a0526102a5565b80516001600160a01b0381168114610221575f80fd5b919050565b5f805f805f805f805f6101208a8c03121561023f575f80fd5b6102488a61020b565b985061025660208b0161020b565b975061026460408b0161020b565b965061027260608b0161020b565b955060808a0151945060a08a0151935060c08a0151925060e08a015191506101008a015190509295985092959850929598565b60805160a05160c05160e051610100516148fc61036e5f395f81816103450152818161141701528181611d220152611dc901525f81816106710152818161144a015281816116c8015281816116fc01528181611d5901528181611ef3015281816131f0015261325601525f81816101ef015281816109c201528181610ac901528181610e5701528181610fa6015281816126f90152818161280601528181612b4601526135ae01525f818161063e01526118d101525f818161029c015261189d01526148fc5ff3fe6080604052600436106101da575f3560e01c806379bc81dd116100fd578063bc7d5c5c11610092578063dcb5ccc411610062578063dcb5ccc4146105f9578063e09177781461062d578063e6be59e714610660578063f4da12ba14610693575f80fd5b8063bc7d5c5c14610568578063d529779314610587578063d7accbcc146105a6578063d8bf69bf146105da575f80fd5b80639649a35c116100cd5780639649a35c146104eb578063a5edd4fc146104ff578063a6f9dae11461051e578063bb78678f1461053d575f80fd5b806379bc81dd1461046e5780638513e77d1461048d5780638833c205146104b85780638da5cb5b146104cc575f80fd5b80633c18d1dd1161017357806361d027b31161014357806361d027b3146103d257806363096509146103f157806363c4d28e14610410578063777e49c91461042f575f80fd5b80633c18d1dd146103345780634ac7251d146103675780635a55a482146103865780635c975abb146103a5575f80fd5b80632ad923dc116101ae5780632ad923dc146102cc5780632c0f3f29146102f757806334be5af41461030c5780633907196c14610321575f80fd5b806231d115146101de5780630d17db111461022e5780630d3241ee1461026c5780632a3bb6931461028b575b5f80fd5b3480156101e9575f80fd5b506102117f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610239575f80fd5b5061025c610248366004613ca3565b600a6020525f908152604090205460ff1681565b6040519015158152602001610225565b348015610277575f80fd5b50600554610211906001600160a01b031681565b348015610296575f80fd5b506102be7f000000000000000000000000000000000000000000000000000000000000000081565b604051908152602001610225565b3480156102d7575f80fd5b506102be6102e6366004613ca3565b60066020525f908152604090205481565b61030a610305366004613d6b565b6106a7565b005b348015610317575f80fd5b506102be60015481565b61030a61032f366004613ecb565b610bf4565b34801561033f575f80fd5b506102be7f000000000000000000000000000000000000000000000000000000000000000081565b348015610372575f80fd5b50600354610211906001600160a01b031681565b348015610391575f80fd5b5061030a6103a036600461404b565b61114b565b3480156103b0575f80fd5b506002546103c590600160a81b900460ff1681565b6040516102259190614088565b3480156103dd575f80fd5b50600454610211906001600160a01b031681565b3480156103fc575f80fd5b5061030a61040b3660046140ae565b611315565b34801561041b575f80fd5b5061030a61042a366004613ca3565b6113d4565b34801561043a575f80fd5b5061044e6104493660046140d3565b611681565b604080519485526020850193909352918301526060820152608001610225565b348015610479575f80fd5b5061030a61048836600461404b565b611bc6565b348015610498575f80fd5b506102be6104a7366004613ca3565b60076020525f908152604090205481565b3480156104c3575f80fd5b506102be5f5481565b3480156104d7575f80fd5b50600254610211906001600160a01b031681565b3480156104f6575f80fd5b5061030a611cd5565b34801561050a575f80fd5b5061030a610519366004613ca3565b612077565b348015610529575f80fd5b5061030a61053836600461411d565b612243565b348015610548575f80fd5b506102be610557366004613ca3565b60096020525f908152604090205481565b348015610573575f80fd5b5061030a610582366004614136565b612300565b348015610592575f80fd5b5061030a6105a1366004614156565b6123b0565b3480156105b1575f80fd5b506105c56105c0366004614196565b61251e565b60408051928352602083019190915201610225565b3480156105e5575f80fd5b5061030a6105f43660046141f6565b61295b565b348015610604575f80fd5b50610211610613366004613ca3565b60086020525f90815260409020546001600160a01b031681565b348015610638575f80fd5b506102be7f000000000000000000000000000000000000000000000000000000000000000081565b34801561066b575f80fd5b506102be7f000000000000000000000000000000000000000000000000000000000000000081565b34801561069e575f80fd5b506102be612abe565b6002546001600160a01b90910460ff1611156106d6576040516345f5ce8b60e11b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790555f83900361070a57604051637c946ed760e01b815260040160405180910390fd5b5f82900361072b5760405163d92e233d60e01b815260040160405180910390fd5b5f548085111561075d57604051637ae5968560e01b815260048101869052602481018290526044015b60405180910390fd5b60028054600160a81b900460ff169081600381111561077e5761077e614074565b148061079b5750600381600381111561079957610799614074565b145b8061081257506004805460408051635c975abb60e01b815290516001600160a01b0390921692635c975abb92828201926020929082900301815f875af11580156107e7573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061080b91906142a9565b60ff166002145b15610830576040516313d0ff5960e31b815260040160405180910390fd5b5f8581526008602090815260408083205481517fa8b2ae0200000000000000000000000000000000000000000000000000000000815291516001600160a01b039091169392849263a8b2ae0292600480830193928290030181865afa15801561089b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108bf91906142c2565b90505f805f806108d18c8c8c88611681565b5f81815260066020526040902082905592965090945092509050821561094b57600354604051635e148f0960e11b8152600481018590526001600160a01b039091169063bc291e12906024015f604051808303815f87803b158015610934575f80fd5b505af1158015610946573d5f803e3d5ffd5b505050505b5f8415610b8157505f8b815260096020526040902054849080156109a5578181106109845761097a82826142ed565b90505f9150610994565b61098e81836142ed565b91505f90505b5f8d81526009602052604090208190555b8115610b72576040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610a0f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a3391906142c2565b60048054604051637ff796ab60e01b815230928101929092525f6024830152604482018690529192506001600160a01b0390911690637ff796ab906064016020604051808303815f875af1158015610a8d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ab19190614306565b506040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610b16573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b3a91906142c2565b610b4491906142ed565b9050828114610b705760405163312b003360e01b81526004810182905260248101849052604401610754565b505b610b7f8d8d888e86612aea565b505b604080518d8152602081018d9052908101869052606081018290526080810185905233907f4095040bd441bb6761c0f983f93688032932a70ea67c45acf217522134d0e90c9060a00160405180910390a250506002805460ff60a01b1916600160a01b1790555050505050505050505050565b6002546001600160a01b90910460ff161115610c23576040516345f5ce8b60e11b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b179055610c4284848484612ce8565b5f5480861115610c6f57604051637ae5968560e01b81526004810187905260248101829052604401610754565b60028054600160a81b900460ff1690816003811115610c9057610c90614074565b1480610cad57506003816003811115610cab57610cab614074565b145b80610d2457506004805460408051635c975abb60e01b815290516001600160a01b0390921692635c975abb92828201926020929082900301815f875af1158015610cf9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d1d91906142a9565b60ff166002145b15610d42576040516313d0ff5960e31b815260040160405180910390fd5b6060806060610d528a8a8a612fe6565b825192955090935091505f9084906002908110610d7157610d71614325565b60200260200101511115610dfd5760035483516001600160a01b039091169063bc291e129085906002908110610da957610da9614325565b60200260200101516040518263ffffffff1660e01b8152600401610dcf91815260200190565b5f604051808303815f87803b158015610de6575f80fd5b505af1158015610df8573d5f803e3d5ffd5b505050505b5f835f81518110610e1057610e10614325565b60200260200101511115611094575f83600181518110610e3257610e32614325565b60200260200101511115611086576040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610ea4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ec891906142c2565b60045485519192506001600160a01b031690637ff796ab9030905f9088906001908110610ef757610ef7614325565b60209081029190910101516040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b039093166004840152602483019190915260448201526064016020604051808303815f875af1158015610f6a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f8e9190614306565b506040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610ff3573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061101791906142c2565b61102191906142ed565b90508360018151811061103657611036614325565b6020026020010151811461108457808460018151811061105857611058614325565b602002602001015160405163312b003360e01b8152600401610754929190918252602082015260400190565b505b6110948989848a858b613540565b336001600160a01b03167f4e8f98bab2ce9f2ab5649073958662ae3277689fdf749865832601431e3153ac8a8a85875f815181106110d4576110d4614325565b6020026020010151886001815181106110ef576110ef614325565b60200260200101518960028151811061110a5761110a614325565b6020026020010151604051611124969594939291906143ee565b60405180910390a250506002805460ff60a01b1916600160a01b1790555050505050505050565b6002546001600160a01b0316331461118b5760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b821580611196575081155b8061119f575080155b156111bd57604051637c946ed760e01b815260040160405180910390fd5b4683036111e057604051633881b68960e01b815260048101849052602401610754565b5f838152600960205260408120546111f9908490614484565b90506bffffffffffffffffffffffff81111561123d57604051637ae5968560e01b8152600481018290526bffffffffffffffffffffffff6024820152604401610754565b5f8481526009602090815260408083208490556008909152908190205490517fac65ded2000000000000000000000000000000000000000000000000000000008152600481018490526001600160a01b0390911690819063ac65ded2906024015f604051808303815f87803b1580156112b4575f80fd5b505af11580156112c6573d5f803e3d5ffd5b505060408051888152602081018890529081018590528592507f2192822efd68ddf583804c65675b73a59694e672cab1758eb6714613f932a97591506060015b60405180910390a25050505050565b6002546001600160a01b031633146113555760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b600280548291907fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16600160a81b83600381111561139557611395614074565b02179055507fa814f27828c0243d429ea8c7033cb10f0c825b9466fdc04f63e0cca26c28eb8a816040516113c99190614088565b60405180910390a150565b6005546001600160a01b031633146114145760055460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610754565b807f00000000000000000000000000000000000000000000000000000000000000000361147657604051636aba776560e11b81527f00000000000000000000000000000000000000000000000000000000000000006004820152602401610754565b600354604080517f14b19c5a00000000000000000000000000000000000000000000000000000000815290515f926001600160a01b0316916314b19c5a9160048083019260209291908290030181865afa1580156114d6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114fa9190614497565b60035463ffffffff9190911691505f906001600160a01b031663d4ee9f8d6115236001856142ed565b6040518263ffffffff1660e01b815260040161154191815260200190565b602060405180830381865afa15801561155c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061158091906142c2565b90505f60035f9054906101000a90046001600160a01b03166001600160a01b031663d2b3996f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115f79190614497565b63ffffffff1690505f62093a8061160e8385614484565b61161891906142ed565b905080421061164357604051637ae5968560e01b815242600482015260248101829052604401610754565b5f858152600760205260408082208690555186917f5a6a4aed2babbf3fe4cddce74151568eaac96f250cf910532f6528b1f6ee13d891a25050505050565b5f805f80865f036116a557604051637c946ed760e01b815260040160405180910390fd5b5f8690036116c65760405163d92e233d60e01b815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000000860361172857604051636aba776560e11b81527f00000000000000000000000000000000000000000000000000000000000000006004820152602401610754565b5060408051808201825286815260209081018881528251808301899052905181840152825180820384018152606090910190925281519101205f61176c828a613b56565b6005546040516317d5e89d60e31b8152600481018b9052602481018c90529195509192506001600160a01b039091169063beaf44e8906044015f604051808303815f87803b1580156117bc575f80fd5b505af11580156117ce573d5f803e3d5ffd5b5083925050505b83811015611bb9575f818152600a602052604090205460ff16611bb157600354604051631ddf133560e01b8152600481018390525f916001600160a01b031690631ddf133590602401608060405180830381865afa158015611839573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061185d91906144d5565b606081015190915060ff16156118fc57604081015161ffff16158015611893575060208101516bffffffffffffffffffffffff16155b156118f75761ffff7f00000000000000000000000000000000000000000000000000000000000000001660408201526bffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660208201525b611902565b50611bb1565b60035460405163d4ee9f8d60e01b8152600481018490525f916001600160a01b03169063d4ee9f8d90602401602060405180830381865afa158015611949573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061196d91906142c2565b600554604051630c88d47f60e41b8152600481018d9052602481018e9052604481018390529192505f9182916001600160a01b03169063c88d47f0906064016040805180830381865afa1580156119c6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119ea9190614558565b91509150805f03611a32575f858152600a60205260409020805460ff191660011790558351611a27906bffffffffffffffffffffffff168a614484565b985050505050611bb1565b83515f9081906bffffffffffffffffffffffff168184821115611a5f57611a5985836142ed565b90508491505b6040880151611a789061ffff16655af3107a400061457a565b861015611aae57670de0b6b3a764000086611a938484614484565b611a9d919061457a565b611aa791906145a5565b9250611b9c565b670de0b6b3a7640000611ac1878461457a565b611acb91906145a5565b9350670de0b6b3a7640000611ae0878361457a565b611aea91906145a5565b925087602001516bffffffffffffffffffffffff16915081841115611b2357611b1382856142ed565b611b1d9084614484565b92508193505b60128f1015611b8f575f8f6012611b3a91906142ed565b611b4590600a614698565b611b4f90866145a5565b90508f6012611b5e91906142ed565b611b6990600a614698565b611b73908261457a565b9050611b7f81866142ed565b611b899085614484565b90945092505b611b99848f614484565b9d505b611ba6838e614484565b9c5050505050505050505b6001016117d5565b5050945094509450949050565b5f838152600860205260409020546001600160a01b0316338114611c27576040517fdeeeedec0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0382166024820152604401610754565b5f84815260096020526040812054611c40908590614484565b90506bffffffffffffffffffffffff811115611c8457604051637ae5968560e01b8152600481018290526bffffffffffffffffffffffff6024820152604401610754565b5f85815260096020908152604091829020839055815187815290810186905290810182905283907f2192822efd68ddf583804c65675b73a59694e672cab1758eb6714613f932a97590606001611306565b6002546001600160a01b90910460ff161115611d04576040516345f5ce8b60e11b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790555f80548190611d47907f000000000000000000000000000000000000000000000000000000000000000090613b56565b6005546040516317d5e89d60e31b81527f000000000000000000000000000000000000000000000000000000000000000060048201524660248201529294509092506001600160a01b03169063beaf44e8906044015f604051808303815f87803b158015611db3575f80fd5b505af1158015611dc5573d5f803e3d5ffd5b50507f00000000000000000000000000000000000000000000000000000000000000005f90815260066020526040812084905591508390505b82811015611fb557600354604051631ddf133560e01b8152600481018390525f916001600160a01b031690631ddf133590602401608060405180830381865afa158015611e4d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e7191906144d5565b60035460405163d4ee9f8d60e01b8152600481018590529192505f916001600160a01b039091169063d4ee9f8d90602401602060405180830381865afa158015611ebd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ee191906142c2565b600554604051630c88d47f60e41b81527f00000000000000000000000000000000000000000000000000000000000000006004820152466024820152604481018390529192505f916001600160a01b039091169063c88d47f0906064016040805180830381865afa158015611f58573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f7c9190614558565b508351909150611f9b9082906bffffffffffffffffffffffff1661457a565b611fa59086614484565b9450505050806001019050611dfe565b50611fc8670de0b6b3a7640000826145a5565b9050801561202a57600354604051635e148f0960e11b8152600481018390526001600160a01b039091169063bc291e12906024015f604051808303815f87803b158015612013575f80fd5b505af1158015612025573d5f803e3d5ffd5b505050505b60405181815233907f2a8de497d698d6869cb0844411788378e76214d03a541eec6ba514b795d9f42e9060200160405180910390a250506002805460ff60a01b1916600160a01b17905550565b6005546001600160a01b031633146120b75760055460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610754565b60028054600160a81b900460ff16908160038111156120d8576120d8614074565b14806120f5575060038160038111156120f3576120f3614074565b145b8061216c57506004805460408051635c975abb60e01b815290516001600160a01b0390921692635c975abb92828201926020929082900301815f875af1158015612141573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061216591906142a9565b60ff166002145b1561218a576040516313d0ff5960e31b815260040160405180910390fd5b60035f9054906101000a90046001600160a01b03166001600160a01b03166314b19c5a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121da573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121fe9190614497565b5f8381526006602052604080822063ffffffff93909316909255905183917f5381b67b592d2dc84b61238222ab88ee04db3b3a082894a445c4e5cfa8ba11be91a25050565b6002546001600160a01b031633146122835760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b6001600160a01b0381166122aa5760405163d92e233d60e01b815260040160405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f4ffd725fc4a22075e9ec71c59edf9c38cdeb588a91b24fc5b61388c5be41282b905f90a250565b6002546001600160a01b031633146123405760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b81158061234b575080155b1561236957604051637c946ed760e01b815260040160405180910390fd5b5f829055600181905560408051838152602081018390527f61f6c4cc9665a257352c0b46189ffc2ae6fbbc11e155ff20901217ff203a517e91015b60405180910390a15050565b6002546001600160a01b031633146123f05760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b6001600160a01b03831615612453576003805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0385169081179091556040517f4672fe7e13cfb163442d0b729b5733fb3efafc66cbe3677eac9940eb41c284c2905f90a25b6001600160a01b038216156124b6576004805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0384169081179091556040517f7dae230f18360d76a040c81f050aa14eb9d6dc7901b20fc5d855e2a20fe814d1905f90a25b6001600160a01b03811615612519576005805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f04a606379838ed6fc83fd189eea9d1835b5eff05035c4b74622911ea2ae6b217905f90a25b505050565b5f806001600260149054906101000a900460ff1660ff161115612554576040516345f5ce8b60e11b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b179081905560ff600160a81b90910416600181600381111561258857612588614074565b14806125a5575060038160038111156125a3576125a3614074565b145b8061261c57506004805460408051635c975abb60e01b815290516001600160a01b0390921692635c975abb92828201926020929082900301815f875af11580156125f1573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061261591906142a9565b60ff166002145b1561263a576040516313d0ff5960e31b815260040160405180910390fd5b6003546040517f2e070f540000000000000000000000000000000000000000000000000000000081526001600160a01b0390911690632e070f5490612687903390899089906004016146a3565b60408051808303815f875af11580156126a2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126c69190614558565b90935091505f806126d78486614484565b11156128af575f831561276d576040516370a0823160e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015612746573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061276a91906142c2565b90505b60048054604051637ff796ab60e01b8152339281019290925260248201879052604482018690526001600160a01b031690637ff796ab906064016020604051808303815f875af11580156127c3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127e79190614306565b915083156128ad576040516370a0823160e01b815233600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015612853573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061287791906142c2565b61288191906142ed565b90508381146128ad5760405163312b003360e01b81526004810182905260248101859052604401610754565b505b806128f6576040517f942dc9da0000000000000000000000000000000000000000000000000000000081523360048201526024810185905260448101849052606401610754565b336001600160a01b03167fbe9ae4aaa6e41ee5c966cad91e78ec7202d0062fe8c9564b28629a614003cf828585898960405161293594939291906146e0565b60405180910390a250506002805460ff60a01b1916600160a01b17905590939092509050565b6002546001600160a01b0316331461299b5760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b815115806129ab57508051825114155b156129d657815181516040516308151c1160e41b815260048101929092526024820152604401610754565b5f5b8151811015612a8c578181815181106129f3576129f3614325565b60200260200101515f03612a1a57604051637c946ed760e01b815260040160405180910390fd5b828181518110612a2c57612a2c614325565b602002602001015160085f848481518110612a4957612a49614325565b602002602001015181526020019081526020015f205f6101000a8154816001600160a01b0302191690836001600160a01b031602179055508060010190506129d8565b507fe87460f6c400fa0166984512586d7bdf03a3230bbadf9651f27f08716dd77fa582826040516123a4929190614753565b6024612ad3600267ffffffffffffffff614780565b612add91906147a6565b67ffffffffffffffff1681565b5f858152600860205260409020546001600160a01b03168115612bb2576040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b038281166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303815f875af1158015612b8c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bb09190614306565b505b6024612bc7600267ffffffffffffffff614780565b612bd191906147a6565b67ffffffffffffffff168611612c64576040517fb2267a7b00000000000000000000000000000000000000000000000000000000815285906001600160a01b0383169063b2267a7b903490612c309085908a908a908a906004016147fc565b5f604051808303818588803b158015612c47575f80fd5b505af1158015612c59573d5f803e3d5ffd5b505050505050612ce0565b6040517f6585ecdc0000000000000000000000000000000000000000000000000000000081526001600160a01b03821690636585ecdc903490612cb1908990899089908990600401614834565b5f604051808303818588803b158015612cc8575f80fd5b505af1158015612cda573d5f803e3d5ffd5b50505050505b505050505050565b8251845114612d1757835183516040516308151c1160e41b815260048101929092526024820152604401610754565b8151845114612d4657835182516040516308151c1160e41b815260048101929092526024820152604401610754565b8051845114612d7557835181516040516308151c1160e41b815260048101929092526024820152604401610754565b5f805f5b8651811015612fbc57868181518110612d9457612d94614325565b60200260200101518310612dd857868181518110612db457612db4614325565b6020026020010151604051633881b68960e01b815260040161075491815260200190565b868181518110612dea57612dea614325565b60200260200101519250858181518110612e0657612e06614325565b6020026020010151515f03612e2e57604051637c946ed760e01b815260040160405180910390fd5b838181518110612e4057612e40614325565b602002602001015182612e539190614484565b91505f600154905080878381518110612e6e57612e6e614325565b6020026020010151511115612ebd57868281518110612e8f57612e8f614325565b60200260200101515181604051637ae5968560e01b8152600401610754929190918252602082015260400190565b5f805b888481518110612ed257612ed2614325565b602002602001015151811015612fae57888481518110612ef457612ef4614325565b60200260200101518181518110612f0d57612f0d614325565b60200260200101515f1c825f1c10612f6e57888481518110612f3157612f31614325565b60200260200101518181518110612f4a57612f4a614325565b6020026020010151604051636aba776560e11b815260040161075491815260200190565b888481518110612f8057612f80614325565b60200260200101518181518110612f9957612f99614325565b60200260200101519150806001019050612ec0565b505050806001019050612d79565b50803414612ce05760405163312b003360e01b815234600482015260248101829052604401610754565b6040805160038082526080820190925260609182918291602082018380368337019050509250845167ffffffffffffffff81111561302657613026613cba565b60405190808252806020026020018201604052801561305957816020015b60608152602001906001900390816130445790505b509150845167ffffffffffffffff81111561307657613076613cba565b60405190808252806020026020018201604052801561309f578160200160208202803683370190505b5090505f5b8551811015613536575f60085f8884815181106130c3576130c3614325565b602002602001015181526020019081526020015f205f9054906101000a90046001600160a01b031690505f816001600160a01b031663a8b2ae026040518163ffffffff1660e01b8152600401602060405180830381865afa15801561312a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061314e91906142c2565b905086838151811061316257613162614325565b60200260200101515167ffffffffffffffff81111561318357613183613cba565b6040519080825280602002602001820160405280156131ac578160200160208202803683370190505b508584815181106131bf576131bf614325565b60200260200101819052505f5b8784815181106131de576131de614325565b6020026020010151518110156133c5577f000000000000000000000000000000000000000000000000000000000000000088858151811061322157613221614325565b6020026020010151828151811061323a5761323a614325565b60200260200101510361328257604051636aba776560e11b81527f00000000000000000000000000000000000000000000000000000000000000006004820152602401610754565b5f805f806132dd8e8e8a8151811061329c5761329c614325565b60200260200101518e8b815181106132b6576132b6614325565b602002602001015188815181106132cf576132cf614325565b602002602001015189611681565b5f8181526006602052604090208290558d519397509195509350915084908b908a90811061330d5761330d614325565b6020026020010151868151811061332657613326614325565b6020026020010181815250508389898151811061334557613345614325565b602002602001018181516133599190614484565b9052508a5184908c905f9061337057613370614325565b602002602001018181516133849190614484565b9052508a5183908c90600290811061339e5761339e614325565b602002602001018181516133b29190614484565b90525050600190930192506131cc915050565b505f8484815181106133d9576133d9614325565b602002602001015111156134e8575f60095f8a86815181106133fd576133fd614325565b602002602001015181526020019081526020015f205490505f8111156134e65784848151811061342f5761342f614325565b602002602001015181106134885784848151811061344f5761344f614325565b60200260200101518161346291906142ed565b90505f85858151811061347757613477614325565b6020026020010181815250506134b6565b8085858151811061349b5761349b614325565b602002602001018181516134af91906142ed565b9052505f90505b8060095f8b87815181106134cc576134cc614325565b602002602001015181526020019081526020015f20819055505b505b8383815181106134fa576134fa614325565b60200260200101518660018151811061351557613515614325565b602002602001018181516135299190614484565b90525050506001016130a4565b5093509350939050565b5f5b8651811015613b4d575f60085f89848151811061356157613561614325565b602002602001015181526020019081526020015f205f9054906101000a90046001600160a01b031690505f84838151811061359e5761359e614325565b60200260200101511115613669577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb828685815181106135ee576135ee614325565b60200260200101516040518363ffffffff1660e01b81526004016136279291906001600160a01b03929092168252602082015260400190565b6020604051808303815f875af1158015613643573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136679190614306565b505b5f8088848151811061367d5761367d614325565b60200260200101515167ffffffffffffffff81111561369e5761369e613cba565b6040519080825280602002602001820160405280156136c7578160200160208202803683370190505b5090505f5b8985815181106136de576136de614325565b602002602001015151811015613760575f89868151811061370157613701614325565b6020026020010151828151811061371a5761371a614325565b6020026020010151111561375857600182828151811061373c5761373c614325565b9115156020928302919091019091015261375583614852565b92505b6001016136cc565b50815f0361377057505050613b45565b5f8267ffffffffffffffff81111561378a5761378a613cba565b6040519080825280602002602001820160405280156137b3578160200160208202803683370190505b5090505f8367ffffffffffffffff8111156137d0576137d0613cba565b6040519080825280602002602001820160405280156137f9578160200160208202803683370190505b5090505f805b8c888151811061381157613811614325565b6020026020010151518110156138f55784818151811061383357613833614325565b6020026020010151156138ed578c888151811061385257613852614325565b6020026020010151818151811061386b5761386b614325565b602002602001015184838151811061388557613885614325565b6020026020010181815250508b88815181106138a3576138a3614325565b602002602001015181815181106138bc576138bc614325565b60200260200101518383815181106138d6576138d6614325565b60209081029190910101526138ea82614852565b91505b6001016137ff565b50602461390b600267ffffffffffffffff614780565b61391591906147a6565b67ffffffffffffffff168d888151811061393157613931614325565b602002602001015111613a91575f835167ffffffffffffffff81111561395957613959613cba565b604051908082528060200260200182016040528015613982578160200160208202803683370190505b5090505f5b84518110156139de578481815181106139a2576139a2614325565b60200260200101515f1c8282815181106139be576139be614325565b6001600160a01b0390921660209283029190910190910152600101613987565b50866001600160a01b031663bde526618a8a81518110613a0057613a00614325565b602002602001015183868f8d81518110613a1c57613a1c614325565b60200260200101518f8e81518110613a3657613a36614325565b60200260200101516040518663ffffffff1660e01b8152600401613a5d949392919061486a565b5f604051808303818588803b158015613a74575f80fd5b505af1158015613a86573d5f803e3d5ffd5b505050505050613b3e565b856001600160a01b03166355442b59898981518110613ab257613ab2614325565b602002602001015185858e8c81518110613ace57613ace614325565b60200260200101518e8d81518110613ae857613ae8614325565b60200260200101516040518663ffffffff1660e01b8152600401613b0f94939291906148b4565b5f604051808303818588803b158015613b26575f80fd5b505af1158015613b38573d5f803e3d5ffd5b50505050505b5050505050505b600101613542565b50505050505050565b5f805f60035f9054906101000a90046001600160a01b03166001600160a01b03166314b19c5a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613ba9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613bcd9190614497565b5f86815260066020526040812054945063ffffffff919091169150839003613c0857604051637c946ed760e01b815260040160405180910390fd5b808303613c3d5782613c1b6001836142ed565b604051637ae5968560e01b815260048101929092526024820152604401610754565b5f858152600760205260409020548015801590613c5a5750808410155b15613c6b5783613c1b6001836142ed565b613c758585614484565b92505f81118015613c8557508083115b15613c8e578092505b81831115613c9a578192505b50509250929050565b5f60208284031215613cb3575f80fd5b5035919050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff81118282101715613cf757613cf7613cba565b604052919050565b5f82601f830112613d0e575f80fd5b813567ffffffffffffffff811115613d2857613d28613cba565b613d3b601f8201601f1916602001613cce565b818152846020838601011115613d4f575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f8060808587031215613d7e575f80fd5b843593506020850135925060408501359150606085013567ffffffffffffffff811115613da9575f80fd5b613db587828801613cff565b91505092959194509250565b5f67ffffffffffffffff821115613dda57613dda613cba565b5060051b60200190565b5f82601f830112613df3575f80fd5b81356020613e08613e0383613dc1565b613cce565b8083825260208201915060208460051b870101935086841115613e29575f80fd5b602086015b84811015613e455780358352918301918301613e2e565b509695505050505050565b5f82601f830112613e5f575f80fd5b81356020613e6f613e0383613dc1565b82815260059290921b84018101918181019086841115613e8d575f80fd5b8286015b84811015613e4557803567ffffffffffffffff811115613eaf575f80fd5b613ebd8986838b0101613cff565b845250918301918301613e91565b5f805f805f60a08688031215613edf575f80fd5b8535945067ffffffffffffffff8060208801351115613efc575f80fd5b613f0c8860208901358901613de4565b94508060408801351115613f1e575f80fd5b6040870135870188601f820112613f33575f80fd5b613f40613e038235613dc1565b81358082526020808301929160051b8401018b1015613f5d575f80fd5b602083015b6020843560051b850101811015613ff7578481351115613f80575f80fd5b803584018c603f820112613f92575f80fd5b613fa2613e036020830135613dc1565b602082810135808352908201919060051b83016040018f811115613fc4575f80fd5b6040840193505b80841015613fe6578335835260209384019390920191613fcb565b508552505060209283019201613f62565b5095505050606087013581101561400c575f80fd5b61401c8860608901358901613e50565b9250806080880135111561402e575f80fd5b5061403f8760808801358801613de4565b90509295509295909350565b5f805f6060848603121561405d575f80fd5b505081359360208301359350604090920135919050565b634e487b7160e01b5f52602160045260245ffd5b60208101600483106140a857634e487b7160e01b5f52602160045260245ffd5b91905290565b5f602082840312156140be575f80fd5b8135600481106140cc575f80fd5b9392505050565b5f805f80608085870312156140e6575f80fd5b5050823594602084013594506040840135936060013592509050565b80356001600160a01b0381168114614118575f80fd5b919050565b5f6020828403121561412d575f80fd5b6140cc82614102565b5f8060408385031215614147575f80fd5b50508035926020909101359150565b5f805f60608486031215614168575f80fd5b61417184614102565b925061417f60208501614102565b915061418d60408501614102565b90509250925092565b5f80604083850312156141a7575f80fd5b823567ffffffffffffffff808211156141be575f80fd5b6141ca86838701613de4565b935060208501359150808211156141df575f80fd5b506141ec85828601613de4565b9150509250929050565b5f8060408385031215614207575f80fd5b823567ffffffffffffffff8082111561421e575f80fd5b818501915085601f830112614231575f80fd5b81356020614241613e0383613dc1565b82815260059290921b8401810191818101908984111561425f575f80fd5b948201945b838610156142845761427586614102565b82529482019490820190614264565b965050860135925050808211156141df575f80fd5b805160ff81168114614118575f80fd5b5f602082840312156142b9575f80fd5b6140cc82614299565b5f602082840312156142d2575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b81810381811115614300576143006142d9565b92915050565b5f60208284031215614316575f80fd5b815180151581146140cc575f80fd5b634e487b7160e01b5f52603260045260245ffd5b5f815180845260208085019450602084015f5b838110156143685781518752958201959082019060010161434c565b509495945050505050565b5f82825180855260208086019550808260051b8401018186015f5b848110156143e157858303601f190189528151805180855290850190858501905f5b818110156143cc578351835292870192918701916001016143b0565b5050998501999350509083019060010161438e565b5090979650505050505050565b60c081525f61440060c0830189614339565b6020838203818501528189518084528284019150828160051b850101838c015f5b8381101561444f57601f1987840301855261443d838351614339565b94860194925090850190600101614421565b50508681036040880152614463818c614373565b606088019a909a525050505060808301949094525060a00152509392505050565b80820180821115614300576143006142d9565b5f602082840312156144a7575f80fd5b815163ffffffff811681146140cc575f80fd5b80516bffffffffffffffffffffffff81168114614118575f80fd5b5f608082840312156144e5575f80fd5b6040516080810181811067ffffffffffffffff8211171561450857614508613cba565b604052614514836144ba565b8152614522602084016144ba565b6020820152604083015161ffff8116811461453b575f80fd5b604082015261454c60608401614299565b60608201529392505050565b5f8060408385031215614569575f80fd5b505080516020909101519092909150565b8082028115828204841417614300576143006142d9565b634e487b7160e01b5f52601260045260245ffd5b5f826145b3576145b3614591565b500490565b600181815b808511156145f257815f19048211156145d8576145d86142d9565b808516156145e557918102915b93841c93908002906145bd565b509250929050565b5f8261460857506001614300565b8161461457505f614300565b816001811461462a576002811461463457614650565b6001915050614300565b60ff841115614645576146456142d9565b50506001821b614300565b5060208310610133831016604e8410600b8410161715614673575081810a614300565b61467d83836145b8565b805f1904821115614690576146906142d9565b029392505050565b5f6140cc83836145fa565b6001600160a01b0384168152606060208201525f6146c46060830185614339565b82810360408401526146d68185614339565b9695505050505050565b848152836020820152608060408201525f6146fe6080830185614339565b82810360608401526147108185614339565b979650505050505050565b5f815180845260208085019450602084015f5b838110156143685781516001600160a01b03168752958201959082019060010161472e565b604081525f614765604083018561471b565b82810360208401526147778185614339565b95945050505050565b5f67ffffffffffffffff8084168061479a5761479a614591565b92169190910492915050565b67ffffffffffffffff8281168282160390808211156147c7576147c76142d9565b5092915050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b0385168152836020820152608060408201525f61482360808301856147ce565b905082606083015295945050505050565b848152836020820152608060408201525f61482360808301856147ce565b5f60018201614863576148636142d9565b5060010190565b608081525f61487c608083018761471b565b828103602084015261488e8187614339565b905082810360408401526148a281866147ce565b91505082606083015295945050505050565b608081525f61487c608083018761433956fea26469706673582212204f62b365dfacc16118c8e0397d13c78fb01e19f895ea8e406a87973c6c961c4c64736f6c63430008190033", + "deployedBytecode": "0x6080604052600436106101da575f3560e01c806379bc81dd116100fd578063bc7d5c5c11610092578063dcb5ccc411610062578063dcb5ccc4146105f9578063e09177781461062d578063e6be59e714610660578063f4da12ba14610693575f80fd5b8063bc7d5c5c14610568578063d529779314610587578063d7accbcc146105a6578063d8bf69bf146105da575f80fd5b80639649a35c116100cd5780639649a35c146104eb578063a5edd4fc146104ff578063a6f9dae11461051e578063bb78678f1461053d575f80fd5b806379bc81dd1461046e5780638513e77d1461048d5780638833c205146104b85780638da5cb5b146104cc575f80fd5b80633c18d1dd1161017357806361d027b31161014357806361d027b3146103d257806363096509146103f157806363c4d28e14610410578063777e49c91461042f575f80fd5b80633c18d1dd146103345780634ac7251d146103675780635a55a482146103865780635c975abb146103a5575f80fd5b80632ad923dc116101ae5780632ad923dc146102cc5780632c0f3f29146102f757806334be5af41461030c5780633907196c14610321575f80fd5b806231d115146101de5780630d17db111461022e5780630d3241ee1461026c5780632a3bb6931461028b575b5f80fd5b3480156101e9575f80fd5b506102117f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610239575f80fd5b5061025c610248366004613ca3565b600a6020525f908152604090205460ff1681565b6040519015158152602001610225565b348015610277575f80fd5b50600554610211906001600160a01b031681565b348015610296575f80fd5b506102be7f000000000000000000000000000000000000000000000000000000000000000081565b604051908152602001610225565b3480156102d7575f80fd5b506102be6102e6366004613ca3565b60066020525f908152604090205481565b61030a610305366004613d6b565b6106a7565b005b348015610317575f80fd5b506102be60015481565b61030a61032f366004613ecb565b610bf4565b34801561033f575f80fd5b506102be7f000000000000000000000000000000000000000000000000000000000000000081565b348015610372575f80fd5b50600354610211906001600160a01b031681565b348015610391575f80fd5b5061030a6103a036600461404b565b61114b565b3480156103b0575f80fd5b506002546103c590600160a81b900460ff1681565b6040516102259190614088565b3480156103dd575f80fd5b50600454610211906001600160a01b031681565b3480156103fc575f80fd5b5061030a61040b3660046140ae565b611315565b34801561041b575f80fd5b5061030a61042a366004613ca3565b6113d4565b34801561043a575f80fd5b5061044e6104493660046140d3565b611681565b604080519485526020850193909352918301526060820152608001610225565b348015610479575f80fd5b5061030a61048836600461404b565b611bc6565b348015610498575f80fd5b506102be6104a7366004613ca3565b60076020525f908152604090205481565b3480156104c3575f80fd5b506102be5f5481565b3480156104d7575f80fd5b50600254610211906001600160a01b031681565b3480156104f6575f80fd5b5061030a611cd5565b34801561050a575f80fd5b5061030a610519366004613ca3565b612077565b348015610529575f80fd5b5061030a61053836600461411d565b612243565b348015610548575f80fd5b506102be610557366004613ca3565b60096020525f908152604090205481565b348015610573575f80fd5b5061030a610582366004614136565b612300565b348015610592575f80fd5b5061030a6105a1366004614156565b6123b0565b3480156105b1575f80fd5b506105c56105c0366004614196565b61251e565b60408051928352602083019190915201610225565b3480156105e5575f80fd5b5061030a6105f43660046141f6565b61295b565b348015610604575f80fd5b50610211610613366004613ca3565b60086020525f90815260409020546001600160a01b031681565b348015610638575f80fd5b506102be7f000000000000000000000000000000000000000000000000000000000000000081565b34801561066b575f80fd5b506102be7f000000000000000000000000000000000000000000000000000000000000000081565b34801561069e575f80fd5b506102be612abe565b6002546001600160a01b90910460ff1611156106d6576040516345f5ce8b60e11b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790555f83900361070a57604051637c946ed760e01b815260040160405180910390fd5b5f82900361072b5760405163d92e233d60e01b815260040160405180910390fd5b5f548085111561075d57604051637ae5968560e01b815260048101869052602481018290526044015b60405180910390fd5b60028054600160a81b900460ff169081600381111561077e5761077e614074565b148061079b5750600381600381111561079957610799614074565b145b8061081257506004805460408051635c975abb60e01b815290516001600160a01b0390921692635c975abb92828201926020929082900301815f875af11580156107e7573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061080b91906142a9565b60ff166002145b15610830576040516313d0ff5960e31b815260040160405180910390fd5b5f8581526008602090815260408083205481517fa8b2ae0200000000000000000000000000000000000000000000000000000000815291516001600160a01b039091169392849263a8b2ae0292600480830193928290030181865afa15801561089b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108bf91906142c2565b90505f805f806108d18c8c8c88611681565b5f81815260066020526040902082905592965090945092509050821561094b57600354604051635e148f0960e11b8152600481018590526001600160a01b039091169063bc291e12906024015f604051808303815f87803b158015610934575f80fd5b505af1158015610946573d5f803e3d5ffd5b505050505b5f8415610b8157505f8b815260096020526040902054849080156109a5578181106109845761097a82826142ed565b90505f9150610994565b61098e81836142ed565b91505f90505b5f8d81526009602052604090208190555b8115610b72576040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610a0f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a3391906142c2565b60048054604051637ff796ab60e01b815230928101929092525f6024830152604482018690529192506001600160a01b0390911690637ff796ab906064016020604051808303815f875af1158015610a8d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ab19190614306565b506040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610b16573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b3a91906142c2565b610b4491906142ed565b9050828114610b705760405163312b003360e01b81526004810182905260248101849052604401610754565b505b610b7f8d8d888e86612aea565b505b604080518d8152602081018d9052908101869052606081018290526080810185905233907f4095040bd441bb6761c0f983f93688032932a70ea67c45acf217522134d0e90c9060a00160405180910390a250506002805460ff60a01b1916600160a01b1790555050505050505050505050565b6002546001600160a01b90910460ff161115610c23576040516345f5ce8b60e11b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b179055610c4284848484612ce8565b5f5480861115610c6f57604051637ae5968560e01b81526004810187905260248101829052604401610754565b60028054600160a81b900460ff1690816003811115610c9057610c90614074565b1480610cad57506003816003811115610cab57610cab614074565b145b80610d2457506004805460408051635c975abb60e01b815290516001600160a01b0390921692635c975abb92828201926020929082900301815f875af1158015610cf9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d1d91906142a9565b60ff166002145b15610d42576040516313d0ff5960e31b815260040160405180910390fd5b6060806060610d528a8a8a612fe6565b825192955090935091505f9084906002908110610d7157610d71614325565b60200260200101511115610dfd5760035483516001600160a01b039091169063bc291e129085906002908110610da957610da9614325565b60200260200101516040518263ffffffff1660e01b8152600401610dcf91815260200190565b5f604051808303815f87803b158015610de6575f80fd5b505af1158015610df8573d5f803e3d5ffd5b505050505b5f835f81518110610e1057610e10614325565b60200260200101511115611094575f83600181518110610e3257610e32614325565b60200260200101511115611086576040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610ea4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ec891906142c2565b60045485519192506001600160a01b031690637ff796ab9030905f9088906001908110610ef757610ef7614325565b60209081029190910101516040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b039093166004840152602483019190915260448201526064016020604051808303815f875af1158015610f6a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f8e9190614306565b506040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610ff3573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061101791906142c2565b61102191906142ed565b90508360018151811061103657611036614325565b6020026020010151811461108457808460018151811061105857611058614325565b602002602001015160405163312b003360e01b8152600401610754929190918252602082015260400190565b505b6110948989848a858b613540565b336001600160a01b03167f4e8f98bab2ce9f2ab5649073958662ae3277689fdf749865832601431e3153ac8a8a85875f815181106110d4576110d4614325565b6020026020010151886001815181106110ef576110ef614325565b60200260200101518960028151811061110a5761110a614325565b6020026020010151604051611124969594939291906143ee565b60405180910390a250506002805460ff60a01b1916600160a01b1790555050505050505050565b6002546001600160a01b0316331461118b5760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b821580611196575081155b8061119f575080155b156111bd57604051637c946ed760e01b815260040160405180910390fd5b4683036111e057604051633881b68960e01b815260048101849052602401610754565b5f838152600960205260408120546111f9908490614484565b90506bffffffffffffffffffffffff81111561123d57604051637ae5968560e01b8152600481018290526bffffffffffffffffffffffff6024820152604401610754565b5f8481526009602090815260408083208490556008909152908190205490517fac65ded2000000000000000000000000000000000000000000000000000000008152600481018490526001600160a01b0390911690819063ac65ded2906024015f604051808303815f87803b1580156112b4575f80fd5b505af11580156112c6573d5f803e3d5ffd5b505060408051888152602081018890529081018590528592507f2192822efd68ddf583804c65675b73a59694e672cab1758eb6714613f932a97591506060015b60405180910390a25050505050565b6002546001600160a01b031633146113555760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b600280548291907fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16600160a81b83600381111561139557611395614074565b02179055507fa814f27828c0243d429ea8c7033cb10f0c825b9466fdc04f63e0cca26c28eb8a816040516113c99190614088565b60405180910390a150565b6005546001600160a01b031633146114145760055460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610754565b807f00000000000000000000000000000000000000000000000000000000000000000361147657604051636aba776560e11b81527f00000000000000000000000000000000000000000000000000000000000000006004820152602401610754565b600354604080517f14b19c5a00000000000000000000000000000000000000000000000000000000815290515f926001600160a01b0316916314b19c5a9160048083019260209291908290030181865afa1580156114d6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114fa9190614497565b60035463ffffffff9190911691505f906001600160a01b031663d4ee9f8d6115236001856142ed565b6040518263ffffffff1660e01b815260040161154191815260200190565b602060405180830381865afa15801561155c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061158091906142c2565b90505f60035f9054906101000a90046001600160a01b03166001600160a01b031663d2b3996f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115f79190614497565b63ffffffff1690505f62093a8061160e8385614484565b61161891906142ed565b905080421061164357604051637ae5968560e01b815242600482015260248101829052604401610754565b5f858152600760205260408082208690555186917f5a6a4aed2babbf3fe4cddce74151568eaac96f250cf910532f6528b1f6ee13d891a25050505050565b5f805f80865f036116a557604051637c946ed760e01b815260040160405180910390fd5b5f8690036116c65760405163d92e233d60e01b815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000000860361172857604051636aba776560e11b81527f00000000000000000000000000000000000000000000000000000000000000006004820152602401610754565b5060408051808201825286815260209081018881528251808301899052905181840152825180820384018152606090910190925281519101205f61176c828a613b56565b6005546040516317d5e89d60e31b8152600481018b9052602481018c90529195509192506001600160a01b039091169063beaf44e8906044015f604051808303815f87803b1580156117bc575f80fd5b505af11580156117ce573d5f803e3d5ffd5b5083925050505b83811015611bb9575f818152600a602052604090205460ff16611bb157600354604051631ddf133560e01b8152600481018390525f916001600160a01b031690631ddf133590602401608060405180830381865afa158015611839573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061185d91906144d5565b606081015190915060ff16156118fc57604081015161ffff16158015611893575060208101516bffffffffffffffffffffffff16155b156118f75761ffff7f00000000000000000000000000000000000000000000000000000000000000001660408201526bffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660208201525b611902565b50611bb1565b60035460405163d4ee9f8d60e01b8152600481018490525f916001600160a01b03169063d4ee9f8d90602401602060405180830381865afa158015611949573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061196d91906142c2565b600554604051630c88d47f60e41b8152600481018d9052602481018e9052604481018390529192505f9182916001600160a01b03169063c88d47f0906064016040805180830381865afa1580156119c6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119ea9190614558565b91509150805f03611a32575f858152600a60205260409020805460ff191660011790558351611a27906bffffffffffffffffffffffff168a614484565b985050505050611bb1565b83515f9081906bffffffffffffffffffffffff168184821115611a5f57611a5985836142ed565b90508491505b6040880151611a789061ffff16655af3107a400061457a565b861015611aae57670de0b6b3a764000086611a938484614484565b611a9d919061457a565b611aa791906145a5565b9250611b9c565b670de0b6b3a7640000611ac1878461457a565b611acb91906145a5565b9350670de0b6b3a7640000611ae0878361457a565b611aea91906145a5565b925087602001516bffffffffffffffffffffffff16915081841115611b2357611b1382856142ed565b611b1d9084614484565b92508193505b60128f1015611b8f575f8f6012611b3a91906142ed565b611b4590600a614698565b611b4f90866145a5565b90508f6012611b5e91906142ed565b611b6990600a614698565b611b73908261457a565b9050611b7f81866142ed565b611b899085614484565b90945092505b611b99848f614484565b9d505b611ba6838e614484565b9c5050505050505050505b6001016117d5565b5050945094509450949050565b5f838152600860205260409020546001600160a01b0316338114611c27576040517fdeeeedec0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0382166024820152604401610754565b5f84815260096020526040812054611c40908590614484565b90506bffffffffffffffffffffffff811115611c8457604051637ae5968560e01b8152600481018290526bffffffffffffffffffffffff6024820152604401610754565b5f85815260096020908152604091829020839055815187815290810186905290810182905283907f2192822efd68ddf583804c65675b73a59694e672cab1758eb6714613f932a97590606001611306565b6002546001600160a01b90910460ff161115611d04576040516345f5ce8b60e11b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790555f80548190611d47907f000000000000000000000000000000000000000000000000000000000000000090613b56565b6005546040516317d5e89d60e31b81527f000000000000000000000000000000000000000000000000000000000000000060048201524660248201529294509092506001600160a01b03169063beaf44e8906044015f604051808303815f87803b158015611db3575f80fd5b505af1158015611dc5573d5f803e3d5ffd5b50507f00000000000000000000000000000000000000000000000000000000000000005f90815260066020526040812084905591508390505b82811015611fb557600354604051631ddf133560e01b8152600481018390525f916001600160a01b031690631ddf133590602401608060405180830381865afa158015611e4d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e7191906144d5565b60035460405163d4ee9f8d60e01b8152600481018590529192505f916001600160a01b039091169063d4ee9f8d90602401602060405180830381865afa158015611ebd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ee191906142c2565b600554604051630c88d47f60e41b81527f00000000000000000000000000000000000000000000000000000000000000006004820152466024820152604481018390529192505f916001600160a01b039091169063c88d47f0906064016040805180830381865afa158015611f58573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f7c9190614558565b508351909150611f9b9082906bffffffffffffffffffffffff1661457a565b611fa59086614484565b9450505050806001019050611dfe565b50611fc8670de0b6b3a7640000826145a5565b9050801561202a57600354604051635e148f0960e11b8152600481018390526001600160a01b039091169063bc291e12906024015f604051808303815f87803b158015612013575f80fd5b505af1158015612025573d5f803e3d5ffd5b505050505b60405181815233907f2a8de497d698d6869cb0844411788378e76214d03a541eec6ba514b795d9f42e9060200160405180910390a250506002805460ff60a01b1916600160a01b17905550565b6005546001600160a01b031633146120b75760055460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610754565b60028054600160a81b900460ff16908160038111156120d8576120d8614074565b14806120f5575060038160038111156120f3576120f3614074565b145b8061216c57506004805460408051635c975abb60e01b815290516001600160a01b0390921692635c975abb92828201926020929082900301815f875af1158015612141573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061216591906142a9565b60ff166002145b1561218a576040516313d0ff5960e31b815260040160405180910390fd5b60035f9054906101000a90046001600160a01b03166001600160a01b03166314b19c5a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121da573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121fe9190614497565b5f8381526006602052604080822063ffffffff93909316909255905183917f5381b67b592d2dc84b61238222ab88ee04db3b3a082894a445c4e5cfa8ba11be91a25050565b6002546001600160a01b031633146122835760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b6001600160a01b0381166122aa5760405163d92e233d60e01b815260040160405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f4ffd725fc4a22075e9ec71c59edf9c38cdeb588a91b24fc5b61388c5be41282b905f90a250565b6002546001600160a01b031633146123405760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b81158061234b575080155b1561236957604051637c946ed760e01b815260040160405180910390fd5b5f829055600181905560408051838152602081018390527f61f6c4cc9665a257352c0b46189ffc2ae6fbbc11e155ff20901217ff203a517e91015b60405180910390a15050565b6002546001600160a01b031633146123f05760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b6001600160a01b03831615612453576003805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0385169081179091556040517f4672fe7e13cfb163442d0b729b5733fb3efafc66cbe3677eac9940eb41c284c2905f90a25b6001600160a01b038216156124b6576004805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0384169081179091556040517f7dae230f18360d76a040c81f050aa14eb9d6dc7901b20fc5d855e2a20fe814d1905f90a25b6001600160a01b03811615612519576005805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f04a606379838ed6fc83fd189eea9d1835b5eff05035c4b74622911ea2ae6b217905f90a25b505050565b5f806001600260149054906101000a900460ff1660ff161115612554576040516345f5ce8b60e11b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b179081905560ff600160a81b90910416600181600381111561258857612588614074565b14806125a5575060038160038111156125a3576125a3614074565b145b8061261c57506004805460408051635c975abb60e01b815290516001600160a01b0390921692635c975abb92828201926020929082900301815f875af11580156125f1573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061261591906142a9565b60ff166002145b1561263a576040516313d0ff5960e31b815260040160405180910390fd5b6003546040517f2e070f540000000000000000000000000000000000000000000000000000000081526001600160a01b0390911690632e070f5490612687903390899089906004016146a3565b60408051808303815f875af11580156126a2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126c69190614558565b90935091505f806126d78486614484565b11156128af575f831561276d576040516370a0823160e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015612746573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061276a91906142c2565b90505b60048054604051637ff796ab60e01b8152339281019290925260248201879052604482018690526001600160a01b031690637ff796ab906064016020604051808303815f875af11580156127c3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127e79190614306565b915083156128ad576040516370a0823160e01b815233600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015612853573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061287791906142c2565b61288191906142ed565b90508381146128ad5760405163312b003360e01b81526004810182905260248101859052604401610754565b505b806128f6576040517f942dc9da0000000000000000000000000000000000000000000000000000000081523360048201526024810185905260448101849052606401610754565b336001600160a01b03167fbe9ae4aaa6e41ee5c966cad91e78ec7202d0062fe8c9564b28629a614003cf828585898960405161293594939291906146e0565b60405180910390a250506002805460ff60a01b1916600160a01b17905590939092509050565b6002546001600160a01b0316331461299b5760025460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610754565b815115806129ab57508051825114155b156129d657815181516040516308151c1160e41b815260048101929092526024820152604401610754565b5f5b8151811015612a8c578181815181106129f3576129f3614325565b60200260200101515f03612a1a57604051637c946ed760e01b815260040160405180910390fd5b828181518110612a2c57612a2c614325565b602002602001015160085f848481518110612a4957612a49614325565b602002602001015181526020019081526020015f205f6101000a8154816001600160a01b0302191690836001600160a01b031602179055508060010190506129d8565b507fe87460f6c400fa0166984512586d7bdf03a3230bbadf9651f27f08716dd77fa582826040516123a4929190614753565b6024612ad3600267ffffffffffffffff614780565b612add91906147a6565b67ffffffffffffffff1681565b5f858152600860205260409020546001600160a01b03168115612bb2576040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b038281166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303815f875af1158015612b8c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bb09190614306565b505b6024612bc7600267ffffffffffffffff614780565b612bd191906147a6565b67ffffffffffffffff168611612c64576040517fb2267a7b00000000000000000000000000000000000000000000000000000000815285906001600160a01b0383169063b2267a7b903490612c309085908a908a908a906004016147fc565b5f604051808303818588803b158015612c47575f80fd5b505af1158015612c59573d5f803e3d5ffd5b505050505050612ce0565b6040517f6585ecdc0000000000000000000000000000000000000000000000000000000081526001600160a01b03821690636585ecdc903490612cb1908990899089908990600401614834565b5f604051808303818588803b158015612cc8575f80fd5b505af1158015612cda573d5f803e3d5ffd5b50505050505b505050505050565b8251845114612d1757835183516040516308151c1160e41b815260048101929092526024820152604401610754565b8151845114612d4657835182516040516308151c1160e41b815260048101929092526024820152604401610754565b8051845114612d7557835181516040516308151c1160e41b815260048101929092526024820152604401610754565b5f805f5b8651811015612fbc57868181518110612d9457612d94614325565b60200260200101518310612dd857868181518110612db457612db4614325565b6020026020010151604051633881b68960e01b815260040161075491815260200190565b868181518110612dea57612dea614325565b60200260200101519250858181518110612e0657612e06614325565b6020026020010151515f03612e2e57604051637c946ed760e01b815260040160405180910390fd5b838181518110612e4057612e40614325565b602002602001015182612e539190614484565b91505f600154905080878381518110612e6e57612e6e614325565b6020026020010151511115612ebd57868281518110612e8f57612e8f614325565b60200260200101515181604051637ae5968560e01b8152600401610754929190918252602082015260400190565b5f805b888481518110612ed257612ed2614325565b602002602001015151811015612fae57888481518110612ef457612ef4614325565b60200260200101518181518110612f0d57612f0d614325565b60200260200101515f1c825f1c10612f6e57888481518110612f3157612f31614325565b60200260200101518181518110612f4a57612f4a614325565b6020026020010151604051636aba776560e11b815260040161075491815260200190565b888481518110612f8057612f80614325565b60200260200101518181518110612f9957612f99614325565b60200260200101519150806001019050612ec0565b505050806001019050612d79565b50803414612ce05760405163312b003360e01b815234600482015260248101829052604401610754565b6040805160038082526080820190925260609182918291602082018380368337019050509250845167ffffffffffffffff81111561302657613026613cba565b60405190808252806020026020018201604052801561305957816020015b60608152602001906001900390816130445790505b509150845167ffffffffffffffff81111561307657613076613cba565b60405190808252806020026020018201604052801561309f578160200160208202803683370190505b5090505f5b8551811015613536575f60085f8884815181106130c3576130c3614325565b602002602001015181526020019081526020015f205f9054906101000a90046001600160a01b031690505f816001600160a01b031663a8b2ae026040518163ffffffff1660e01b8152600401602060405180830381865afa15801561312a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061314e91906142c2565b905086838151811061316257613162614325565b60200260200101515167ffffffffffffffff81111561318357613183613cba565b6040519080825280602002602001820160405280156131ac578160200160208202803683370190505b508584815181106131bf576131bf614325565b60200260200101819052505f5b8784815181106131de576131de614325565b6020026020010151518110156133c5577f000000000000000000000000000000000000000000000000000000000000000088858151811061322157613221614325565b6020026020010151828151811061323a5761323a614325565b60200260200101510361328257604051636aba776560e11b81527f00000000000000000000000000000000000000000000000000000000000000006004820152602401610754565b5f805f806132dd8e8e8a8151811061329c5761329c614325565b60200260200101518e8b815181106132b6576132b6614325565b602002602001015188815181106132cf576132cf614325565b602002602001015189611681565b5f8181526006602052604090208290558d519397509195509350915084908b908a90811061330d5761330d614325565b6020026020010151868151811061332657613326614325565b6020026020010181815250508389898151811061334557613345614325565b602002602001018181516133599190614484565b9052508a5184908c905f9061337057613370614325565b602002602001018181516133849190614484565b9052508a5183908c90600290811061339e5761339e614325565b602002602001018181516133b29190614484565b90525050600190930192506131cc915050565b505f8484815181106133d9576133d9614325565b602002602001015111156134e8575f60095f8a86815181106133fd576133fd614325565b602002602001015181526020019081526020015f205490505f8111156134e65784848151811061342f5761342f614325565b602002602001015181106134885784848151811061344f5761344f614325565b60200260200101518161346291906142ed565b90505f85858151811061347757613477614325565b6020026020010181815250506134b6565b8085858151811061349b5761349b614325565b602002602001018181516134af91906142ed565b9052505f90505b8060095f8b87815181106134cc576134cc614325565b602002602001015181526020019081526020015f20819055505b505b8383815181106134fa576134fa614325565b60200260200101518660018151811061351557613515614325565b602002602001018181516135299190614484565b90525050506001016130a4565b5093509350939050565b5f5b8651811015613b4d575f60085f89848151811061356157613561614325565b602002602001015181526020019081526020015f205f9054906101000a90046001600160a01b031690505f84838151811061359e5761359e614325565b60200260200101511115613669577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb828685815181106135ee576135ee614325565b60200260200101516040518363ffffffff1660e01b81526004016136279291906001600160a01b03929092168252602082015260400190565b6020604051808303815f875af1158015613643573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136679190614306565b505b5f8088848151811061367d5761367d614325565b60200260200101515167ffffffffffffffff81111561369e5761369e613cba565b6040519080825280602002602001820160405280156136c7578160200160208202803683370190505b5090505f5b8985815181106136de576136de614325565b602002602001015151811015613760575f89868151811061370157613701614325565b6020026020010151828151811061371a5761371a614325565b6020026020010151111561375857600182828151811061373c5761373c614325565b9115156020928302919091019091015261375583614852565b92505b6001016136cc565b50815f0361377057505050613b45565b5f8267ffffffffffffffff81111561378a5761378a613cba565b6040519080825280602002602001820160405280156137b3578160200160208202803683370190505b5090505f8367ffffffffffffffff8111156137d0576137d0613cba565b6040519080825280602002602001820160405280156137f9578160200160208202803683370190505b5090505f805b8c888151811061381157613811614325565b6020026020010151518110156138f55784818151811061383357613833614325565b6020026020010151156138ed578c888151811061385257613852614325565b6020026020010151818151811061386b5761386b614325565b602002602001015184838151811061388557613885614325565b6020026020010181815250508b88815181106138a3576138a3614325565b602002602001015181815181106138bc576138bc614325565b60200260200101518383815181106138d6576138d6614325565b60209081029190910101526138ea82614852565b91505b6001016137ff565b50602461390b600267ffffffffffffffff614780565b61391591906147a6565b67ffffffffffffffff168d888151811061393157613931614325565b602002602001015111613a91575f835167ffffffffffffffff81111561395957613959613cba565b604051908082528060200260200182016040528015613982578160200160208202803683370190505b5090505f5b84518110156139de578481815181106139a2576139a2614325565b60200260200101515f1c8282815181106139be576139be614325565b6001600160a01b0390921660209283029190910190910152600101613987565b50866001600160a01b031663bde526618a8a81518110613a0057613a00614325565b602002602001015183868f8d81518110613a1c57613a1c614325565b60200260200101518f8e81518110613a3657613a36614325565b60200260200101516040518663ffffffff1660e01b8152600401613a5d949392919061486a565b5f604051808303818588803b158015613a74575f80fd5b505af1158015613a86573d5f803e3d5ffd5b505050505050613b3e565b856001600160a01b03166355442b59898981518110613ab257613ab2614325565b602002602001015185858e8c81518110613ace57613ace614325565b60200260200101518e8d81518110613ae857613ae8614325565b60200260200101516040518663ffffffff1660e01b8152600401613b0f94939291906148b4565b5f604051808303818588803b158015613b26575f80fd5b505af1158015613b38573d5f803e3d5ffd5b50505050505b5050505050505b600101613542565b50505050505050565b5f805f60035f9054906101000a90046001600160a01b03166001600160a01b03166314b19c5a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613ba9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613bcd9190614497565b5f86815260066020526040812054945063ffffffff919091169150839003613c0857604051637c946ed760e01b815260040160405180910390fd5b808303613c3d5782613c1b6001836142ed565b604051637ae5968560e01b815260048101929092526024820152604401610754565b5f858152600760205260409020548015801590613c5a5750808410155b15613c6b5783613c1b6001836142ed565b613c758585614484565b92505f81118015613c8557508083115b15613c8e578092505b81831115613c9a578192505b50509250929050565b5f60208284031215613cb3575f80fd5b5035919050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff81118282101715613cf757613cf7613cba565b604052919050565b5f82601f830112613d0e575f80fd5b813567ffffffffffffffff811115613d2857613d28613cba565b613d3b601f8201601f1916602001613cce565b818152846020838601011115613d4f575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f8060808587031215613d7e575f80fd5b843593506020850135925060408501359150606085013567ffffffffffffffff811115613da9575f80fd5b613db587828801613cff565b91505092959194509250565b5f67ffffffffffffffff821115613dda57613dda613cba565b5060051b60200190565b5f82601f830112613df3575f80fd5b81356020613e08613e0383613dc1565b613cce565b8083825260208201915060208460051b870101935086841115613e29575f80fd5b602086015b84811015613e455780358352918301918301613e2e565b509695505050505050565b5f82601f830112613e5f575f80fd5b81356020613e6f613e0383613dc1565b82815260059290921b84018101918181019086841115613e8d575f80fd5b8286015b84811015613e4557803567ffffffffffffffff811115613eaf575f80fd5b613ebd8986838b0101613cff565b845250918301918301613e91565b5f805f805f60a08688031215613edf575f80fd5b8535945067ffffffffffffffff8060208801351115613efc575f80fd5b613f0c8860208901358901613de4565b94508060408801351115613f1e575f80fd5b6040870135870188601f820112613f33575f80fd5b613f40613e038235613dc1565b81358082526020808301929160051b8401018b1015613f5d575f80fd5b602083015b6020843560051b850101811015613ff7578481351115613f80575f80fd5b803584018c603f820112613f92575f80fd5b613fa2613e036020830135613dc1565b602082810135808352908201919060051b83016040018f811115613fc4575f80fd5b6040840193505b80841015613fe6578335835260209384019390920191613fcb565b508552505060209283019201613f62565b5095505050606087013581101561400c575f80fd5b61401c8860608901358901613e50565b9250806080880135111561402e575f80fd5b5061403f8760808801358801613de4565b90509295509295909350565b5f805f6060848603121561405d575f80fd5b505081359360208301359350604090920135919050565b634e487b7160e01b5f52602160045260245ffd5b60208101600483106140a857634e487b7160e01b5f52602160045260245ffd5b91905290565b5f602082840312156140be575f80fd5b8135600481106140cc575f80fd5b9392505050565b5f805f80608085870312156140e6575f80fd5b5050823594602084013594506040840135936060013592509050565b80356001600160a01b0381168114614118575f80fd5b919050565b5f6020828403121561412d575f80fd5b6140cc82614102565b5f8060408385031215614147575f80fd5b50508035926020909101359150565b5f805f60608486031215614168575f80fd5b61417184614102565b925061417f60208501614102565b915061418d60408501614102565b90509250925092565b5f80604083850312156141a7575f80fd5b823567ffffffffffffffff808211156141be575f80fd5b6141ca86838701613de4565b935060208501359150808211156141df575f80fd5b506141ec85828601613de4565b9150509250929050565b5f8060408385031215614207575f80fd5b823567ffffffffffffffff8082111561421e575f80fd5b818501915085601f830112614231575f80fd5b81356020614241613e0383613dc1565b82815260059290921b8401810191818101908984111561425f575f80fd5b948201945b838610156142845761427586614102565b82529482019490820190614264565b965050860135925050808211156141df575f80fd5b805160ff81168114614118575f80fd5b5f602082840312156142b9575f80fd5b6140cc82614299565b5f602082840312156142d2575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b81810381811115614300576143006142d9565b92915050565b5f60208284031215614316575f80fd5b815180151581146140cc575f80fd5b634e487b7160e01b5f52603260045260245ffd5b5f815180845260208085019450602084015f5b838110156143685781518752958201959082019060010161434c565b509495945050505050565b5f82825180855260208086019550808260051b8401018186015f5b848110156143e157858303601f190189528151805180855290850190858501905f5b818110156143cc578351835292870192918701916001016143b0565b5050998501999350509083019060010161438e565b5090979650505050505050565b60c081525f61440060c0830189614339565b6020838203818501528189518084528284019150828160051b850101838c015f5b8381101561444f57601f1987840301855261443d838351614339565b94860194925090850190600101614421565b50508681036040880152614463818c614373565b606088019a909a525050505060808301949094525060a00152509392505050565b80820180821115614300576143006142d9565b5f602082840312156144a7575f80fd5b815163ffffffff811681146140cc575f80fd5b80516bffffffffffffffffffffffff81168114614118575f80fd5b5f608082840312156144e5575f80fd5b6040516080810181811067ffffffffffffffff8211171561450857614508613cba565b604052614514836144ba565b8152614522602084016144ba565b6020820152604083015161ffff8116811461453b575f80fd5b604082015261454c60608401614299565b60608201529392505050565b5f8060408385031215614569575f80fd5b505080516020909101519092909150565b8082028115828204841417614300576143006142d9565b634e487b7160e01b5f52601260045260245ffd5b5f826145b3576145b3614591565b500490565b600181815b808511156145f257815f19048211156145d8576145d86142d9565b808516156145e557918102915b93841c93908002906145bd565b509250929050565b5f8261460857506001614300565b8161461457505f614300565b816001811461462a576002811461463457614650565b6001915050614300565b60ff841115614645576146456142d9565b50506001821b614300565b5060208310610133831016604e8410600b8410161715614673575081810a614300565b61467d83836145b8565b805f1904821115614690576146906142d9565b029392505050565b5f6140cc83836145fa565b6001600160a01b0384168152606060208201525f6146c46060830185614339565b82810360408401526146d68185614339565b9695505050505050565b848152836020820152608060408201525f6146fe6080830185614339565b82810360608401526147108185614339565b979650505050505050565b5f815180845260208085019450602084015f5b838110156143685781516001600160a01b03168752958201959082019060010161472e565b604081525f614765604083018561471b565b82810360208401526147778185614339565b95945050505050565b5f67ffffffffffffffff8084168061479a5761479a614591565b92169190910492915050565b67ffffffffffffffff8281168282160390808211156147c7576147c76142d9565b5092915050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b0385168152836020820152608060408201525f61482360808301856147ce565b905082606083015295945050505050565b848152836020820152608060408201525f61482360808301856147ce565b5f60018201614863576148636142d9565b5060010190565b608081525f61487c608083018761471b565b828103602084015261488e8187614339565b905082810360408401526148a281866147ce565b91505082606083015295945050505050565b608081525f61487c608083018761433956fea26469706673582212204f62b365dfacc16118c8e0397d13c78fb01e19f895ea8e406a87973c6c961c4c64736f6c63430008190033", "linkReferences": {}, "deployedLinkReferences": {} } diff --git a/audits/README.md b/audits/README.md index 6c263fec..85dc3e82 100644 --- a/audits/README.md +++ b/audits/README.md @@ -10,7 +10,9 @@ An internal audit with a focus on depository implementation v.1.0.1 is located i An internal audit with a focus on PoAA Staking is located in this folder: [internal audit 4](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/audits/internal4). -An internal audit with a focus on AIP-1 (bonding) is located in this folder: [internal audit 5](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/audits/internal5). +An internal audit with a focus on PoAA Staking fixing after C4A is located in this folder: [internal audit 5](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/audits/internal5). + +An internal audit with a focus on AIP-1 (bonding) is located in this folder: [internal audit 6](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/audits/internal6). ### External audit Audit reports: [v1](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/audits/Autonolas%20Tokenomics%20Smart%20Contract%20Audit.pdf) and [v2](https://sourcehat.com/audits/AutonolasTokenomics/). diff --git a/audits/internal5/README.md b/audits/internal5/README.md index d0b56f3f..b9cafd51 100644 --- a/audits/internal5/README.md +++ b/audits/internal5/README.md @@ -1,61 +1,130 @@ # Internal audit of autonolas-tokenomics The review has been performed based on the contract code in the following repository:
`https://github.com/valory-xyz/autonolas-tokenomics`
-commit: `12101b49a2dcdc7a7378f416ddb1611e10459b67` or `tag: v1.3.0-pre-internal-audit`
+commit: `357539f11e3386c18bc9370d4cd20066c7fc0599` or `tag: v1.2.2-pre-internal-audit`
## Objectives -The audit focused on contracts related to AIP-1 implementation (Bonding) in this repo. +The audit focused on fixing contracts related to PoAA Staking after C4A. -### Flatten version -Flatten version of contracts. [contracts](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/audits/internal5/analysis/contracts) +### Coverage +Hardhat coverage has been performed before the audit and can be found here: +```sh +---------------------------------|----------|----------|----------|----------|----------------| +File | % Stmts | % Branch | % Funcs | % Lines |Uncovered Lines | +---------------------------------|----------|----------|----------|----------|----------------| + contracts/ | 99.64 | 96.79 | 100 | 98.09 | | -### Coverage: N/A -In this commit, the tests are in the process of being reworked and therefore the coverage section does not make sense. + Dispenser.sol | 98.94 | 90.65 | 100 | 93.86 |... 0,1188,1246 | -### Storage and proxy -Using sol2uml tools: https://github.com/naddison36/sol2uml
+ contracts/staking/ | 97.52 | 90.83 | 98.36 | 93.97 | | + ArbitrumDepositProcessorL1.sol | 100 | 96.15 | 100 | 97.14 | 157 | + ArbitrumTargetDispenserL2.sol | 100 | 100 | 100 | 100 | | + DefaultDepositProcessorL1.sol | 100 | 90.63 | 100 | 94.83 | 134,227,235 | + DefaultTargetDispenserL2.sol | 97.5 | 87.8 | 100 | 92.52 |... 459,489,511 | + EthereumDepositProcessor.sol | 85.71 | 88.89 | 100 | 86.11 |... 109,112,114 | + GnosisDepositProcessorL1.sol | 100 | 100 | 100 | 100 | | + GnosisTargetDispenserL2.sol | 100 | 100 | 100 | 100 | | + OptimismDepositProcessorL1.sol | 100 | 100 | 100 | 100 | | + OptimismTargetDispenserL2.sol | 100 | 100 | 100 | 100 | | + PolygonDepositProcessorL1.sol | 91.67 | 80 | 80 | 84.21 | 97,105,110 | + PolygonTargetDispenserL2.sol | 100 | 50 | 100 | 81.82 | 68,73 | + WormholeDepositProcessorL1.sol | 100 | 100 | 100 | 100 | | + WormholeTargetDispenserL2.sol | 100 | 91.67 | 100 | 96.77 | 114 | + +---------------------------------|----------|----------|----------|----------|----------------| ``` -npm link sol2uml --only=production -sol2uml storage contracts/ -f png -c Tokenomics -o audits/internal4/analysis/storage -Generated png file audits/internal5/analysis/storage/Tokenomics.png -``` -[Tokenomics-storage](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/audits/internal5/analysis/storage/Tokenomics.png)
-current deployed:
-[Tokenomics-storage-current](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/audits/internal4/analysis/storage/Tokenomics.png)
-The new slot allocation for Tokenomics (critical as proxy pattern) does not affect the previous one. - -### Security issues. -#### Problems found instrumentally -Several checks are obtained automatically. They are commented. Some issues found need to be fixed.
-All automatic warnings are listed in the following file, concerns of which we address in more detail below:
-[slither-full](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/audits/internal5/analysis/slither_full.txt)
- -#### Issue -1. minOLASLeftoverAmount never setupped/updated -``` - // Minimum amount of supply such that any value below is given to the bonding account in order to close the product - uint256 public minOLASLeftoverAmount; -``` -2. Reentrancy after ERC721 "safe" mint in deposit +Please, pay attention.
+[x] Noted. Missing 100% is not an obvious problem. + +#### Checking the corrections made after C4A +##### Bridging +67. Withheld tokens could become unsynchronized by using retry-ability of bridging protocols #67 +https://github.com/code-423n4/2024-05-olas-findings/issues/67 +[x] fixed + +54. OptimismTargetDispenserL2:syncWithheldTokens is callable with no sanity check on payloads and can lead to permanent loss of withheld token amounts #54 +https://github.com/code-423n4/2024-05-olas-findings/issues/54 +20. Users will lose all ETH sent as cost parameter in transactions to and from Optimism #20 +https://github.com/code-423n4/2024-05-olas-findings/issues/20 +4. The msg.value - cost for multiple cross-chain bridges are not refunded to users #4 +https://github.com/code-423n4/2024-05-olas-findings/issues/4 +[x] fixed + +32. Refunds for unconsumed gas will be lost due to incorrect refund chain ID #32 +https://github.com/code-423n4/2024-05-olas-findings/issues/32 +[x] fixed + +29. Attacker can cancel claimed staking incentives on Arbitrum #29 +https://github.com/code-423n4/2024-05-olas-findings/issues/29 +[x] fixed + +26. Non-normalized amounts sent via Wormhole lead to failure to redeem incentives #26 +https://github.com/code-423n4/2024-05-olas-findings/issues/26 +[x] fixed + +22. Arbitrary tokens and data can be bridged to GnosisTargetDispenserL2 to manipulate staking incentives #22 +https://github.com/code-423n4/2024-05-olas-findings/issues/22 +[x] fixed + +5. The refundAccount is erroneously set to msg.sender instead of tx.origin when refundAccount specified as address(0) #5 +https://github.com/code-423n4/2024-05-olas-findings/issues/5 +[x] fixed + +##### Dispenser +61. Loss of incentives if total weight in an epoch is zero #61 +https://github.com/code-423n4/2024-05-olas-findings/issues/61 +[x] fixed + +56. In retain function checkpoint nominee function is not called which can cause zero amount of tokens being retained. #56 +https://github.com/code-423n4/2024-05-olas-findings/issues/56 +[x] fixed + +38. Removed nominee doesn't receive staking incentives for the epoch in which they were removed which is against the intended behaviour #38 +https://github.com/code-423n4/2024-05-olas-findings/issues/38 +[x] fixed + +27. Unauthorized claiming of staking incentives for retainer #27 +https://github.com/code-423n4/2024-05-olas-findings/issues/27 +[x] fixed + +##### No need to change the code, just add information to the documentation +59. Changing VoteWeighting contract can result in lost staking incentives #59 +https://github.com/code-423n4/2024-05-olas-findings/issues/59 +[x] fixed + +#### Low issue +107. QA Report #107 +https://github.com/code-423n4/2024-05-olas-findings/issues/107 ``` - External calls: - - _safeMint(msg.sender,bondId) (Depository-flatten.sol#891) - - require(bool,string)(ERC721TokenReceiver(to).onERC721Received(msg.sender,address(0),id,) == ERC721TokenReceiver.onERC721Received.selector,UNSAFE_RECIPIENT) (Depository-flatten.sol#461-465) - After adding _safeMint(msg.sender, bondId), it became clearly susceptible reentrancy attack. - We need to add explicit protection against reentrancy. +[N-44] Missing event for critical changes addNomenee in Dispenser ``` -#### Genaral notes: more tests need to be done, needed re-audit later +[x] fixed + +110. QA Report #110 +https://github.com/code-423n4/2024-05-olas-findings/issues/110 ``` -trackServiceDonations requires a large number of tests and coverage of all scenarios. +[NonCritical-9] Missing events in sensitive function setL2TargetDispenser(address l2Dispenser) ``` -#### Notes for discussion: epsilonRate +[x] fixed + +113. QA Report #113 +https://github.com/code-423n4/2024-05-olas-findings/issues/113 ``` -in this implementation epsilonRate is deprecated and simply not used. perhaps it makes sense (?) to use this dimensionless coefficient as a limiter. -// The IDF depends on the epsilonRate value, idf = 1 + epsilonRate, and epsilonRate is bound by 17 with 18 decimals -new -// IDF = 1 + normalized booster -idf = 1e18 + discountBooster; -maybe idf = min(1e18 + discountBooster, 1e18 + epsilonRate) -Moreover, according to calculations discountBooster <= 1e18 << max(epsilonRate) +[L-08] Use abi.encodeCall() instead of abi.encodeWithSignature()/abi.encodeWithSelector() +grep -r encodeWithSelec ./contracts/ +./contracts/staking/OptimismDepositProcessorL1.sol: bytes memory data = abi.encodeWithSelector(RECEIVE_MESSAGE, abi.encode(targets, stakingIncentives, batchHash)); +./contracts/staking/OptimismTargetDispenserL2.sol: bytes memory data = abi.encodeWithSelector(RECEIVE_MESSAGE, abi.encode(amount, batchHash)); +./contracts/staking/ArbitrumTargetDispenserL2.sol: bytes memory data = abi.encodeWithSelector(RECEIVE_MESSAGE, abi.encode(amount, batchHash)); +./contracts/staking/GnosisTargetDispenserL2.sol: bytes memory data = abi.encodeWithSelector(RECEIVE_MESSAGE, abi.encode(amount, batchHash)); +./contracts/staking/ArbitrumDepositProcessorL1.sol: bytes memory data = abi.encodeWithSelector(RECEIVE_MESSAGE, abi.encode(targets, stakingIncentives, batchHash)); +./contracts/staking/GnosisDepositProcessorL1.sol: bytes memory data = abi.encodeWithSelector(RECEIVE_MESSAGE, abi.encode(targets, stakingIncentives, batchHash)); ``` +[x] Noted. The fact that codebase hasn't been changed is not a problem. + +### Catch up on changes. 15.07.24 +https://github.com/valory-xyz/autonolas-tokenomics/compare/v1.2.2-pre-internal-audit...v1.2.2-pre-audit
+The changes to the codebase appear to be correct. + + + diff --git a/audits/internal6/README.md b/audits/internal6/README.md new file mode 100644 index 00000000..db892c93 --- /dev/null +++ b/audits/internal6/README.md @@ -0,0 +1,100 @@ +# Internal audit of autonolas-tokenomics +The review has been performed based on the contract code in the following repository:
+`https://github.com/valory-xyz/autonolas-tokenomics`
+commit: `12101b49a2dcdc7a7378f416ddb1611e10459b67` or `tag: v1.3.0-pre-internal-audit`
+ +## Objectives +The audit focused on contracts related to AIP-1 implementation (Bonding) in this repo. + +### Flatten version +Flatten version of contracts. [contracts](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/audits/internal5/analysis/contracts) + +### Coverage: N/A +In this commit, the tests are in the process of being reworked and therefore the coverage section does not make sense. + +### Storage and proxy +Using sol2uml tools: https://github.com/naddison36/sol2uml
+``` +npm link sol2uml --only=production +sol2uml storage contracts/ -f png -c Tokenomics -o audits/internal4/analysis/storage +Generated png file audits/internal5/analysis/storage/Tokenomics.png +``` +[Tokenomics-storage](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/audits/internal5/analysis/storage/Tokenomics.png)
+current deployed:
+[Tokenomics-storage-current](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/audits/internal4/analysis/storage/Tokenomics.png)
+The new slot allocation for Tokenomics (critical as proxy pattern) does not affect the previous one. + +### Security issues. +#### Problems found instrumentally +Several checks are obtained automatically. They are commented. Some issues found need to be fixed.
+All automatic warnings are listed in the following file, concerns of which we address in more detail below:
+[slither-full](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/audits/internal5/analysis/slither_full.txt)
+ +#### Issue +1. minOLASLeftoverAmount never setupped/updated +``` + // Minimum amount of supply such that any value below is given to the bonding account in order to close the product + uint256 public minOLASLeftoverAmount; +``` +[x] fixed + +2. Reentrancy after ERC721 "safe" mint in deposit +``` + External calls: + - _safeMint(msg.sender,bondId) (Depository-flatten.sol#891) + - require(bool,string)(ERC721TokenReceiver(to).onERC721Received(msg.sender,address(0),id,) == ERC721TokenReceiver.onERC721Received.selector,UNSAFE_RECIPIENT) (Depository-flatten.sol#461-465) + After adding _safeMint(msg.sender, bondId), it became clearly susceptible reentrancy attack. + We need to add explicit protection against reentrancy. +``` +[x] fixed + +#### General notes: more tests need to be done, needed re-audit later +``` +trackServiceDonations requires a large number of tests and coverage of all scenarios. +``` +[x] noted + +#### Notes for discussion: epsilonRate +``` +in this implementation epsilonRate is deprecated and simply not used. perhaps it makes sense (?) to use this dimensionless coefficient as a limiter. +// The IDF depends on the epsilonRate value, idf = 1 + epsilonRate, and epsilonRate is bound by 17 with 18 decimals +new +// IDF = 1 + normalized booster +idf = 1e18 + discountBooster; +maybe idf = min(1e18 + discountBooster, 1e18 + epsilonRate) +Moreover, according to calculations discountBooster <= 1e18 << max(epsilonRate) +``` +[x] IDF is never bigger than 2e18 by design + +### Re-audit 02.08.24 +The review has been performed based on the contract code in the following repository:
+`https://github.com/valory-xyz/autonolas-tokenomics`
+commit: `c76a04a64fd450e1a7a34873ea49b6a4b4b0b856` or `tag: v1.3.0-internal-audit2`
+ +### Coverage +``` +---------------------------------|----------|----------|----------|----------|----------------| +File | % Stmts | % Branch | % Funcs | % Lines |Uncovered Lines | +---------------------------------|----------|----------|----------|----------|----------------| + contracts/ | 98.83 | 96.45 | 95.51 | 97.79 | | + BondCalculator.sol | 97.44 | 98 | 85.71 | 97.22 | 181,299 | + Depository.sol | 95.56 | 92.71 | 81.25 | 93.49 |... 605,608,615 | + Dispenser.sol | 98.95 | 93.06 | 100 | 96.24 |... 0,1209,1267 | +---------------------------------|----------|----------|----------|----------|----------------| +``` +Please, pay attention. + +### Storage and proxy +Using sol2uml tools: https://github.com/naddison36/sol2uml
+``` +npm link sol2uml --only=production +sol2uml storage contracts/ -f png -c Tokenomics -o audits/internal6/analysis/storage +Generated png file audits/internal6/analysis/storage/Tokenomics.png +``` +[Tokenomics-storage](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/audits/internal6/analysis/storage/Tokenomics.png)
+current deployed:
+[Tokenomics-storage-current](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/audits/internal4/analysis/storage/Tokenomics.png)
+The new slot allocation for Tokenomics (critical as proxy pattern) does not affect the previous one. + +### Issue +I don't see any problems. diff --git a/audits/internal5/analysis/contracts/BondCalculator-flatten.sol b/audits/internal6/analysis/contracts/BondCalculator-flatten.sol similarity index 100% rename from audits/internal5/analysis/contracts/BondCalculator-flatten.sol rename to audits/internal6/analysis/contracts/BondCalculator-flatten.sol diff --git a/audits/internal5/analysis/contracts/Depository-flatten.sol b/audits/internal6/analysis/contracts/Depository-flatten.sol similarity index 100% rename from audits/internal5/analysis/contracts/Depository-flatten.sol rename to audits/internal6/analysis/contracts/Depository-flatten.sol diff --git a/audits/internal5/analysis/contracts/script.sh b/audits/internal6/analysis/contracts/script.sh similarity index 100% rename from audits/internal5/analysis/contracts/script.sh rename to audits/internal6/analysis/contracts/script.sh diff --git a/audits/internal5/analysis/slither_BondCalculator-flatten.sol.BondCalculator.call-graph.png b/audits/internal6/analysis/slither_BondCalculator-flatten.sol.BondCalculator.call-graph.png similarity index 100% rename from audits/internal5/analysis/slither_BondCalculator-flatten.sol.BondCalculator.call-graph.png rename to audits/internal6/analysis/slither_BondCalculator-flatten.sol.BondCalculator.call-graph.png diff --git a/audits/internal5/analysis/slither_BondCalculator-flatten.sol.ITokenomics.call-graph.png b/audits/internal6/analysis/slither_BondCalculator-flatten.sol.ITokenomics.call-graph.png similarity index 100% rename from audits/internal5/analysis/slither_BondCalculator-flatten.sol.ITokenomics.call-graph.png rename to audits/internal6/analysis/slither_BondCalculator-flatten.sol.ITokenomics.call-graph.png diff --git a/audits/internal5/analysis/slither_BondCalculator-flatten.sol.IUniswapV2Pair.call-graph.png b/audits/internal6/analysis/slither_BondCalculator-flatten.sol.IUniswapV2Pair.call-graph.png similarity index 100% rename from audits/internal5/analysis/slither_BondCalculator-flatten.sol.IUniswapV2Pair.call-graph.png rename to audits/internal6/analysis/slither_BondCalculator-flatten.sol.IUniswapV2Pair.call-graph.png diff --git a/audits/internal5/analysis/slither_BondCalculator-flatten.sol.IVotingEscrow.call-graph.png b/audits/internal6/analysis/slither_BondCalculator-flatten.sol.IVotingEscrow.call-graph.png similarity index 100% rename from audits/internal5/analysis/slither_BondCalculator-flatten.sol.IVotingEscrow.call-graph.png rename to audits/internal6/analysis/slither_BondCalculator-flatten.sol.IVotingEscrow.call-graph.png diff --git a/audits/internal5/analysis/slither_BondCalculator-flatten.sol.all_contracts.call-graph.png b/audits/internal6/analysis/slither_BondCalculator-flatten.sol.all_contracts.call-graph.png similarity index 100% rename from audits/internal5/analysis/slither_BondCalculator-flatten.sol.all_contracts.call-graph.png rename to audits/internal6/analysis/slither_BondCalculator-flatten.sol.all_contracts.call-graph.png diff --git a/audits/internal5/analysis/slither_BondCalculator-flatten.sol.inheritance-graph.png b/audits/internal6/analysis/slither_BondCalculator-flatten.sol.inheritance-graph.png similarity index 100% rename from audits/internal5/analysis/slither_BondCalculator-flatten.sol.inheritance-graph.png rename to audits/internal6/analysis/slither_BondCalculator-flatten.sol.inheritance-graph.png diff --git a/audits/internal5/analysis/slither_Depository-flatten.sol.Depository.call-graph.png b/audits/internal6/analysis/slither_Depository-flatten.sol.Depository.call-graph.png similarity index 100% rename from audits/internal5/analysis/slither_Depository-flatten.sol.Depository.call-graph.png rename to audits/internal6/analysis/slither_Depository-flatten.sol.Depository.call-graph.png diff --git a/audits/internal5/analysis/slither_Depository-flatten.sol.ERC721TokenReceiver.call-graph.png b/audits/internal6/analysis/slither_Depository-flatten.sol.ERC721TokenReceiver.call-graph.png similarity index 100% rename from audits/internal5/analysis/slither_Depository-flatten.sol.ERC721TokenReceiver.call-graph.png rename to audits/internal6/analysis/slither_Depository-flatten.sol.ERC721TokenReceiver.call-graph.png diff --git a/audits/internal5/analysis/slither_Depository-flatten.sol.IBondCalculator.call-graph.png b/audits/internal6/analysis/slither_Depository-flatten.sol.IBondCalculator.call-graph.png similarity index 100% rename from audits/internal5/analysis/slither_Depository-flatten.sol.IBondCalculator.call-graph.png rename to audits/internal6/analysis/slither_Depository-flatten.sol.IBondCalculator.call-graph.png diff --git a/audits/internal5/analysis/slither_Depository-flatten.sol.IToken.call-graph.png b/audits/internal6/analysis/slither_Depository-flatten.sol.IToken.call-graph.png similarity index 100% rename from audits/internal5/analysis/slither_Depository-flatten.sol.IToken.call-graph.png rename to audits/internal6/analysis/slither_Depository-flatten.sol.IToken.call-graph.png diff --git a/audits/internal5/analysis/slither_Depository-flatten.sol.ITokenomics.call-graph.png b/audits/internal6/analysis/slither_Depository-flatten.sol.ITokenomics.call-graph.png similarity index 100% rename from audits/internal5/analysis/slither_Depository-flatten.sol.ITokenomics.call-graph.png rename to audits/internal6/analysis/slither_Depository-flatten.sol.ITokenomics.call-graph.png diff --git a/audits/internal5/analysis/slither_Depository-flatten.sol.ITreasury.call-graph.png b/audits/internal6/analysis/slither_Depository-flatten.sol.ITreasury.call-graph.png similarity index 100% rename from audits/internal5/analysis/slither_Depository-flatten.sol.ITreasury.call-graph.png rename to audits/internal6/analysis/slither_Depository-flatten.sol.ITreasury.call-graph.png diff --git a/audits/internal5/analysis/slither_Depository-flatten.sol.all_contracts.call-graph.png b/audits/internal6/analysis/slither_Depository-flatten.sol.all_contracts.call-graph.png similarity index 100% rename from audits/internal5/analysis/slither_Depository-flatten.sol.all_contracts.call-graph.png rename to audits/internal6/analysis/slither_Depository-flatten.sol.all_contracts.call-graph.png diff --git a/audits/internal5/analysis/slither_Depository-flatten.sol.inheritance-graph.png b/audits/internal6/analysis/slither_Depository-flatten.sol.inheritance-graph.png similarity index 100% rename from audits/internal5/analysis/slither_Depository-flatten.sol.inheritance-graph.png rename to audits/internal6/analysis/slither_Depository-flatten.sol.inheritance-graph.png diff --git a/audits/internal5/analysis/slither_call-graph.txt b/audits/internal6/analysis/slither_call-graph.txt similarity index 100% rename from audits/internal5/analysis/slither_call-graph.txt rename to audits/internal6/analysis/slither_call-graph.txt diff --git a/audits/internal5/analysis/slither_constructor-calls.txt b/audits/internal6/analysis/slither_constructor-calls.txt similarity index 100% rename from audits/internal5/analysis/slither_constructor-calls.txt rename to audits/internal6/analysis/slither_constructor-calls.txt diff --git a/audits/internal5/analysis/slither_contract-summary.txt b/audits/internal6/analysis/slither_contract-summary.txt similarity index 100% rename from audits/internal5/analysis/slither_contract-summary.txt rename to audits/internal6/analysis/slither_contract-summary.txt diff --git a/audits/internal5/analysis/slither_data-dependency.txt b/audits/internal6/analysis/slither_data-dependency.txt similarity index 100% rename from audits/internal5/analysis/slither_data-dependency.txt rename to audits/internal6/analysis/slither_data-dependency.txt diff --git a/audits/internal5/analysis/slither_full.txt b/audits/internal6/analysis/slither_full.txt similarity index 100% rename from audits/internal5/analysis/slither_full.txt rename to audits/internal6/analysis/slither_full.txt diff --git a/audits/internal5/analysis/slither_function-summary.txt b/audits/internal6/analysis/slither_function-summary.txt similarity index 100% rename from audits/internal5/analysis/slither_function-summary.txt rename to audits/internal6/analysis/slither_function-summary.txt diff --git a/audits/internal5/analysis/slither_human-summary.txt b/audits/internal6/analysis/slither_human-summary.txt similarity index 100% rename from audits/internal5/analysis/slither_human-summary.txt rename to audits/internal6/analysis/slither_human-summary.txt diff --git a/audits/internal5/analysis/slither_inheritance-graph.txt b/audits/internal6/analysis/slither_inheritance-graph.txt similarity index 100% rename from audits/internal5/analysis/slither_inheritance-graph.txt rename to audits/internal6/analysis/slither_inheritance-graph.txt diff --git a/audits/internal5/analysis/slither_inheritance.txt b/audits/internal6/analysis/slither_inheritance.txt similarity index 100% rename from audits/internal5/analysis/slither_inheritance.txt rename to audits/internal6/analysis/slither_inheritance.txt diff --git a/audits/internal5/analysis/slither_modifiers.txt b/audits/internal6/analysis/slither_modifiers.txt similarity index 100% rename from audits/internal5/analysis/slither_modifiers.txt rename to audits/internal6/analysis/slither_modifiers.txt diff --git a/audits/internal5/analysis/slither_require.txt b/audits/internal6/analysis/slither_require.txt similarity index 100% rename from audits/internal5/analysis/slither_require.txt rename to audits/internal6/analysis/slither_require.txt diff --git a/audits/internal5/analysis/slither_variable-order.txt b/audits/internal6/analysis/slither_variable-order.txt similarity index 100% rename from audits/internal5/analysis/slither_variable-order.txt rename to audits/internal6/analysis/slither_variable-order.txt diff --git a/audits/internal5/analysis/slither_vars-and-auth.txt b/audits/internal6/analysis/slither_vars-and-auth.txt similarity index 100% rename from audits/internal5/analysis/slither_vars-and-auth.txt rename to audits/internal6/analysis/slither_vars-and-auth.txt diff --git a/audits/internal5/analysis/storage/Tokenomics.png b/audits/internal6/analysis/storage/Tokenomics.png similarity index 82% rename from audits/internal5/analysis/storage/Tokenomics.png rename to audits/internal6/analysis/storage/Tokenomics.png index 5e281d85..754e86cd 100644 Binary files a/audits/internal5/analysis/storage/Tokenomics.png and b/audits/internal6/analysis/storage/Tokenomics.png differ diff --git a/contracts/Depository.sol b/contracts/Depository.sol index f18559fc..e6a86c9b 100644 --- a/contracts/Depository.sol +++ b/contracts/Depository.sol @@ -128,6 +128,8 @@ contract Depository is ERC721, IErrorsTokenomics { address public treasury; // Bond Calculator contract address address public bondCalculator; + // Reentrancy lock + uint8 internal _locked; // Mapping of bond Id => account bond instance mapping(uint256 => Bond) public mapUserBonds; @@ -225,6 +227,17 @@ contract Depository is ERC721, IErrorsTokenomics { } } + /// @dev Sets minimum OLAS leftover amount for the product to keep the supply. + /// @param _minOLASLeftoverAmount Updated minimum OLAS leftover amount. + function setMinOLASLeftoverAmount(uint256 _minOLASLeftoverAmount) external { + // Check for the contract ownership + if (msg.sender != owner) { + revert OwnerOnly(msg.sender, owner); + } + + minOLASLeftoverAmount = _minOLASLeftoverAmount; + } + /// @dev Creates a new bond product. /// @param token LP token to be deposited for pairs like OLAS-DAI, OLAS-ETH, etc. /// @param priceLP LP token price with 18 additional decimals. @@ -344,6 +357,12 @@ contract Depository is ERC721, IErrorsTokenomics { function deposit(uint256 productId, uint256 tokenAmount, uint256 bondVestingTime) external returns (uint256 payout, uint256 maturity, uint256 bondId) { + // Reentrancy guard + if (_locked > 1) { + revert ReentrancyGuard(); + } + _locked = 2; + // Check the token amount if (tokenAmount == 0) { revert ZeroValue(); @@ -423,6 +442,8 @@ contract Depository is ERC721, IErrorsTokenomics { } emit CreateBond(token, productId, msg.sender, bondId, payout, tokenAmount, maturity); + + _locked = 1; } /// @dev Redeems account bonds. diff --git a/contracts/Dispenser.sol b/contracts/Dispenser.sol index 6b10797e..8d869a2f 100644 --- a/contracts/Dispenser.sol +++ b/contracts/Dispenser.sol @@ -267,13 +267,18 @@ contract Dispenser { event TreasuryUpdated(address indexed treasury); event VoteWeightingUpdated(address indexed voteWeighting); event StakingParamsUpdated(uint256 maxNumClaimingEpochs, uint256 maxNumStakingTargets); - event IncentivesClaimed(address indexed owner, uint256 reward, uint256 topUp); - event StakingIncentivesClaimed(address indexed account, uint256 stakingIncentive, uint256 transferAmount, - uint256 returnAmount); + event IncentivesClaimed(address indexed owner, uint256 reward, uint256 topUp, uint256[] unitTypes, uint256[] unitIds); + event StakingIncentivesClaimed(address indexed account, uint256 chainId, bytes32 stakingTarget, + uint256 stakingIncentive, uint256 transferAmount, uint256 returnAmount); + event StakingIncentivesBatchClaimed(address indexed account, uint256[] chainIds, bytes32[][] stakingTargets, + uint256[][] stakingIncentives, uint256 totalStakingIncentive, uint256 totalTransferAmount, + uint256 totalReturnAmount); event Retained(address indexed account, uint256 returnAmount); event SetDepositProcessorChainIds(address[] depositProcessors, uint256[] chainIds); event WithheldAmountSynced(uint256 chainId, uint256 amount, uint256 updatedWithheldAmount, bytes32 indexed batchHash); event PauseDispenser(Pause pauseState); + event AddNomineeHash(bytes32 indexed nomineeHash); + event RemoveNomineeHash(bytes32 indexed nomineeHash); // Maximum chain Id as per EVM specs uint256 public constant MAX_EVM_CHAIN_ID = type(uint64).max / 2 - 36; @@ -397,11 +402,11 @@ contract Dispenser { revert Overflow(firstClaimedEpoch, eCounter - 1); } - // Get epoch when the nominee was removed + // Get epoch number when the nominee was removed uint256 epochRemoved = mapRemovedNomineeEpochs[nomineeHash]; - // If the nominee is not removed, its value in the map is always zero, unless removed + // If the nominee is not removed, its value in the map is always zero // The staking contract nominee cannot be removed in the zero-th epoch by default - if (epochRemoved > 1 && firstClaimedEpoch >= epochRemoved) { + if (epochRemoved > 0 && firstClaimedEpoch >= epochRemoved) { revert Overflow(firstClaimedEpoch, epochRemoved - 1); } @@ -410,7 +415,7 @@ contract Dispenser { // Limit last claimed epoch by the number following the nominee removal epoch // The condition for is lastClaimedEpoch strictly > because the lastClaimedEpoch is not included in claiming - if (epochRemoved > 1 && lastClaimedEpoch > epochRemoved) { + if (epochRemoved > 0 && lastClaimedEpoch > epochRemoved) { lastClaimedEpoch = epochRemoved; } @@ -487,6 +492,11 @@ contract Dispenser { } } + // Skip if there are no actual staking targets + if (numActualTargets == 0) { + continue; + } + // Allocate updated arrays accounting only for nonzero staking incentives bytes32[] memory updatedStakingTargets = new bytes32[](numActualTargets); uint256[] memory updatedStakingAmounts = new uint256[](numActualTargets); @@ -769,9 +779,17 @@ contract Dispenser { } mapLastClaimedStakingEpochs[nomineeHash] = ITokenomics(tokenomics).epochCounter(); + + emit AddNomineeHash(nomineeHash); } /// @dev Records nominee removal epoch number. + /// @notice The staking contract nominee cannot be removed starting from one week before the end of epoch. + /// Since the epoch end time is unknown and the nominee removal is applied in the following week, + /// it is prohibited to remove nominee one week before the foreseen epoch end to correctly reflect + /// the removal epoch number. + /// If the staking contract nominee must not get incentives in the ongoing ending epoch as well, + /// the DAO is advised to use the removeInstance() function in the corresponding StakingFactory contract. /// @param nomineeHash Nominee hash. function removeNominee(bytes32 nomineeHash) external { // Check for the contract ownership @@ -803,6 +821,8 @@ contract Dispenser { // Set the removed nominee epoch number mapRemovedNomineeEpochs[nomineeHash] = eCounter; + + emit RemoveNomineeHash(nomineeHash); } /// @dev Claims incentives for the owner of components / agents. @@ -857,7 +877,7 @@ contract Dispenser { revert ClaimIncentivesFailed(msg.sender, reward, topUp); } - emit IncentivesClaimed(msg.sender, reward, topUp); + emit IncentivesClaimed(msg.sender, reward, topUp, unitTypes, unitIds); _locked = 1; } @@ -1097,7 +1117,7 @@ contract Dispenser { _distributeStakingIncentives(chainId, stakingTarget, stakingIncentive, bridgePayload, transferAmount); } - emit StakingIncentivesClaimed(msg.sender, stakingIncentive, transferAmount, returnAmount); + emit StakingIncentivesClaimed(msg.sender, chainId, stakingTarget, stakingIncentive, transferAmount, returnAmount); _locked = 1; } @@ -1176,7 +1196,8 @@ contract Dispenser { valueAmounts); } - emit StakingIncentivesClaimed(msg.sender, totalAmounts[0], totalAmounts[1], totalAmounts[2]); + emit StakingIncentivesBatchClaimed(msg.sender, chainIds, stakingTargets, stakingIncentives, totalAmounts[0], + totalAmounts[1], totalAmounts[2]); _locked = 1; } diff --git a/contracts/Tokenomics.sol b/contracts/Tokenomics.sol index ea4704ba..98581e8c 100644 --- a/contracts/Tokenomics.sol +++ b/contracts/Tokenomics.sol @@ -247,11 +247,16 @@ struct StakingPoint { uint8 stakingFraction; } -// Struct for service staking epoch info +// Struct for donation point struct DonationPoint { + // Amount of OLAS intended to fund component / agent top-ups for the epoch based on the inflation schedule + // After 10 years, the OLAS inflation rate is 2% per year. It would take 220+ years to reach 2^96 - 1 uint96 totalUnitTopUps; + // Amount of veOLAS power used to trigger top-ups accumulated from all the unique donators per a single epoch + // veOLAS amount cannot practically be bigger than the OLAS amount uint96 totalDonationPower; - bool moreDonationPower; + // Sum of component / agent top-up fractions in a corresponding epoch + uint8 sumTopUpUnitFractions; } /// @title Tokenomics - Smart contract for tokenomics logic with incentives for unit owners, discount factor @@ -381,9 +386,9 @@ contract Tokenomics is TokenomicsConstants { // Mapping of epoch => service staking point mapping(uint256 => StakingPoint) public mapEpochStakingPoints; // Mapping of hash(epoch + donator address) => true the voting power has been utilized in the on-going epoch - mapping(bytes32 => bool) public mapEpochDonatorPowerHashes; + mapping(bytes32 => bool) public mapEpochDonationPowerHashes; // Mapping of epoch => donation point - mapping(uint256 => DonationPoint) mapDonationPoints; + mapping(uint256 => DonationPoint) public mapDonationPoints; /// @dev Tokenomics constructor. constructor() @@ -864,19 +869,20 @@ contract Tokenomics is TokenomicsConstants { // The pendingRelativeTopUp can be zero if the service owner did not stake enough veOLAS // The topUpUnitFraction was checked before and if it were zero, pendingRelativeTopUp would be zero as well if (totalIncentives > 0) { + DonationPoint memory donationPoint = mapDonationPoints[epochNum]; // Summation of all the unit top-ups and total amount of top-ups per epoch - // TODO: update the formula - // topUp = (pendingRelativeTopUp * totalTopUpsOLAS * topUpUnitFraction) / (100 * sumUnitTopUpsOLAS) - if (mapDonationPoints[epochNum].moreDonationPower) { - // TODO: calculate top-ups for components and agents before this function call, before the loop if possible - uint256 totalTopUpsOLAS = mapEpochTokenomics[epochNum].epochPoint.totalTopUpsOLAS; - // TODO: pass this as a function parameter in order to optimize on gas - uint256 totalDonationPower = mapDonationPoints[epochNum].totalDonationPower; - totalIncentives *= totalTopUpsOLAS * mapEpochTokenomics[epochNum].unitPoints[unitType].topUpUnitFraction; - totalIncentives = mapUnitIncentives[unitType][unitId].topUp + (totalIncentives / (totalDonationPower * 100)); + // topUp = (pendingRelativeTopUp * totalUnitTopUps * topUpUnitFraction) / sumTopUpUnitFractions, if totalDonationPower > totalUnitTopUps + // topUp = pendingRelativeTopUp * topUpUnitFraction, otherwise + totalIncentives *= mapEpochTokenomics[epochNum].unitPoints[unitType].topUpUnitFraction; + if (donationPoint.totalDonationPower > donationPoint.totalUnitTopUps) { + totalIncentives = mapUnitIncentives[unitType][unitId].topUp + + (totalIncentives * donationPoint.totalUnitTopUps) / + (donationPoint.totalDonationPower * donationPoint.sumTopUpUnitFractions); } else { - totalIncentives = mapUnitIncentives[unitType][unitId].topUp + totalIncentives; + totalIncentives = mapUnitIncentives[unitType][unitId].topUp + + totalIncentives / donationPoint.sumTopUpUnitFractions; } + // Record the accumulated top-up value mapUnitIncentives[unitType][unitId].topUp = uint96(totalIncentives); // Setting pending top-up to zero mapUnitIncentives[unitType][unitId].pendingRelativeTopUp = 0; @@ -914,9 +920,9 @@ contract Tokenomics is TokenomicsConstants { uint256 vPower; if (incentiveFlags[2] || incentiveFlags[3]) { vPower = IVotingEscrow(ve).getVotes(donator); - bytes32 donatorPowerHash = keccak256(abi.encode(epochCounter, donator)); + bytes32 donationPowerHash = keccak256(abi.encode(epochCounter, donator)); // Check the donator voting power - if (vPower < veOLASThreshold || mapEpochDonatorPowerHashes[donatorPowerHash]) { + if (vPower < veOLASThreshold || mapEpochDonationPowerHashes[donationPowerHash]) { // If voting power is below the threshold or has been already utilized during the on-going epoch, // top-ups are not eligible vPower = 0; @@ -926,7 +932,7 @@ contract Tokenomics is TokenomicsConstants { // Otherwise, split them to the corresponding number of services vPower /= numServices; // Add donator voting power to the map - mapEpochDonatorPowerHashes[donatorPowerHash] = true; + mapEpochDonationPowerHashes[donationPowerHash] = true; } } @@ -1206,11 +1212,11 @@ contract Tokenomics is TokenomicsConstants { // we still record the amount of OLAS allocated for component / agent owner top-ups from the inflation schedule. // This amount will appear in the EpochSettled event, and thus can be tracked historically uint256 accountTopUps = incentives[5] + incentives[6]; - // Record donation power state in a settled epoch - if (mapDonationPoints[eCounter].totalDonationPower > accountTopUps) { - mapDonationPoints[eCounter].moreDonationPower = true; - } - mapDonationPoints[eCounter].totalDonationPower = uint96(accountTopUps); + + // Record total unit top-ups and fractions in a settled epoch + mapDonationPoints[eCounter].totalUnitTopUps = uint96(accountTopUps); + mapDonationPoints[eCounter].sumTopUpUnitFractions = tp.unitPoints[0].topUpUnitFraction + + tp.unitPoints[1].topUpUnitFraction; // Service staking funding // Refunded amount during the epoch @@ -1413,19 +1419,16 @@ contract Tokenomics is TokenomicsConstants { // Add the final top-up for the last epoch totalIncentives = mapUnitIncentives[unitTypes[i]][unitIds[i]].pendingRelativeTopUp; if (totalIncentives > 0) { + DonationPoint memory donationPoint = mapDonationPoints[lastEpoch]; // Summation of all the unit top-ups and total amount of top-ups per epoch - // TODO: update the formula - // topUp = (pendingRelativeTopUp * totalTopUpsOLAS * topUpUnitFraction) / (100 * sumUnitTopUpsOLAS) - // Accumulate to the final top-up for the last epoch - if (mapDonationPoints[lastEpoch].moreDonationPower) { - // TODO: calculate top-ups for components and agents before this function call, before the loop if possible - uint256 totalTopUpsOLAS = mapEpochTokenomics[lastEpoch].epochPoint.totalTopUpsOLAS; - // TODO: pass this as a function parameter in order to optimize on gas - uint256 totalDonationPower = mapDonationPoints[lastEpoch].totalDonationPower; - totalIncentives *= totalTopUpsOLAS * mapEpochTokenomics[lastEpoch].unitPoints[unitTypes[i]].topUpUnitFraction; - totalIncentives = mapUnitIncentives[unitTypes[i]][unitIds[i]].topUp + (totalIncentives / (totalDonationPower * 100)); + // topUp = (pendingRelativeTopUp * totalUnitTopUps * topUpUnitFraction) / sumTopUpUnitFractions, if totalDonationPower > totalUnitTopUps + // topUp = pendingRelativeTopUp * topUpUnitFraction, otherwise + totalIncentives *= mapEpochTokenomics[lastEpoch].unitPoints[unitTypes[i]].topUpUnitFraction; + if (donationPoint.totalDonationPower > donationPoint.totalUnitTopUps) { + topUp += (totalIncentives * donationPoint.totalUnitTopUps) / + (donationPoint.totalDonationPower * donationPoint.sumTopUpUnitFractions); } else { - topUp += totalIncentives; + topUp += totalIncentives / donationPoint.sumTopUpUnitFractions; } } } diff --git a/contracts/test/ReentrancyAttacker.sol b/contracts/test/ReentrancyAttacker.sol index 938f5f13..ebadb4a4 100644 --- a/contracts/test/ReentrancyAttacker.sol +++ b/contracts/test/ReentrancyAttacker.sol @@ -58,6 +58,10 @@ contract ReentrancyAttacker { attackMode = _attackMode; } + /// @dev Makes a deposit from an attacker in order to get top-ups from the inflation + function depositServiceDonationsETH(uint256[] memory serviceIds, uint256[] memory amounts) external payable { + ITokenomics(treasury).depositServiceDonationsETH{value: msg.value}(serviceIds, amounts); + } /// @dev Lets the attacker call back its contract to get back to the claimOwnerIncentives() function. function badClaimOwnerIncentives(bool attack, uint256[] memory unitTypes, uint256[] memory unitIds) external diff --git a/docs/configuration.json b/docs/configuration.json index d6afd484..eca1c39c 100644 --- a/docs/configuration.json +++ b/docs/configuration.json @@ -10,8 +10,8 @@ }, { "name": "Tokenomics", - "artifact": "abis/0.8.20/Tokenomics.json", - "address": "0xD599ED4a5c45Fa66AA3C474b00701Fd452a2C30e" + "artifact": "abis/0.8.25/Tokenomics.json", + "address": "0x2C1633765c66a7CF0EC801a1046347bBee7344C9" }, { "name": "TokenomicsProxy", @@ -30,54 +30,180 @@ }, { "name": "Dispenser", - "artifact": "abis/0.8.18/Dispenser.json", - "address": "0xeED0000fE94d7cfeF4Dc0CA86a223f0F603A61B8" + "artifact": "abis/0.8.25/Dispenser.json", + "address": "0x5650300fCBab43A0D7D02F8Cb5d0f039402593f0" }, { "name": "Depository", "artifact": "abis/0.8.20/Depository.json", "address": "0xfF8697d8d2998d6AA2e09B405795C6F4BEeB0C81" - } - ] - }, - { - "name": "goerli", - "chainId": "5", - "contracts": [ + }, { - "name": "DonatorBlacklist", - "artifact": "abis/0.8.18/DonatorBlacklist.json", - "address": "0x1E11f1224e32Fe0f65FF7D13aD4b053B83bD09FA" + "name": "ArbitrumDepositProcessorL1", + "artifact": "abis/0.8.25/ArbitrumDepositProcessorL1.json", + "address": "0x5e13E07006D68B097DCb5979ef5545C4f9156162" }, { - "name": "Tokenomics", - "artifact": "abis/0.8.20/Tokenomics.json", - "address": "0x93Cd3f6DcE64d67f4420939865A00aC89776D4b5" + "name": "OptimismDepositProcessorL1", + "artifact": "abis/0.8.25/OptimismDepositProcessorL1.json", + "address": "0x42BA1BbD797E4C90F386F03a544F3b62C1f917d0" }, { - "name": "TokenomicsProxy", - "artifact": "abis/0.8.18/TokenomicsProxy.json", - "address": "0x10100e74b7F706222F8A7C0be9FC7Ae1717Ad8B2" + "name": "WormholeDepositProcessorL1", + "artifact": "abis/0.8.25/WormholeDepositProcessorL1.json", + "address": "0x223902b6C583f18E8dc84AF4E6a8fa523d088B78" }, { - "name": "Treasury", - "artifact": "abis/0.8.18/Treasury.json", - "address": "0x7bedCA17D29e53C8062d10902a6219F8d1E3B9B5" + "name": "EthereumDepositProcessor", + "artifact": "abis/0.8.25/EthereumDepositProcessor.json", + "address": "0x15CD7fAeE048c7673aB818C9e582630F1a924593" }, { - "name": "GenericBondCalculator", - "artifact": "abis/0.8.18/GenericBondCalculator.json", - "address": "0x77290FF625fc576f465D0256F6a12Ce4480a5b8a" + "name": "GnosisDepositProcessorL1", + "artifact": "abis/0.8.25/GnosisDepositProcessorL1.json", + "address": "0xEEf2c02cFC445bFFf1c891D486424Ef3aBc66AB0" }, { - "name": "Dispenser", - "artifact": "abis/0.8.18/Dispenser.json", - "address": "0xeDd71796B90eaCc56B074C39BAC90ED2Ca6D93Ee" + "name": "OptimismDepositProcessorL1", + "artifact": "abis/0.8.25/OptimismDepositProcessorL1.json", + "address": "0xAB787ceebe8F2b8dca44e3bB744D6e63003ee978" }, { - "name": "Depository", - "artifact": "abis/0.8.20/Depository.json", - "address": "0x5FDc466f4A7547c876eF40CD30fFA2A89F1EcDE7" + "name": "PolygonDepositProcessorL1", + "artifact": "abis/0.8.25/PolygonDepositProcessorL1.json", + "address": "0x4Ce43b82EF1298E1466D3b3Cee67BA6680bF82FB" + } + ] + }, + { + "name": "arbitrumOne", + "chainId": "42161", + "contracts": [ + { + "name": "ArbitrumTargetDispenserL2", + "artifact": "abis/0.8.25/ArbitrumTargetDispenserL2.json", + "address": "0x10c5525F77F13b28f42c5626240c001c2D57CAd4" + } + ] + }, + { + "name": "arbitrumSepolia", + "chainId": "421614", + "contracts": [ + { + "name": "ArbitrumTargetDispenserL2", + "artifact": "abis/0.8.25/ArbitrumTargetDispenserL2.json", + "address": "" + } + ] + }, + { + "name": "base", + "chainId": "8453", + "contracts": [ + { + "name": "OptimismTargetDispenserL2", + "artifact": "abis/0.8.25/OptimismTargetDispenserL2.json", + "address": "0xcDdD9D9ABaB36fFa882530D69c73FeE5D4001C2d" + } + ] + }, + { + "name": "baseSepolia", + "chainId": "84532", + "contracts": [ + { + "name": "OptimismTargetDispenserL2", + "artifact": "abis/0.8.25/OptimismTargetDispenserL2.json", + "address": "" + } + ] + }, + { + "name": "celo", + "chainId": "42220", + "contracts": [ + { + "name": "WormholeTargetDispenserL2", + "artifact": "abis/0.8.25/WormholeTargetDispenserL2.json", + "address": "0xb4096d181C08DDF75f1A63918cCa0d1023C4e6C7" + } + ] + }, + { + "name": "celoAlfajores", + "chainId": "44787", + "contracts": [ + { + "name": "WormholeTargetDispenserL2", + "artifact": "abis/0.8.25/WormholeTargetDispenserL2.json", + "address": "" + } + ] + }, + { + "name": "gnosis", + "chainId": "100", + "contracts": [ + { + "name": "GnosisTargetDispenserL2", + "artifact": "abis/0.8.25/GnosisTargetDispenserL2.json", + "address": "0x67722c823010CEb4BED5325fE109196C0f67D053" + } + ] + }, + { + "name": "chiado", + "chainId": "10200", + "contracts": [ + { + "name": "GnosisTargetDispenserL2", + "artifact": "abis/0.8.25/GnosisTargetDispenserL2.json", + "address": "" + } + ] + }, + { + "name": "optimistic", + "chainId": "10", + "contracts": [ + { + "name": "OptimismTargetDispenserL2", + "artifact": "abis/0.8.25/OptimismTargetDispenserL2.json", + "address": "0x04b0007b2aFb398015B76e5f22993a1fddF83644" + } + ] + }, + { + "name": "optimisticSepolia", + "chainId": "11155420", + "contracts": [ + { + "name": "OptimismTargetDispenserL2", + "artifact": "abis/0.8.25/OptimismTargetDispenserL2.json", + "address": "" + } + ] + }, + { + "name": "polygon", + "chainId": "137", + "contracts": [ + { + "name": "PolygonTargetDispenserL2", + "artifact": "abis/0.8.25/PolygonTargetDispenserL2.json", + "address": "0xf76953444C35F1FcE2F6CA1b167173357d3F5C17" + } + ] + }, + { + "name": "polygonAmoy", + "chainId": "80002", + "contracts": [ + { + "name": "PolygonTargetDispenserL2", + "artifact": "abis/0.8.25/PolygonTargetDispenserL2.json", + "address": "" } ] } diff --git a/docs/deployment_v1.2.md b/docs/deployment_v1.2.md new file mode 100644 index 00000000..37cbb6ed --- /dev/null +++ b/docs/deployment_v1.2.md @@ -0,0 +1,24 @@ +Steps for deploying the tokenomics version 1.2 contracts are as follows: + +1. EOA to deploy Tokenomics implementation (`TokenomicsThree`); +2. TokenomicsProxy to change Tokenomics implementation calling `changeTokenomicsImplementation(TokenomicsThree)`; +3. EOA to deploy Dispenser with VoteWeighting contract being deployed before that in `autonolas-governance`; +4. EOA to change Dispenser address in VoteWeighting calling `changeDispenser(Dispenser)`; +5. EOA to unpause staking incentives in Dispenser calling `setPauseState(0)`; +6. EOA to add a retainer address as a nominee in VoteWeighting; +7. EOA to deploy staking bridging contracts on L1 and L2 with StakingFactory contract being deployed before that in `autonolas-registries`; +8. EOA to set up correct L1->L2 links for all the bridging contracts calling `setL2TargetDispenser(L2 corresponding contract)`; +9. EOA to enable bridge deposit processors in Dispenser calling `setDepositProcessorChainIds()`; +10. EOA to transfer ownership rights of all the L2 bridging contracts to Timelock representation calling `changeOwner(Timelock)`; +11. EOA to transfer ownership rights of Dispenser to Timelock calling `changeOwner(Timelock)`; +12. DAO to change Tokenomics managers calling `changeManagers(ZeroAddress, ZeroAddress, Dispenser)`; +13. DAO to change staking parameters in Tokenomics calling `changeStakingParams()`; +14. DAO to change Treasury managers calling `changeManagers(ZeroAddress, ZeroAddress, Dispenser)`. + +Note for updating VoteWeighting contract address in Dispenser, if required at some point of time. +As outlined in the C4R [issue 59](https://github.com/code-423n4/2024-05-olas-findings/issues/59), the following set of +steps must be taken into account in order to avoid possible staking inflation loss: +- Initiate claim of incentives for all the outstanding staking contract, as those are ownerless; +- Pause staking incentives; +- Change VoteWeighting contract; +- Unpause staking incentives. \ No newline at end of file diff --git a/scripts/audit_chains/audit_contracts_setup.js b/scripts/audit_chains/audit_contracts_setup.js index 4fd2dc98..f4272176 100644 --- a/scripts/audit_chains/audit_contracts_setup.js +++ b/scripts/audit_chains/audit_contracts_setup.js @@ -3,6 +3,7 @@ const { ethers } = require("ethers"); const { expect } = require("chai"); const fs = require("fs"); +const AddressZero = ethers.constants.AddressZero; // Custom expect that is wrapped into try / catch block function customExpect(arg1, arg2, log) { @@ -58,10 +59,18 @@ async function checkBytecode(provider, configContracts, contractName, log) { } // Find the contract name from the configuration data -async function findContractInstance(provider, configContracts, contractName) { +// idx is to choose the contract, if there are more than one +async function findContractInstance(provider, configContracts, contractName, idx = 0) { + let numFound = 0; // Get the contract number from the set of configuration contracts for (let i = 0; i < configContracts.length; i++) { if (configContracts[i]["name"] === contractName) { + // Keep searching if needed idx is not found + if (numFound != idx) { + numFound++; + continue; + } + // Get the contract instance let contractFromJSON = fs.readFileSync(configContracts[i]["artifact"], "utf8"); @@ -127,7 +136,7 @@ async function checkTokenomicsProxy(chainId, provider, globalsInstance, configCo const implementationHash = await tokenomics.PROXY_TOKENOMICS(); const implementation = await provider.getStorageAt(tokenomics.address, implementationHash); // Need to extract address size of bytes from the storage return value - customExpect("0x" + implementation.slice(-40), globalsInstance["tokenomicsTwoAddress"].toLowerCase(), + customExpect("0x" + implementation.slice(-40), globalsInstance["tokenomicsThreeAddress"].toLowerCase(), log + ", function: PROXY_TOKENOMICS()"); } @@ -166,7 +175,7 @@ async function checkTreasury(chainId, provider, globalsInstance, configContracts // Check paused const paused = await treasury.paused(); - customExpect(paused, false, log + ", function: paused()"); + customExpect(paused, 1, log + ", function: paused()"); } // Check Generic Bond Calculator: chain Id, provider, parsed globals, configuration contracts, contract name @@ -247,10 +256,400 @@ async function checkDepository(chainId, provider, globalsInstance, configContrac customExpect(minVesting, 3600 * 24, log + ", function: VERSION()"); } +// Check DepositProcessorL1: contract, globalsInstance +async function checkDepositProcessorL1(depositProcessorL1, globalsInstance, log) { + log += ", address: " + depositProcessorL1.address; + // Check contract owner + const owner = await depositProcessorL1.owner(); + customExpect(owner, AddressZero, log + ", function: owner()"); + + // Check L1 OLAS token + const olas = await depositProcessorL1.olas(); + customExpect(olas, globalsInstance["olasAddress"], log + ", function: olas()"); + + // Check L1 dispenser + const dispenser = await depositProcessorL1.l1Dispenser(); + customExpect(dispenser, globalsInstance["dispenserAddress"], log + ", function: dispenser ()"); +} + +// Check ArbitrumDepositProcessorL1: chain Id, provider, parsed globals, configuration contracts, contract name +async function checkArbitrumDepositProcessorL1(chainId, provider, globalsInstance, configContracts, contractName, log) { + // Check the bytecode + await checkBytecode(provider, configContracts, contractName, log); + + // Get the contract instance + const arbitrumDepositProcessorL1 = await findContractInstance(provider, configContracts, contractName); + + log += ", address: " + arbitrumDepositProcessorL1.address; + await checkDepositProcessorL1(arbitrumDepositProcessorL1, globalsInstance, log); + + // Check L1 token relayer + const l1TokenRelayer = await arbitrumDepositProcessorL1.l1TokenRelayer(); + customExpect(l1TokenRelayer, globalsInstance["arbitrumL1ERC20GatewayRouterAddress"], log + ", function: l1TokenRelayer()"); + + // Check L1 message relayer + const l1MessageRelayer = await arbitrumDepositProcessorL1.l1MessageRelayer(); + customExpect(l1MessageRelayer, globalsInstance["arbitrumInboxAddress"], log + ", function: l1MessageRelayer()"); + + // Check L2 target chain Id + const l2TargetChainId = await arbitrumDepositProcessorL1.l2TargetChainId(); + customExpect(l2TargetChainId.toString(), globalsInstance["arbitrumL2TargetChainId"], log + ", function: l2TargetChainId()"); + + // Check L1 ERC20Gateway + const l1ERC20Gateway = await arbitrumDepositProcessorL1.l1ERC20Gateway(); + customExpect(l1ERC20Gateway, globalsInstance["arbitrumL1ERC20GatewayAddress"], log + ", function: l1ERC20Gateway()"); + + // Check L1 outbox + const outbox = await arbitrumDepositProcessorL1.outbox(); + customExpect(outbox, globalsInstance["arbitrumOutboxAddress"], log + ", function: outbox()"); + + // Check L1 bridge + const bridge = await arbitrumDepositProcessorL1.bridge(); + customExpect(bridge, globalsInstance["arbitrumBridgeAddress"], log + ", function: bridge()"); + + // Check L2 target dispenser + const l2TargetDispenser = await arbitrumDepositProcessorL1.l2TargetDispenser(); + customExpect(l2TargetDispenser, globalsInstance["arbitrumTargetDispenserL2Address"], log + ", function: l2TargetDispenser()"); +} + +// Check checkEthereumDepositProcessor: chain Id, provider, parsed globals, configuration contracts, contract name +async function checkEthereumDepositProcessor(chainId, provider, globalsInstance, configContracts, contractName, log) { + // Check the bytecode + await checkBytecode(provider, configContracts, contractName, log); + + // Get the contract instance + const ethereumDepositProcessorL1 = await findContractInstance(provider, configContracts, contractName); + + log += ", address: " + ethereumDepositProcessorL1.address; + // Check OLAS token + const olas = await ethereumDepositProcessorL1.olas(); + customExpect(olas, globalsInstance["olasAddress"], log + ", function: olas()"); + + // Check dispenser + const dispenser = await ethereumDepositProcessorL1.dispenser(); + customExpect(dispenser, globalsInstance["dispenserAddress"], log + ", function: dispenser()"); + + // Check L1 staking factory + const stakingFactory = await ethereumDepositProcessorL1.stakingFactory(); + customExpect(stakingFactory, globalsInstance["serviceStakingFactoryAddress"], log + ", function: stakingFactory()"); + + // Check L1 timelock + const timelock = await ethereumDepositProcessorL1.timelock(); + customExpect(timelock, globalsInstance["timelockAddress"], log + ", function: timelock()"); +} + +// Check GnosisDepositProcessorL1: chain Id, provider, parsed globals, configuration contracts, contract name +async function checkGnosisDepositProcessorL1(chainId, provider, globalsInstance, configContracts, contractName, log) { + // Check the bytecode + await checkBytecode(provider, configContracts, contractName, log); + + // Get the contract instance + const gnosisDepositProcessorL1 = await findContractInstance(provider, configContracts, contractName); + + log += ", address: " + gnosisDepositProcessorL1.address; + await checkDepositProcessorL1(gnosisDepositProcessorL1, globalsInstance, log); + + // Check L1 token relayer + const l1TokenRelayer = await gnosisDepositProcessorL1.l1TokenRelayer(); + customExpect(l1TokenRelayer, globalsInstance["gnosisOmniBridgeAddress"], log + ", function: l1TokenRelayer()"); + + // Check L1 message relayer + const l1MessageRelayer = await gnosisDepositProcessorL1.l1MessageRelayer(); + customExpect(l1MessageRelayer, globalsInstance["gnosisAMBForeignAddress"], log + ", function: l1MessageRelayer()"); + + // Check L2 target chain Id + const l2TargetChainId = await gnosisDepositProcessorL1.l2TargetChainId(); + customExpect(l2TargetChainId.toString(), globalsInstance["gnosisL2TargetChainId"], log + ", function: l2TargetChainId()"); + + // Check L2 target dispenser + const l2TargetDispenser = await gnosisDepositProcessorL1.l2TargetDispenser(); + customExpect(l2TargetDispenser, globalsInstance["gnosisTargetDispenserL2Address"], log + ", function: l2TargetDispenser()"); +} + +// Check OptimismDepositProcessorL1: chain Id, provider, parsed globals, configuration contracts, contract name +async function checkOptimismDepositProcessorL1(chainId, provider, globalsInstance, configContracts, contractName, log) { + // Check the bytecode + await checkBytecode(provider, configContracts, contractName, log); + + // Get the contract instance + const optimismDepositProcessorL1 = await findContractInstance(provider, configContracts, contractName, 1); + + log += ", address: " + optimismDepositProcessorL1.address; + await checkDepositProcessorL1(optimismDepositProcessorL1, globalsInstance, log); + + // Check L1 token relayer + const l1TokenRelayer = await optimismDepositProcessorL1.l1TokenRelayer(); + customExpect(l1TokenRelayer, globalsInstance["optimisticL1StandardBridgeProxyAddress"], log + ", function: l1TokenRelayer()"); + + // Check L1 message relayer + const l1MessageRelayer = await optimismDepositProcessorL1.l1MessageRelayer(); + customExpect(l1MessageRelayer, globalsInstance["optimisticL1CrossDomainMessengerProxyAddress"], log + ", function: l1MessageRelayer()"); + + // Check L2 target chain Id + const l2TargetChainId = await optimismDepositProcessorL1.l2TargetChainId(); + customExpect(l2TargetChainId.toString(), globalsInstance["optimisticL2TargetChainId"], log + ", function: l2TargetChainId()"); + + // Check L2 OLAS address + const olasL2 = await optimismDepositProcessorL1.olasL2(); + customExpect(olasL2, globalsInstance["optimisticOLASAddress"], log + ", function: olasL2()"); + + // Check L2 target dispenser + const l2TargetDispenser = await optimismDepositProcessorL1.l2TargetDispenser(); + customExpect(l2TargetDispenser, globalsInstance["optimismTargetDispenserL2Address"], log + ", function: l2TargetDispenser()"); +} + +// Check BaseDepositProcessorL1: chain Id, provider, parsed globals, configuration contracts, contract name +async function checkBaseDepositProcessorL1(chainId, provider, globalsInstance, configContracts, contractName, log) { + // Check the bytecode + await checkBytecode(provider, configContracts, contractName, log); + + // Get the contract instance + const baseDepositProcessorL1 = await findContractInstance(provider, configContracts, contractName); + + log += ", address: " + baseDepositProcessorL1.address; + await checkDepositProcessorL1(baseDepositProcessorL1, globalsInstance, log); + + // Check L1 token relayer + const l1TokenRelayer = await baseDepositProcessorL1.l1TokenRelayer(); + customExpect(l1TokenRelayer, globalsInstance["baseL1StandardBridgeProxyAddress"], log + ", function: l1TokenRelayer()"); + + // Check L1 message relayer + const l1MessageRelayer = await baseDepositProcessorL1.l1MessageRelayer(); + customExpect(l1MessageRelayer, globalsInstance["baseL1CrossDomainMessengerProxyAddress"], log + ", function: l1MessageRelayer()"); + + // Check L2 target chain Id + const l2TargetChainId = await baseDepositProcessorL1.l2TargetChainId(); + customExpect(l2TargetChainId.toString(), globalsInstance["baseL2TargetChainId"], log + ", function: l2TargetChainId()"); + + // Check L2 OLAS address + const olasL2 = await baseDepositProcessorL1.olasL2(); + customExpect(olasL2, globalsInstance["baseOLASAddress"], log + ", function: olasL2()"); + + // Check L2 target dispenser + const l2TargetDispenser = await baseDepositProcessorL1.l2TargetDispenser(); + customExpect(l2TargetDispenser, globalsInstance["baseTargetDispenserL2Address"], log + ", function: l2TargetDispenser()"); +} + +// Check PolygonDepositProcessorL1: chain Id, provider, parsed globals, configuration contracts, contract name +async function checkPolygonDepositProcessorL1(chainId, provider, globalsInstance, configContracts, contractName, log) { + // Check the bytecode + await checkBytecode(provider, configContracts, contractName, log); + + // Get the contract instance + const polygonDepositProcessorL1 = await findContractInstance(provider, configContracts, contractName); + + log += ", address: " + polygonDepositProcessorL1.address; + await checkDepositProcessorL1(polygonDepositProcessorL1, globalsInstance, log); + + // Check L1 token relayer + const l1TokenRelayer = await polygonDepositProcessorL1.l1TokenRelayer(); + customExpect(l1TokenRelayer, globalsInstance["polygonRootChainManagerProxyAddress"], log + ", function: l1TokenRelayer()"); + + // Check L1 message relayer + const l1MessageRelayer = await polygonDepositProcessorL1.l1MessageRelayer(); + customExpect(l1MessageRelayer, globalsInstance["polygonFXRootAddress"], log + ", function: l1MessageRelayer()"); + + // Check L2 target chain Id + const l2TargetChainId = await polygonDepositProcessorL1.l2TargetChainId(); + customExpect(l2TargetChainId.toString(), globalsInstance["polygonL2TargetChainId"], log + ", function: l2TargetChainId()"); + + // Check L1 checkpoint manager + const checkpointManager = await polygonDepositProcessorL1.checkpointManager(); + customExpect(checkpointManager, globalsInstance["polygonCheckpointManagerAddress"], log + ", function: checkpointManager()"); + + // Check L1 predicate + const predicate = await polygonDepositProcessorL1.predicate(); + customExpect(predicate, globalsInstance["polygonERC20PredicateAddress"], log + ", function: predicate()"); + + // Check L2 target dispenser + const l2TargetDispenser = await polygonDepositProcessorL1.l2TargetDispenser(); + customExpect(l2TargetDispenser, globalsInstance["polygonTargetDispenserL2Address"], log + ", function: l2TargetDispenser()"); +} + +// Check CeloDepositProcessorL1: chain Id, provider, parsed globals, configuration contracts, contract name +async function checkCeloDepositProcessorL1(chainId, provider, globalsInstance, configContracts, contractName, log) { + // Check the bytecode + await checkBytecode(provider, configContracts, contractName, log); + + // Get the contract instance + const celoDepositProcessorL1 = await findContractInstance(provider, configContracts, contractName); + + log += ", address: " + celoDepositProcessorL1.address; + await checkDepositProcessorL1(celoDepositProcessorL1, globalsInstance, log); + + // Check L1 token relayer + const l1TokenRelayer = await celoDepositProcessorL1.l1TokenRelayer(); + customExpect(l1TokenRelayer, globalsInstance["wormholeL1TokenRelayerAddress"], log + ", function: l1TokenRelayer()"); + + // Check L1 message relayer + const l1MessageRelayer = await celoDepositProcessorL1.l1MessageRelayer(); + customExpect(l1MessageRelayer, globalsInstance["wormholeL1MessageRelayerAddress"], log + ", function: l1MessageRelayer()"); + + // Check L2 target chain Id + const l2TargetChainId = await celoDepositProcessorL1.l2TargetChainId(); + customExpect(l2TargetChainId.toString(), globalsInstance["celoL2TargetChainId"], log + ", function: l2TargetChainId()"); + + // Check L1 wormhole core + const wormhole = await celoDepositProcessorL1.wormhole(); + customExpect(wormhole, globalsInstance["wormholeL1CoreAddress"], log + ", function: wormhole()"); + + // Check L2 wormhole chain Id format + const wormholeTargetChainId = await celoDepositProcessorL1.wormholeTargetChainId(); + customExpect(wormholeTargetChainId.toString(), globalsInstance["celoWormholeL2TargetChainId"], log + ", function: wormholeTargetChainId()"); + + // Check L2 target dispenser + const l2TargetDispenser = await celoDepositProcessorL1.l2TargetDispenser(); + customExpect(l2TargetDispenser, globalsInstance["celoTargetDispenserL2Address"], log + ", function: l2TargetDispenser()"); +} + +// Check TargetDispenserL2: contract, globalsInstance +async function checkTargetDispenserL2(targetDispenserL2, globalsInstance, log) { + log += ", address: " + targetDispenserL2.address; + // Check contract owner + const owner = await targetDispenserL2.owner(); + customExpect(owner, globalsInstance["bridgeMediatorAddress"], log + ", function: owner()"); + + // Check L2 OLAS token + const olas = await targetDispenserL2.olas(); + customExpect(olas, globalsInstance["olasAddress"], log + ", function: olas()"); + + // Check L2 staking factory + const stakingFactory = await targetDispenserL2.stakingFactory(); + customExpect(stakingFactory, globalsInstance["serviceStakingFactoryAddress"], log + ", function: stakingFactory()"); + + // Check L1 source chain Id + const l1SourceChainId = await targetDispenserL2.l1SourceChainId(); + customExpect(l1SourceChainId.toString(), globalsInstance["l1ChainId"], log + ", function: l1SourceChainId()"); +} + +// Check PolygonTargetDispenserL2: chain Id, provider, parsed globals, configuration contracts, contract name +async function checkPolygonTargetDispenserL2(chainId, provider, globalsInstance, configContracts, contractName, log) { + // Check the bytecode + await checkBytecode(provider, configContracts, contractName, log); + + // Get the contract instance + const polygonTargetDispenserL2 = await findContractInstance(provider, configContracts, contractName); + + log += ", address: " + polygonTargetDispenserL2.address; + await checkTargetDispenserL2(polygonTargetDispenserL2, globalsInstance, log); + + // Check L2 message relayer + const l2MessageRelayer = await polygonTargetDispenserL2.l2MessageRelayer(); + customExpect(l2MessageRelayer, globalsInstance["polygonFXChildAddress"], log + ", function: l2MessageRelayer()"); + + // Check L1 deposit processor + const l1DepositProcessor = await polygonTargetDispenserL2.l1DepositProcessor(); + customExpect(l1DepositProcessor, globalsInstance["polygonDepositProcessorL1Address"], log + ", function: l1DepositProcessor()"); +} + +// Check GnosisTargetDispenserL2: chain Id, provider, parsed globals, configuration contracts, contract name +async function checkGnosisTargetDispenserL2(chainId, provider, globalsInstance, configContracts, contractName, log) { + // Check the bytecode + await checkBytecode(provider, configContracts, contractName, log); + + // Get the contract instance + const gnosisTargetDispenserL2 = await findContractInstance(provider, configContracts, contractName); + + log += ", address: " + gnosisTargetDispenserL2.address; + await checkTargetDispenserL2(gnosisTargetDispenserL2, globalsInstance, log); + + // Check L2 message relayer + const l2MessageRelayer = await gnosisTargetDispenserL2.l2MessageRelayer(); + customExpect(l2MessageRelayer, globalsInstance["gnosisAMBHomeAddress"], log + ", function: l2MessageRelayer()"); + + // Check L1 deposit processor + const l1DepositProcessor = await gnosisTargetDispenserL2.l1DepositProcessor(); + customExpect(l1DepositProcessor, globalsInstance["gnosisDepositProcessorL1Address"], log + ", function: l1DepositProcessor()"); +} + +// Check ArbitrumTargetDispenserL2: chain Id, provider, parsed globals, configuration contracts, contract name +async function checkArbitrumTargetDispenserL2(chainId, provider, globalsInstance, configContracts, contractName, log) { + // Check the bytecode + await checkBytecode(provider, configContracts, contractName, log); + + // Get the contract instance + const arbitrumTargetDispenserL2 = await findContractInstance(provider, configContracts, contractName); + + log += ", address: " + arbitrumTargetDispenserL2.address; + await checkTargetDispenserL2(arbitrumTargetDispenserL2, globalsInstance, log); + + // Check L2 message relayer + const l2MessageRelayer = await arbitrumTargetDispenserL2.l2MessageRelayer(); + customExpect(l2MessageRelayer, globalsInstance["arbitrumArbSysAddress"], log + ", function: l2MessageRelayer()"); + + // Check L1 deposit processor + const l1DepositProcessor = await arbitrumTargetDispenserL2.l1DepositProcessor(); + customExpect(l1DepositProcessor, globalsInstance["arbitrumDepositProcessorL1Address"], log + ", function: l1DepositProcessor()"); +} + +// Check OptimismTargetDispenserL2: chain Id, provider, parsed globals, configuration contracts, contract name +async function checkOptimismTargetDispenserL2(chainId, provider, globalsInstance, configContracts, contractName, log) { + // Check the bytecode + await checkBytecode(provider, configContracts, contractName, log); + + // Get the contract instance + const optimismTargetDispenserL2 = await findContractInstance(provider, configContracts, contractName); + + log += ", address: " + optimismTargetDispenserL2.address; + await checkTargetDispenserL2(optimismTargetDispenserL2, globalsInstance, log); + + // Check L2 message relayer + const l2MessageRelayer = await optimismTargetDispenserL2.l2MessageRelayer(); + customExpect(l2MessageRelayer, globalsInstance["optimisticL2CrossDomainMessengerAddress"], log + ", function: l2MessageRelayer()"); + + // Check L1 deposit processor + const l1DepositProcessor = await optimismTargetDispenserL2.l1DepositProcessor(); + customExpect(l1DepositProcessor, globalsInstance["optimismDepositProcessorL1Address"], log + ", function: l1DepositProcessor()"); +} + +// Check BaseTargetDispenserL2: chain Id, provider, parsed globals, configuration contracts, contract name +async function checkBaseTargetDispenserL2(chainId, provider, globalsInstance, configContracts, contractName, log) { + // Check the bytecode + await checkBytecode(provider, configContracts, contractName, log); + + // Get the contract instance + const baseTargetDispenserL2 = await findContractInstance(provider, configContracts, contractName); + + log += ", address: " + baseTargetDispenserL2.address; + await checkTargetDispenserL2(baseTargetDispenserL2, globalsInstance, log); + + // Check L2 message relayer + const l2MessageRelayer = await baseTargetDispenserL2.l2MessageRelayer(); + customExpect(l2MessageRelayer, globalsInstance["baseL2CrossDomainMessengerAddress"], log + ", function: l2MessageRelayer()"); + + // Check L1 deposit processor + const l1DepositProcessor = await baseTargetDispenserL2.l1DepositProcessor(); + customExpect(l1DepositProcessor, globalsInstance["baseDepositProcessorL1Address"], log + ", function: l1DepositProcessor()"); +} + +// Check CeloTargetDispenserL2: chain Id, provider, parsed globals, configuration contracts, contract name +async function checkCeloTargetDispenserL2(chainId, provider, globalsInstance, configContracts, contractName, log) { + // Check the bytecode + await checkBytecode(provider, configContracts, contractName, log); + + // Get the contract instance + const celoTargetDispenserL2 = await findContractInstance(provider, configContracts, contractName); + + log += ", address: " + celoTargetDispenserL2.address; + await checkTargetDispenserL2(celoTargetDispenserL2, globalsInstance, log); + + // Check L2 message relayer + const l2MessageRelayer = await celoTargetDispenserL2.l2MessageRelayer(); + customExpect(l2MessageRelayer, globalsInstance["wormholeL2MessageRelayer"], log + ", function: l2MessageRelayer()"); + + // Check L1 deposit processor + const l1DepositProcessor = await celoTargetDispenserL2.l1DepositProcessor(); + customExpect(l1DepositProcessor, globalsInstance["celoDepositProcessorL1Address"], log + ", function: l1DepositProcessor()"); + + // Check L2 wormhole core + const wormhole = await celoTargetDispenserL2.wormhole(); + customExpect(wormhole, globalsInstance["wormholeL2CoreAddress"], log + ", function: wormhole()"); +} + async function main() { // Check for the API keys - if (!process.env.ALCHEMY_API_KEY_MAINNET || !process.env.ALCHEMY_API_KEY_GOERLI || - !process.env.ALCHEMY_API_KEY_MATIC || !process.env.ALCHEMY_API_KEY_MUMBAI) { + if (!process.env.ALCHEMY_API_KEY_MAINNET || !process.env.ALCHEMY_API_KEY_SEPOLIA || + !process.env.ALCHEMY_API_KEY_MATIC || !process.env.ALCHEMY_API_KEY_AMOY) { console.log("Check API keys!"); return; } @@ -260,87 +659,144 @@ async function main() { const dataFromJSON = fs.readFileSync(configFile, "utf8"); const configs = JSON.parse(dataFromJSON); - const numChains = configs.length; // ################################# VERIFY CONTRACTS WITH REPO ################################# - // For now gnosis chains are not supported - const networks = { - "mainnet": "etherscan", - "goerli": "goerli.etherscan", - }; - console.log("\nVerifying deployed contracts vs the repo... If no error is output, then the contracts are correct."); - // Traverse all chains - for (let i = 0; i < numChains; i++) { - // Skip gnosis chains - if (!networks[configs[i]["name"]]) { + // Currently the verification is fo mainnet only + const network = "etherscan"; + const contracts = configs[0]["contracts"]; + + // Verify contracts + for (let i = 0; i < contracts.length; i++) { + console.log("Checking " + contracts[i]["name"]); + const execSync = require("child_process").execSync; + try { + execSync("scripts/audit_chains/audit_repo_contract.sh " + network + " " + contracts[i]["name"] + " " + contracts[i]["address"]); + } catch (error) { continue; } - - console.log("\n\nNetwork:", configs[i]["name"]); - const network = networks[configs[i]["name"]]; - const contracts = configs[i]["contracts"]; - - // Verify contracts - for (let j = 0; j < contracts.length; j++) { - console.log("Checking " + contracts[j]["name"]); - const execSync = require("child_process").execSync; - try { - execSync("scripts/audit_chains/audit_repo_contract.sh " + network + " " + contracts[j]["name"] + " " + contracts[j]["address"]); - } catch (error) { - continue; - } - } } // ################################# /VERIFY CONTRACTS WITH REPO ################################# // ################################# VERIFY CONTRACTS SETUP ################################# const globalNames = { "mainnet": "scripts/deployment/globals_mainnet.json", - "goerli": "scripts/deployment/globals_goerli.json", + "polygon": "scripts/deployment/staking/polygon/globals_polygon_mainnet.json", + "gnosis": "scripts/deployment/staking/gnosis/globals_gnosis_mainnet.json", + "arbitrumOne": "scripts/deployment/staking/arbitrum/globals_arbitrum_one.json", + "optimistic": "scripts/deployment/staking/optimistic/globals_optimistic_mainnet.json", + "base": "scripts/deployment/staking/base/globals_base_mainnet.json", + "celo": "scripts/deployment/staking/celo/globals_celo_mainnet.json" }; + const globals = new Array(); + for (let k in globalNames) { + const dataJSON = fs.readFileSync(globalNames[k], "utf8"); + globals.push(JSON.parse(dataJSON)); + } + // Special case for staking (also on L1) + const dataJSON = fs.readFileSync("scripts/deployment/staking/globals_mainnet.json", "utf8"); + const globalsStaking = JSON.parse(dataJSON); + + const providerLinks = { "mainnet": "https://eth-mainnet.g.alchemy.com/v2/" + process.env.ALCHEMY_API_KEY_MAINNET, - "goerli": "https://eth-goerli.g.alchemy.com/v2/" + process.env.ALCHEMY_API_KEY_GOERLI, + "polygon": "https://polygon-mainnet.g.alchemy.com/v2/" + process.env.ALCHEMY_API_KEY_MATIC, + "gnosis": "https://rpc.gnosischain.com", + "arbitrumOne": "https://arb1.arbitrum.io/rpc", + "optimistic": "https://optimism.drpc.org", + "base": "https://mainnet.base.org", + "celo": "https://forno.celo.org" }; - // Get all the globals processed - const globals = new Array(); const providers = new Array(); - for (let i = 0; i < numChains; i++) { - const dataJSON = fs.readFileSync(globalNames[configs[i]["name"]], "utf8"); - globals.push(JSON.parse(dataJSON)); - const provider = new ethers.providers.JsonRpcProvider(providerLinks[configs[i]["name"]]); + for (let k in providerLinks) { + const provider = new ethers.providers.JsonRpcProvider(providerLinks[k]); providers.push(provider); } console.log("\nVerifying deployed contracts setup... If no error is output, then the contracts are correct."); // L1 contracts - for (let i = 0; i < 2; i++) { - console.log("\n######## Verifying setup on CHAIN ID", configs[i]["chainId"]); + console.log("\n######## Verifying setup on CHAIN ID", configs[0]["chainId"]); - const initLog = "ChainId: " + configs[i]["chainId"] + ", network: " + configs[i]["name"]; + let initLog = "ChainId: " + configs[0]["chainId"] + ", network: " + configs[0]["name"]; - let log = initLog + ", contract: " + "DonatorBlacklist"; - await checkDonatorBlacklist(configs[i]["chainId"], providers[i], globals[i], configs[i]["contracts"], "DonatorBlacklist", log); + let log = initLog + ", contract: " + "DonatorBlacklist"; + await checkDonatorBlacklist(configs[0]["chainId"], providers[0], globals[0], configs[0]["contracts"], "DonatorBlacklist", log); - log = initLog + ", contract: " + "TokenomicsProxy"; - await checkTokenomicsProxy(configs[i]["chainId"], providers[i], globals[i], configs[i]["contracts"], "TokenomicsProxy", log); + log = initLog + ", contract: " + "TokenomicsProxy"; + await checkTokenomicsProxy(configs[0]["chainId"], providers[0], globals[0], configs[0]["contracts"], "TokenomicsProxy", log); - log = initLog + ", contract: " + "Treasury"; - await checkTreasury(configs[i]["chainId"], providers[i], globals[i], configs[i]["contracts"], "Treasury", log); + log = initLog + ", contract: " + "Treasury"; + await checkTreasury(configs[0]["chainId"], providers[0], globals[0], configs[0]["contracts"], "Treasury", log); - log = initLog + ", contract: " + "GenericBondCalculator"; - await checkGenericBondCalculator(configs[i]["chainId"], providers[i], globals[i], configs[i]["contracts"], "GenericBondCalculator", log); + log = initLog + ", contract: " + "GenericBondCalculator"; + await checkGenericBondCalculator(configs[0]["chainId"], providers[0], globals[0], configs[0]["contracts"], "GenericBondCalculator", log); - log = initLog + ", contract: " + "Dispenser"; - await checkDispenser(configs[i]["chainId"], providers[i], globals[i], configs[i]["contracts"], "Dispenser", log); + log = initLog + ", contract: " + "Dispenser"; + await checkDispenser(configs[0]["chainId"], providers[0], globals[0], configs[0]["contracts"], "Dispenser", log); - log = initLog + ", contract: " + "Depository"; - await checkDepository(configs[i]["chainId"], providers[i], globals[i], configs[i]["contracts"], "Depository", log); - } + log = initLog + ", contract: " + "Depository"; + await checkDepository(configs[0]["chainId"], providers[0], globals[0], configs[0]["contracts"], "Depository", log); + + log = initLog + ", contract: " + "ArbitrumDepositProcessorL1"; + await checkArbitrumDepositProcessorL1(configs[0]["chainId"], providers[0], globalsStaking, configs[0]["contracts"], "ArbitrumDepositProcessorL1", log); + + log = initLog + ", contract: " + "EthereumDepositProcessor"; + await checkEthereumDepositProcessor(configs[0]["chainId"], providers[0], globalsStaking, configs[0]["contracts"], "EthereumDepositProcessor", log); + + log = initLog + ", contract: " + "GnosisDepositProcessorL1"; + await checkGnosisDepositProcessorL1(configs[0]["chainId"], providers[0], globalsStaking, configs[0]["contracts"], "GnosisDepositProcessorL1", log); + + log = initLog + ", contract: " + "OptimismDepositProcessorL1"; + await checkOptimismDepositProcessorL1(configs[0]["chainId"], providers[0], globalsStaking, configs[0]["contracts"], "OptimismDepositProcessorL1", log); + + log = initLog + ", contract: " + "BaseDepositProcessorL1"; + await checkBaseDepositProcessorL1(configs[0]["chainId"], providers[0], globalsStaking, configs[0]["contracts"], "OptimismDepositProcessorL1", log); + + log = initLog + ", contract: " + "PolygonDepositProcessorL1"; + await checkPolygonDepositProcessorL1(configs[0]["chainId"], providers[0], globalsStaking, configs[0]["contracts"], "PolygonDepositProcessorL1", log); + + log = initLog + ", contract: " + "CeloDepositProcessorL1"; + await checkCeloDepositProcessorL1(configs[0]["chainId"], providers[0], globalsStaking, configs[0]["contracts"], "WormholeDepositProcessorL1", log); + + // L2 contracts + // Polygon + console.log("\n######## Verifying setup on CHAIN ID", configs[11]["chainId"]); + initLog = "ChainId: " + configs[11]["chainId"] + ", network: " + configs[11]["name"]; + log = initLog + ", contract: " + "PolygonTargetDispenserL2"; + await checkPolygonTargetDispenserL2(configs[11]["chainId"], providers[1], globals[1], configs[11]["contracts"], "PolygonTargetDispenserL2", log); + + // Gnosis + console.log("\n######## Verifying setup on CHAIN ID", configs[7]["chainId"]); + initLog = "ChainId: " + configs[7]["chainId"] + ", network: " + configs[7]["name"]; + log = initLog + ", contract: " + "GnosisTargetDispenserL2"; + await checkGnosisTargetDispenserL2(configs[7]["chainId"], providers[2], globals[2], configs[7]["contracts"], "GnosisTargetDispenserL2", log); + + // Arbitrum + console.log("\n######## Verifying setup on CHAIN ID", configs[1]["chainId"]); + initLog = "ChainId: " + configs[1]["chainId"] + ", network: " + configs[1]["name"]; + log = initLog + ", contract: " + "ArbitrumTargetDispenserL2"; + await checkArbitrumTargetDispenserL2(configs[1]["chainId"], providers[3], globals[3], configs[1]["contracts"], "ArbitrumTargetDispenserL2", log); + + // Base + console.log("\n######## Verifying setup on CHAIN ID", configs[3]["chainId"]); + initLog = "ChainId: " + configs[3]["chainId"] + ", network: " + configs[3]["name"]; + log = initLog + ", contract: " + "BaseTargetDispenserL2"; + await checkBaseTargetDispenserL2(configs[3]["chainId"], providers[5], globals[5], configs[3]["contracts"], "OptimismTargetDispenserL2", log); + + // Celo + console.log("\n######## Verifying setup on CHAIN ID", configs[5]["chainId"]); + initLog = "ChainId: " + configs[5]["chainId"] + ", network: " + configs[5]["name"]; + log = initLog + ", contract: " + "CeloTargetDispenserL2"; + await checkCeloTargetDispenserL2(configs[5]["chainId"], providers[6], globals[6], configs[5]["contracts"], "WormholeTargetDispenserL2", log); + + // Optimism + console.log("\n######## Verifying setup on CHAIN ID", configs[9]["chainId"]); + initLog = "ChainId: " + configs[9]["chainId"] + ", network: " + configs[9]["name"]; + log = initLog + ", contract: " + "OptimismTargetDispenserL2"; + await checkOptimismTargetDispenserL2(configs[9]["chainId"], providers[4], globals[4], configs[9]["contracts"], "OptimismTargetDispenserL2", log); // ################################# /VERIFY CONTRACTS SETUP ################################# } diff --git a/scripts/deployment/README.md b/scripts/deployment/README.md index 1376022f..66b9e2e0 100644 --- a/scripts/deployment/README.md +++ b/scripts/deployment/README.md @@ -1,5 +1,8 @@ # Deployment scripts -This folder contains the scripts to deploy Autonolas tokenomics. These scripts correspond to the steps in the full deployment procedure (as described in [deployment.md](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/docs/deployment.md)). +This folder contains the scripts to deploy Autonolas tokenomics. +These scripts correspond to the steps in the full deployment procedure (as described in [deployment.md](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/docs/deployment.md)). + +For the Tokenomics 1.2, refer to the following deployment procedure: [deployment_v1.2.md](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/docs/deployment_v1.2.md). ## Observations - There are several files with global parameters based on the corresponding network. In order to work with the configuration, please copy `gobals_network.json` file to file the `gobals.json` one, where `network` is the corresponding network. For example: `cp gobals_goerli.json gobals.json`. diff --git a/scripts/deployment/deploy_07_dispenser.js b/scripts/deployment/deploy_07_dispenser.js index f62d53f7..9fb45ef4 100644 --- a/scripts/deployment/deploy_07_dispenser.js +++ b/scripts/deployment/deploy_07_dispenser.js @@ -26,25 +26,35 @@ async function main() { console.log("EOA is:", deployer); // Get all the necessary contract addresses + const olasAddress = parsedData.olasAddress; const tokenomicsProxyAddress = parsedData.tokenomicsProxyAddress; const treasuryAddress = parsedData.treasuryAddress; + const voteWeightingAddress = parsedData.voteWeightingAddress; + const retainerAddress = parsedData.retainerAddress; + const maxNumClaimingEpochs = parsedData.maxNumClaimingEpochs; + const maxNumStakingTargets = parsedData.maxNumStakingTargets; + const minStakingWeight = parsedData.minStakingWeight; + const maxStakingIncentive = parsedData.maxStakingIncentive; // Transaction signing and execution console.log("7. EOA to deploy Dispenser"); const Dispenser = await ethers.getContractFactory("Dispenser"); console.log("You are signing the following transaction: Dispenser.connect(EOA).deploy()"); - const dispenser = await Dispenser.connect(EOA).deploy(tokenomicsProxyAddress, treasuryAddress); + const dispenser = await Dispenser.connect(EOA).deploy(olasAddress, tokenomicsProxyAddress, treasuryAddress, + voteWeightingAddress, retainerAddress, maxNumClaimingEpochs, maxNumStakingTargets, minStakingWeight, + maxStakingIncentive); const result = await dispenser.deployed(); - // If on goerli, wait a minute for the transaction completion - if (providerName === "goerli") { - await new Promise(r => setTimeout(r, 60000)); - } // Transaction details console.log("Contract deployment: Dispenser"); console.log("Contract address:", dispenser.address); console.log("Transaction:", result.deployTransaction.hash); + // If on sepolia, wait half a minute for the transaction completion + if (providerName === "sepolia") { + await new Promise(r => setTimeout(r, 30000)); + } + // Contract verification if (parsedData.contractVerification) { const execSync = require("child_process").execSync; diff --git a/scripts/deployment/globals_mainnet.json b/scripts/deployment/globals_mainnet.json index 3f165c8f..9344fce1 100644 --- a/scripts/deployment/globals_mainnet.json +++ b/scripts/deployment/globals_mainnet.json @@ -1 +1 @@ -{"contractVerification":true,"useLedger":true,"derivationPath":"m/44'/60'/2'/0/0","providerName":"mainnet","olasAddress":"0x0001A500A6B18995B03f44bb040A5fFc28E45CB0","timelockAddress":"0x3C1fF68f5aa342D296d4DEe4Bb1cACCA912D95fE","veOLASAddress":"0x7e01A500805f8A52Fad229b3015AD130A332B7b3","governorAddress":"0x34C895f302D0b5cf52ec0Edd3945321EB0f83dd5","governorTwoAddress":"0x4E3e48bA826b15214FDe72a50BFd17aB286B584E","componentRegistryAddress":"0x15bd56669F57192a97dF41A2aa8f4403e9491776","agentRegistryAddress":"0x2F1f7D38e4772884b88f3eCd8B6b9faCdC319112","serviceRegistryAddress":"0x48b6af7B12C71f09e2fC8aF4855De4Ff54e775cA","epochLen":"2592000","donatorBlacklistAddress":"0xE85791B18F5df42163092Acc5C9da1c479AFEa9d","tokenomicsAddress":"0x87f89F94033305791B6269AE2F9cF4e09983E56e","tokenomicsProxyAddress":"0xc096362fa6f4A4B1a9ea68b1043416f3381ce300","treasuryAddress":"0xa0DA53447C0f6C4987964d8463da7e6628B30f82","genericBondCalculatorAddress":"0x1521918961bDBC9Ed4C67a7103D5999e4130E6CB","depositoryAddress":"0x52A043bcebdB2f939BaEF2E8b6F01652290eAB3f","dispenserAddress":"0xeED0000fE94d7cfeF4Dc0CA86a223f0F603A61B8","tokenomicsTwoAddress":"0xD599ED4a5c45Fa66AA3C474b00701Fd452a2C30e","OLAS_ETH_PairAddress":"0x09D1d767eDF8Fa23A64C51fa559E0688E526812F","depositoryTwoAddress":"0xfF8697d8d2998d6AA2e09B405795C6F4BEeB0C81","XOLAS_WXDAI_PairAddress":"0x27df632fd0dcf191C418c803801D521cd579F18e","tokenomicsThreeAddress":"0x2C1633765c66a7CF0EC801a1046347bBee7344C9"} \ No newline at end of file +{"contractVerification":true,"useLedger":true,"derivationPath":"m/44'/60'/2'/0/0","providerName":"mainnet","olasAddress":"0x0001A500A6B18995B03f44bb040A5fFc28E45CB0","timelockAddress":"0x3C1fF68f5aa342D296d4DEe4Bb1cACCA912D95fE","veOLASAddress":"0x7e01A500805f8A52Fad229b3015AD130A332B7b3","governorAddress":"0x34C895f302D0b5cf52ec0Edd3945321EB0f83dd5","governorTwoAddress":"0x4E3e48bA826b15214FDe72a50BFd17aB286B584E","componentRegistryAddress":"0x15bd56669F57192a97dF41A2aa8f4403e9491776","agentRegistryAddress":"0x2F1f7D38e4772884b88f3eCd8B6b9faCdC319112","serviceRegistryAddress":"0x48b6af7B12C71f09e2fC8aF4855De4Ff54e775cA","epochLen":"2592000","donatorBlacklistAddress":"0xE85791B18F5df42163092Acc5C9da1c479AFEa9d","tokenomicsAddress":"0x87f89F94033305791B6269AE2F9cF4e09983E56e","tokenomicsProxyAddress":"0xc096362fa6f4A4B1a9ea68b1043416f3381ce300","treasuryAddress":"0xa0DA53447C0f6C4987964d8463da7e6628B30f82","genericBondCalculatorAddress":"0x1521918961bDBC9Ed4C67a7103D5999e4130E6CB","depositoryAddress":"0x52A043bcebdB2f939BaEF2E8b6F01652290eAB3f","dispenserAddress":"0x5650300fCBab43A0D7D02F8Cb5d0f039402593f0","tokenomicsTwoAddress":"0xD599ED4a5c45Fa66AA3C474b00701Fd452a2C30e","OLAS_ETH_PairAddress":"0x09D1d767eDF8Fa23A64C51fa559E0688E526812F","depositoryTwoAddress":"0xfF8697d8d2998d6AA2e09B405795C6F4BEeB0C81","XOLAS_WXDAI_PairAddress":"0x27df632fd0dcf191C418c803801D521cd579F18e","tokenomicsThreeAddress":"0x2C1633765c66a7CF0EC801a1046347bBee7344C9","voteWeightingAddress":"0x95418b46d5566d3d1ea62c12aea91227e566c5c1","retainerAddress":"0x000000000000000000000000000000000000000000000000000000000000dEaD","maxNumClaimingEpochs":"1","maxNumStakingTargets":"10","minStakingWeight":"100","maxStakingIncentive":"30000000000000000000000"} \ No newline at end of file diff --git a/scripts/deployment/staking/arbitrum/deploy_21_change_owner.js b/scripts/deployment/staking/arbitrum/deploy_21_change_owner.js new file mode 100644 index 00000000..f05cdf37 --- /dev/null +++ b/scripts/deployment/staking/arbitrum/deploy_21_change_owner.js @@ -0,0 +1,48 @@ +/*global process*/ + +const { ethers } = require("hardhat"); +const { LedgerSigner } = require("@anders-t/ethers-ledger"); + +async function main() { + const fs = require("fs"); + const globalsFile = "globals.json"; + const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); + let parsedData = JSON.parse(dataFromJSON); + const useLedger = parsedData.useLedger; + const derivationPath = parsedData.derivationPath; + const providerName = parsedData.providerName; + const arbitrumTargetDispenserL2Address = parsedData.arbitrumTargetDispenserL2Address; + const bridgeMediatorAddress = parsedData.bridgeMediatorAddress; + + let networkURL = parsedData.networkURL; + const provider = new ethers.providers.JsonRpcProvider(networkURL); + const signers = await ethers.getSigners(); + + let EOA; + if (useLedger) { + EOA = new LedgerSigner(provider, derivationPath); + } else { + EOA = signers[0]; + } + // EOA address + const deployer = await EOA.getAddress(); + console.log("EOA is:", deployer); + + // Transaction signing and execution + console.log("21. EOA to change owner in ArbitrumTargetDispenserL2"); + const arbitrumTargetDispenserL2 = await ethers.getContractAt("ArbitrumTargetDispenserL2", arbitrumTargetDispenserL2Address); + console.log("You are signing the following transaction: ArbitrumTargetDispenserL2.connect(EOA).changeOwner()"); + const result = await arbitrumTargetDispenserL2.connect(EOA).changeOwner(bridgeMediatorAddress); + + // Transaction details + console.log("Contract deployment: ArbitrumTargetDispenserL2"); + console.log("Contract address:", arbitrumTargetDispenserL2.address); + console.log("Transaction:", result.hash); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/scripts/deployment/staking/arbitrum/globals_arbitrum_one.json b/scripts/deployment/staking/arbitrum/globals_arbitrum_one.json new file mode 100644 index 00000000..cc50b481 --- /dev/null +++ b/scripts/deployment/staking/arbitrum/globals_arbitrum_one.json @@ -0,0 +1 @@ +{"contractVerification":true,"useLedger":true,"derivationPath":"m/44'/60'/2'/0/0","providerName":"arbitrumOne","networkURL":"https://arb1.arbitrum.io/rpc","gasPriceInGwei":"5","olasAddress":"0x064F8B858C2A603e1b106a2039f5446D32dc81c1","serviceStakingFactoryAddress":"0xEB5638eefE289691EcE01943f768EDBF96258a80","bridgeMediatorAddress":"0x4d30F68F5AA342d296d4deE4bB1Cacca912dA70F","arbitrumArbSysAddress":"0x0000000000000000000000000000000000000064","l1ChainId":"1","arbitrumDepositProcessorL1Address":"0x5e13E07006D68B097DCb5979ef5545C4f9156162","arbitrumTargetDispenserL2Address":"0x10c5525F77F13b28f42c5626240c001c2D57CAd4"} \ No newline at end of file diff --git a/scripts/deployment/staking/arbitrum/send_tokens_and_message.js b/scripts/deployment/staking/arbitrum/send_tokens_and_message.js index a691b901..482790f2 100644 --- a/scripts/deployment/staking/arbitrum/send_tokens_and_message.js +++ b/scripts/deployment/staking/arbitrum/send_tokens_and_message.js @@ -163,7 +163,7 @@ const main = async () => { await tx.wait(); // tx back to L1: https://sepolia.arbiscan.io/tx/0xea8119b1030bb223a896680d9c4ea03877beee08927ef1b8a9532ce48db68c55 - // Finalized tx on L1: + // Finalized tx on L1: https://sepolia.etherscan.io/tx/0x5f61dd72b5feb31af563f7af76402e523e1e871bdac7f1a82bb0ffefcd333ebb // Use the following script to finalize L2-L1 transaction: // https://github.com/OffchainLabs/arbitrum-tutorials/blob/master/packages/outbox-execute/scripts/exec.js diff --git a/scripts/deployment/staking/base/deploy_07_base_targer_dispenser.js b/scripts/deployment/staking/base/deploy_07_base_targer_dispenser.js new file mode 100644 index 00000000..13bd32fc --- /dev/null +++ b/scripts/deployment/staking/base/deploy_07_base_targer_dispenser.js @@ -0,0 +1,75 @@ +/*global process*/ + +const { ethers } = require("hardhat"); +const { LedgerSigner } = require("@anders-t/ethers-ledger"); + +async function main() { + const fs = require("fs"); + const globalsFile = "globals.json"; + const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); + let parsedData = JSON.parse(dataFromJSON); + const useLedger = parsedData.useLedger; + const derivationPath = parsedData.derivationPath; + const providerName = parsedData.providerName; + + let networkURL = parsedData.networkURL; + if (providerName === "polygon") { + if (!process.env.ALCHEMY_API_KEY_MATIC) { + console.log("set ALCHEMY_API_KEY_MATIC env variable"); + } + networkURL += process.env.ALCHEMY_API_KEY_MATIC; + } else if (providerName === "polygonAmoy") { + if (!process.env.ALCHEMY_API_KEY_AMOY) { + console.log("set ALCHEMY_API_KEY_AMOY env variable"); + return; + } + networkURL += process.env.ALCHEMY_API_KEY_AMOY; + } + + const provider = new ethers.providers.JsonRpcProvider(networkURL); + const signers = await ethers.getSigners(); + + let EOA; + if (useLedger) { + EOA = new LedgerSigner(provider, derivationPath); + } else { + EOA = signers[0]; + } + // EOA address + const deployer = await EOA.getAddress(); + console.log("EOA is:", deployer); + + // Transaction signing and execution + console.log("7. EOA to deploy OptimismTargetDispenserL2 for Base"); + const OptimismTargetDispenserL2 = await ethers.getContractFactory("OptimismTargetDispenserL2"); + console.log("You are signing the following transaction: OptimismTargetDispenserL2.connect(EOA).deploy()"); + const baseTargetDispenserL2 = await OptimismTargetDispenserL2.connect(EOA).deploy(parsedData.olasAddress, + parsedData.serviceStakingFactoryAddress, parsedData.baseL2CrossDomainMessengerAddress, + parsedData.baseDepositProcessorL1Address, parsedData.l1ChainId); + const result = await baseTargetDispenserL2.deployed(); + + // Transaction details + console.log("Contract deployment: OptimismTargetDispenserL2"); + console.log("Contract address:", baseTargetDispenserL2.address); + console.log("Transaction:", result.deployTransaction.hash); + + // Wait for half a minute for the transaction completion + await new Promise(r => setTimeout(r, 30000)); + + // Writing updated parameters back to the JSON file + parsedData.baseTargetDispenserL2Address = baseTargetDispenserL2.address; + fs.writeFileSync(globalsFile, JSON.stringify(parsedData)); + + // Contract verification + if (parsedData.contractVerification) { + const execSync = require("child_process").execSync; + execSync("npx hardhat verify --constructor-args scripts/deployment/staking/optimistic/verify_07_base_target_dispenser.js --network " + providerName + " " + baseTargetDispenserL2.address, { encoding: "utf-8" }); + } +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/scripts/deployment/staking/base/deploy_71_change_owner.js b/scripts/deployment/staking/base/deploy_71_change_owner.js new file mode 100644 index 00000000..d959f2e7 --- /dev/null +++ b/scripts/deployment/staking/base/deploy_71_change_owner.js @@ -0,0 +1,48 @@ +/*global process*/ + +const { ethers } = require("hardhat"); +const { LedgerSigner } = require("@anders-t/ethers-ledger"); + +async function main() { + const fs = require("fs"); + const globalsFile = "globals.json"; + const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); + let parsedData = JSON.parse(dataFromJSON); + const useLedger = parsedData.useLedger; + const derivationPath = parsedData.derivationPath; + const providerName = parsedData.providerName; + const baseTargetDispenserL2Address = parsedData.baseTargetDispenserL2Address; + const bridgeMediatorAddress = parsedData.bridgeMediatorAddress; + + let networkURL = parsedData.networkURL; + const provider = new ethers.providers.JsonRpcProvider(networkURL); + const signers = await ethers.getSigners(); + + let EOA; + if (useLedger) { + EOA = new LedgerSigner(provider, derivationPath); + } else { + EOA = signers[0]; + } + // EOA address + const deployer = await EOA.getAddress(); + console.log("EOA is:", deployer); + + // Transaction signing and execution + console.log("71. EOA to change owner in OptimismTargetDispenserL2 (Base)"); + const baseTargetDispenserL2 = await ethers.getContractAt("OptimismTargetDispenserL2", baseTargetDispenserL2Address); + console.log("You are signing the following transaction: OptimismTargetDispenserL2.connect(EOA).changeOwner()"); + const result = await baseTargetDispenserL2.connect(EOA).changeOwner(bridgeMediatorAddress); + + // Transaction details + console.log("Contract deployment: OptimismTargetDispenserL2"); + console.log("Contract address:", baseTargetDispenserL2.address); + console.log("Transaction:", result.hash); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/scripts/deployment/staking/base/globals_base_mainnet.json b/scripts/deployment/staking/base/globals_base_mainnet.json new file mode 100644 index 00000000..0feae934 --- /dev/null +++ b/scripts/deployment/staking/base/globals_base_mainnet.json @@ -0,0 +1 @@ +{"contractVerification":true,"useLedger":true,"derivationPath":"m/44'/60'/2'/0/0","providerName":"base","networkURL":"https://mainnet.base.org","gasPriceInGwei":"2","olasAddress":"0x54330d28ca3357F294334BDC454a032e7f353416","serviceStakingFactoryAddress":"0x1cEe30D08943EB58EFF84DD1AB44a6ee6FEff63a","bridgeMediatorAddress":"0xE49CB081e8d96920C38aA7AB90cb0294ab4Bc8EA","baseL2CrossDomainMessengerAddress":"0x4200000000000000000000000000000000000007","l1ChainId":"1","baseDepositProcessorL1Address":"0x42BA1BbD797E4C90F386F03a544F3b62C1f917d0","baseTargetDispenserL2Address":"0xcDdD9D9ABaB36fFa882530D69c73FeE5D4001C2d"} \ No newline at end of file diff --git a/scripts/deployment/staking/base/verify_07_base_target_dispenser.js b/scripts/deployment/staking/base/verify_07_base_target_dispenser.js new file mode 100644 index 00000000..be0fd403 --- /dev/null +++ b/scripts/deployment/staking/base/verify_07_base_target_dispenser.js @@ -0,0 +1,12 @@ +const fs = require("fs"); +const globalsFile = "globals.json"; +const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); +const parsedData = JSON.parse(dataFromJSON); + +module.exports = [ + parsedData.olasAddress, + parsedData.serviceStakingFactoryAddress, + parsedData.baseL2CrossDomainMessengerAddress, + parsedData.baseDepositProcessorL1Address, + parsedData.l1ChainId +]; \ No newline at end of file diff --git a/scripts/deployment/staking/celo/deploy_051_change_owner.js b/scripts/deployment/staking/celo/deploy_051_change_owner.js new file mode 100644 index 00000000..6ca830ec --- /dev/null +++ b/scripts/deployment/staking/celo/deploy_051_change_owner.js @@ -0,0 +1,48 @@ +/*global process*/ + +const { ethers } = require("hardhat"); +const { LedgerSigner } = require("@anders-t/ethers-ledger"); + +async function main() { + const fs = require("fs"); + const globalsFile = "globals.json"; + const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); + let parsedData = JSON.parse(dataFromJSON); + const useLedger = parsedData.useLedger; + const derivationPath = parsedData.derivationPath; + const providerName = parsedData.providerName; + const celoTargetDispenserL2Address = parsedData.celoTargetDispenserL2Address; + const bridgeMediatorAddress = parsedData.bridgeMediatorAddress; + + let networkURL = parsedData.networkURL; + const provider = new ethers.providers.JsonRpcProvider(networkURL); + const signers = await ethers.getSigners(); + + let EOA; + if (useLedger) { + EOA = new LedgerSigner(provider, derivationPath); + } else { + EOA = signers[0]; + } + // EOA address + const deployer = await EOA.getAddress(); + console.log("EOA is:", deployer); + + // Transaction signing and execution + console.log("51. EOA to change owner in WormholeTargetDispenserL2 (Celo)"); + const celoTargetDispenserL2 = await ethers.getContractAt("WormholeTargetDispenserL2", celoTargetDispenserL2Address); + console.log("You are signing the following transaction: WormholeTargetDispenserL2.connect(EOA).changeOwner()"); + const result = await celoTargetDispenserL2.connect(EOA).changeOwner(bridgeMediatorAddress); + + // Transaction details + console.log("Contract deployment: WormholeTargetDispenserL2"); + console.log("Contract address:", celoTargetDispenserL2.address); + console.log("Transaction:", result.hash); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/scripts/deployment/staking/celo/deploy_05_celo_targer_dispenser.js b/scripts/deployment/staking/celo/deploy_05_celo_targer_dispenser.js new file mode 100644 index 00000000..cfe1d7b6 --- /dev/null +++ b/scripts/deployment/staking/celo/deploy_05_celo_targer_dispenser.js @@ -0,0 +1,76 @@ +/*global process*/ + +const { ethers } = require("hardhat"); +const { LedgerSigner } = require("@anders-t/ethers-ledger"); + +async function main() { + const fs = require("fs"); + const globalsFile = "globals.json"; + const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); + let parsedData = JSON.parse(dataFromJSON); + const useLedger = parsedData.useLedger; + const derivationPath = parsedData.derivationPath; + const providerName = parsedData.providerName; + + let networkURL = parsedData.networkURL; + if (providerName === "polygon") { + if (!process.env.ALCHEMY_API_KEY_MATIC) { + console.log("set ALCHEMY_API_KEY_MATIC env variable"); + } + networkURL += process.env.ALCHEMY_API_KEY_MATIC; + } else if (providerName === "polygonAmoy") { + if (!process.env.ALCHEMY_API_KEY_AMOY) { + console.log("set ALCHEMY_API_KEY_AMOY env variable"); + return; + } + networkURL += process.env.ALCHEMY_API_KEY_AMOY; + } + + const provider = new ethers.providers.JsonRpcProvider(networkURL); + const signers = await ethers.getSigners(); + + let EOA; + if (useLedger) { + EOA = new LedgerSigner(provider, derivationPath); + } else { + EOA = signers[0]; + } + // EOA address + const deployer = await EOA.getAddress(); + console.log("EOA is:", deployer); + + // Transaction signing and execution + console.log("5. EOA to deploy WormholeTargetDispenserL2"); + const WormholeTargetDispenserL2 = await ethers.getContractFactory("WormholeTargetDispenserL2"); + console.log("You are signing the following transaction: WormholeTargetDispenserL2.connect(EOA).deploy()"); + const celoTargetDispenserL2 = await WormholeTargetDispenserL2.connect(EOA).deploy(parsedData.olasAddress, + parsedData.serviceStakingFactoryAddress, parsedData.wormholeL2MessageRelayer, + parsedData.celoDepositProcessorL1Address, parsedData.wormholel1ChainId, + parsedData.wormholeL2CoreAddress, parsedData.wormholeL2TokenRelayerAddress); + const result = await celoTargetDispenserL2.deployed(); + + // Transaction details + console.log("Contract deployment: WormholeTargetDispenserL2"); + console.log("Contract address:", celoTargetDispenserL2.address); + console.log("Transaction:", result.deployTransaction.hash); + + // Wait for half a minute for the transaction completion + await new Promise(r => setTimeout(r, 30000)); + + // Writing updated parameters back to the JSON file + parsedData.celoTargetDispenserL2Address = celoTargetDispenserL2.address; + fs.writeFileSync(globalsFile, JSON.stringify(parsedData)); + + // Contract verification + if (parsedData.contractVerification) { + const execSync = require("child_process").execSync; + execSync("npx hardhat verify --constructor-args scripts/deployment/staking/celo/verify_05_celo_target_dispenser.js --network " + providerName + " " + celoTargetDispenserL2.address, { encoding: "utf-8" }); + } +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/scripts/deployment/staking/celo/globals_celo_mainnet.json b/scripts/deployment/staking/celo/globals_celo_mainnet.json new file mode 100644 index 00000000..a6d7d552 --- /dev/null +++ b/scripts/deployment/staking/celo/globals_celo_mainnet.json @@ -0,0 +1 @@ +{"contractVerification":true,"useLedger":true,"derivationPath":"m/44'/60'/2'/0/0","providerName":"celo","networkURL":"https://forno.celo.org","gasPriceInGwei":"2","olasAddress":"0xaCFfAe8e57Ec6E394Eb1b41939A8CF7892DbDc51","serviceStakingFactoryAddress":"0x1c2cD884127b080F940b7546c1e9aaf525b1FA55","bridgeMediatorAddress":"0x397125902ED2cA2d42104F621f448A2cE1bC8Fb7","wormholeL2CoreAddress":"0xa321448d90d4e5b0A732867c18eA198e75CAC48E","wormholeL2TokenRelayerAddress":"0x796Dff6D74F3E27060B71255Fe517BFb23C93eed","wormholeL2MessageRelayer":"0x27428DD2d3DD32A4D7f7C497eAaa23130d894911","l1ChainId":"2","celoDepositProcessorL1Address":"0x223902b6C583f18E8dc84AF4E6a8fa523d088B78","celoTargetDispenserL2Address":"0xb4096d181C08DDF75f1A63918cCa0d1023C4e6C7"} \ No newline at end of file diff --git a/scripts/deployment/staking/wormhole/verify_05_celo_wormhole_target_dispenser.js b/scripts/deployment/staking/celo/verify_05_celo_target_dispenser.js similarity index 100% rename from scripts/deployment/staking/wormhole/verify_05_celo_wormhole_target_dispenser.js rename to scripts/deployment/staking/celo/verify_05_celo_target_dispenser.js diff --git a/scripts/deployment/staking/deploy_05_celo_wormhole_deposit_processor.js b/scripts/deployment/staking/deploy_05_celo_deposit_processor.js similarity index 81% rename from scripts/deployment/staking/deploy_05_celo_wormhole_deposit_processor.js rename to scripts/deployment/staking/deploy_05_celo_deposit_processor.js index 43d8d473..e1aab94e 100644 --- a/scripts/deployment/staking/deploy_05_celo_wormhole_deposit_processor.js +++ b/scripts/deployment/staking/deploy_05_celo_deposit_processor.js @@ -29,15 +29,15 @@ async function main() { console.log("5. EOA to deploy WormholeDepositProcessorL1"); const WormholeDepositProcessorL1 = await ethers.getContractFactory("WormholeDepositProcessorL1"); console.log("You are signing the following transaction: WormholeDepositProcessorL1.connect(EOA).deploy()"); - const wormholeDepositProcessorL1 = await WormholeDepositProcessorL1.connect(EOA).deploy(parsedData.olasAddress, + const celoDepositProcessorL1 = await WormholeDepositProcessorL1.connect(EOA).deploy(parsedData.olasAddress, parsedData.dispenserAddress, parsedData.wormholeL1TokenRelayerAddress, parsedData.wormholeL1MessageRelayerAddress, parsedData.celoL2TargetChainId, parsedData.wormholeL1CoreAddress, parsedData.celoWormholeL2TargetChainId); - const result = await wormholeDepositProcessorL1.deployed(); + const result = await celoDepositProcessorL1.deployed(); // Transaction details console.log("Contract deployment: WormholeDepositProcessorL1"); - console.log("Contract address:", wormholeDepositProcessorL1.address); + console.log("Contract address:", celoDepositProcessorL1.address); console.log("Transaction:", result.deployTransaction.hash); // If on sepolia, wait a minute for the transaction completion @@ -46,13 +46,13 @@ async function main() { } // Writing updated parameters back to the JSON file - parsedData.wormholeDepositProcessorL1Address = wormholeDepositProcessorL1.address; + parsedData.celoDepositProcessorL1Address = celoDepositProcessorL1.address; fs.writeFileSync(globalsFile, JSON.stringify(parsedData)); // Contract verification if (parsedData.contractVerification) { const execSync = require("child_process").execSync; - execSync("npx hardhat verify --constructor-args scripts/deployment/staking/verify_05_wormhole_deposit_processor.js --network " + providerName + " " + wormholeDepositProcessorL1.address, { encoding: "utf-8" }); + execSync("npx hardhat verify --constructor-args scripts/deployment/staking/verify_05_celo_deposit_processor.js --network " + providerName + " " + celoDepositProcessorL1.address, { encoding: "utf-8" }); } } diff --git a/scripts/deployment/staking/deploy_07_base_deposit_processor.js b/scripts/deployment/staking/deploy_07_base_deposit_processor.js new file mode 100644 index 00000000..b2ce30d3 --- /dev/null +++ b/scripts/deployment/staking/deploy_07_base_deposit_processor.js @@ -0,0 +1,64 @@ +/*global process*/ + +const { ethers } = require("hardhat"); +const { LedgerSigner } = require("@anders-t/ethers-ledger"); + +async function main() { + const fs = require("fs"); + const globalsFile = "globals.json"; + const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); + let parsedData = JSON.parse(dataFromJSON); + const useLedger = parsedData.useLedger; + const derivationPath = parsedData.derivationPath; + const providerName = parsedData.providerName; + let EOA; + + const provider = await ethers.providers.getDefaultProvider(providerName); + const signers = await ethers.getSigners(); + + if (useLedger) { + EOA = new LedgerSigner(provider, derivationPath); + } else { + EOA = signers[0]; + } + // EOA address + const deployer = await EOA.getAddress(); + console.log("EOA is:", deployer); + + // Transaction signing and execution + console.log("7. EOA to deploy OptimismDepositProcessorL1 for Base"); + const OptimismDepositProcessorL1 = await ethers.getContractFactory("OptimismDepositProcessorL1"); + console.log("You are signing the following transaction: OptimismDepositProcessorL1.connect(EOA).deploy()"); + const baseDepositProcessorL1 = await OptimismDepositProcessorL1.connect(EOA).deploy(parsedData.olasAddress, + parsedData.dispenserAddress, parsedData.baseL1StandardBridgeProxyAddress, + parsedData.baseL1CrossDomainMessengerProxyAddress, parsedData.baseL2TargetChainId, + parsedData.baseOLASAddress); + const result = await baseDepositProcessorL1.deployed(); + + // Transaction details + console.log("Contract deployment: OptimismDepositProcessorL1"); + console.log("Contract address:", baseDepositProcessorL1.address); + console.log("Transaction:", result.deployTransaction.hash); + + // If on sepolia, wait a minute for the transaction completion + if (providerName === "sepolia") { + await new Promise(r => setTimeout(r, 30000)); + } + + // Writing updated parameters back to the JSON file + parsedData.baseDepositProcessorL1Address = baseDepositProcessorL1.address; + fs.writeFileSync(globalsFile, JSON.stringify(parsedData)); + + // Contract verification + if (parsedData.contractVerification) { + const execSync = require("child_process").execSync; + execSync("npx hardhat verify --constructor-args scripts/deployment/staking/verify_07_base_deposit_processor.js --network " + providerName + " " + baseDepositProcessorL1.address, { encoding: "utf-8" }); + } +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/scripts/deployment/staking/deploy_08_ethereum_deposit_processor.js b/scripts/deployment/staking/deploy_08_ethereum_deposit_processor.js new file mode 100644 index 00000000..7a7b3e8a --- /dev/null +++ b/scripts/deployment/staking/deploy_08_ethereum_deposit_processor.js @@ -0,0 +1,62 @@ +/*global process*/ + +const { ethers } = require("hardhat"); +const { LedgerSigner } = require("@anders-t/ethers-ledger"); + +async function main() { + const fs = require("fs"); + const globalsFile = "globals.json"; + const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); + let parsedData = JSON.parse(dataFromJSON); + const useLedger = parsedData.useLedger; + const derivationPath = parsedData.derivationPath; + const providerName = parsedData.providerName; + let EOA; + + const provider = await ethers.providers.getDefaultProvider(providerName); + const signers = await ethers.getSigners(); + + if (useLedger) { + EOA = new LedgerSigner(provider, derivationPath); + } else { + EOA = signers[0]; + } + // EOA address + const deployer = await EOA.getAddress(); + console.log("EOA is:", deployer); + + // Transaction signing and execution + console.log("8. EOA to deploy EthereumDepositProcessor for Base"); + const EthereumDepositProcessor = await ethers.getContractFactory("EthereumDepositProcessor"); + console.log("You are signing the following transaction: EthereumDepositProcessor.connect(EOA).deploy()"); + const ethereumDepositProcessor = await EthereumDepositProcessor.connect(EOA).deploy(parsedData.olasAddress, + parsedData.dispenserAddress, parsedData.serviceStakingFactoryAddress, parsedData.timelockAddress); + const result = await ethereumDepositProcessor.deployed(); + + // Transaction details + console.log("Contract deployment: EthereumDepositProcessor"); + console.log("Contract address:", ethereumDepositProcessor.address); + console.log("Transaction:", result.deployTransaction.hash); + + // If on sepolia, wait a minute for the transaction completion + if (providerName === "sepolia") { + await new Promise(r => setTimeout(r, 30000)); + } + + // Writing updated parameters back to the JSON file + parsedData.ethereumDepositProcessorAddress = ethereumDepositProcessor.address; + fs.writeFileSync(globalsFile, JSON.stringify(parsedData)); + + // Contract verification + if (parsedData.contractVerification) { + const execSync = require("child_process").execSync; + execSync("npx hardhat verify --constructor-args scripts/deployment/staking/verify_08_ethereum_deposit_processor.js --network " + providerName + " " + ethereumDepositProcessor.address, { encoding: "utf-8" }); + } +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/scripts/deployment/staking/deploy_09_set_targer_dispensers.js b/scripts/deployment/staking/deploy_09_set_targer_dispensers.js new file mode 100644 index 00000000..95871b3e --- /dev/null +++ b/scripts/deployment/staking/deploy_09_set_targer_dispensers.js @@ -0,0 +1,81 @@ +/*global process*/ + +const { ethers } = require("hardhat"); +const { LedgerSigner } = require("@anders-t/ethers-ledger"); + +async function main() { + const fs = require("fs"); + const globalsFile = "globals.json"; + const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); + let parsedData = JSON.parse(dataFromJSON); + const useLedger = parsedData.useLedger; + const derivationPath = parsedData.derivationPath; + const providerName = parsedData.providerName; + const arbitrumDepositProcessorL1Address = parsedData.arbitrumDepositProcessorL1Address; + const arbitrumTargetDispenserL2Address = parsedData.arbitrumTargetDispenserL2Address; + const baseDepositProcessorL1Address = parsedData.baseDepositProcessorL1Address; + const baseTargetDispenserL2Address = parsedData.baseTargetDispenserL2Address; + const celoDepositProcessorL1Address = parsedData.celoDepositProcessorL1Address; + const celoTargetDispenserL2Address = parsedData.celoTargetDispenserL2Address; + const gnosisDepositProcessorL1Address = parsedData.gnosisDepositProcessorL1Address; + const gnosisTargetDispenserL2Address = parsedData.gnosisTargetDispenserL2Address; + const optimismDepositProcessorL1Address = parsedData.optimismDepositProcessorL1Address; + const optimismTargetDispenserL2Address = parsedData.optimismTargetDispenserL2Address; + const polygonDepositProcessorL1Address = parsedData.polygonDepositProcessorL1Address; + const polygonTargetDispenserL2Address = parsedData.polygonTargetDispenserL2Address; + let EOA; + + const provider = await ethers.providers.getDefaultProvider(providerName); + const signers = await ethers.getSigners(); + + if (useLedger) { + EOA = new LedgerSigner(provider, derivationPath); + } else { + EOA = signers[0]; + } + // EOA address + const deployer = await EOA.getAddress(); + console.log("EOA is:", deployer); + + // Get all the contracts + const arbitrumDepositProcessorL1 = await ethers.getContractAt("ArbitrumDepositProcessorL1", arbitrumDepositProcessorL1Address); + const baseDepositProcessorL1 = await ethers.getContractAt("OptimismDepositProcessorL1", baseDepositProcessorL1Address); + const celoDepositProcessorL1 = await ethers.getContractAt("WormholeDepositProcessorL1", celoDepositProcessorL1Address); + const gnosisDepositProcessorL1 = await ethers.getContractAt("GnosisDepositProcessorL1", gnosisDepositProcessorL1Address); + const optimismDepositProcessorL1 = await ethers.getContractAt("OptimismDepositProcessorL1", optimismDepositProcessorL1Address); + const polygonDepositProcessorL1 = await ethers.getContractAt("PolygonDepositProcessorL1", polygonDepositProcessorL1Address); + + // Transaction signing and execution + console.log("9. EOA to set TargetDispenserL2 in DepositProcessorL1-s"); + + console.log("You are signing the following transaction: ArbitrumDepositProcessorL1.connect(EOA).setL2TargetDispenser()"); + let result = await arbitrumDepositProcessorL1.connect(EOA).setL2TargetDispenser(arbitrumTargetDispenserL2Address); + console.log("Transaction:", result.hash); + + console.log("You are signing the following transaction: OptimismDepositProcessorL1.connect(EOA).setL2TargetDispenser()"); + result = await baseDepositProcessorL1.connect(EOA).setL2TargetDispenser(baseTargetDispenserL2Address); + console.log("Transaction:", result.hash); + + console.log("You are signing the following transaction: WormholeDepositProcessorL1.connect(EOA).setL2TargetDispenser()"); + result = await celoDepositProcessorL1.connect(EOA).setL2TargetDispenser(celoTargetDispenserL2Address); + console.log("Transaction:", result.hash); + + console.log("You are signing the following transaction: GnosisDepositProcessorL1.connect(EOA).setL2TargetDispenser()"); + result = await gnosisDepositProcessorL1.connect(EOA).setL2TargetDispenser(gnosisTargetDispenserL2Address); + console.log("Transaction:", result.hash); + + console.log("You are signing the following transaction: OptimismDepositProcessorL1.connect(EOA).setL2TargetDispenser()"); + result = await optimismDepositProcessorL1.connect(EOA).setL2TargetDispenser(optimismTargetDispenserL2Address); + console.log("Transaction:", result.hash); + + console.log("You are signing the following transaction: PolygonDepositProcessorL1.connect(EOA).setL2TargetDispenser()"); + result = await polygonDepositProcessorL1.connect(EOA).setL2TargetDispenser(polygonTargetDispenserL2Address); + console.log("Transaction:", result.hash); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/scripts/deployment/staking/deploy_10_set_deposit_processors.js b/scripts/deployment/staking/deploy_10_set_deposit_processors.js new file mode 100644 index 00000000..ddc68cff --- /dev/null +++ b/scripts/deployment/staking/deploy_10_set_deposit_processors.js @@ -0,0 +1,62 @@ +/*global process*/ + +const { ethers } = require("hardhat"); +const { LedgerSigner } = require("@anders-t/ethers-ledger"); + +async function main() { + const fs = require("fs"); + const globalsFile = "globals.json"; + const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); + let parsedData = JSON.parse(dataFromJSON); + const useLedger = parsedData.useLedger; + const derivationPath = parsedData.derivationPath; + const providerName = parsedData.providerName; + const arbitrumDepositProcessorL1Address = parsedData.arbitrumDepositProcessorL1Address; + const baseDepositProcessorL1Address = parsedData.baseDepositProcessorL1Address; + const celoDepositProcessorL1Address = parsedData.celoDepositProcessorL1Address; + const gnosisDepositProcessorL1Address = parsedData.gnosisDepositProcessorL1Address; + const optimismDepositProcessorL1Address = parsedData.optimismDepositProcessorL1Address; + const polygonDepositProcessorL1Address = parsedData.polygonDepositProcessorL1Address; + const ethereumDepositProcessorAddress = parsedData.ethereumDepositProcessorAddress; + const dispenserAddress = parsedData.dispenserAddress; + let EOA; + + const provider = await ethers.providers.getDefaultProvider(providerName); + const signers = await ethers.getSigners(); + + if (useLedger) { + EOA = new LedgerSigner(provider, derivationPath); + } else { + EOA = signers[0]; + } + // EOA address + const deployer = await EOA.getAddress(); + console.log("EOA is:", deployer); + + // Get all the contracts + const arbitrumDepositProcessorL1 = await ethers.getContractAt("ArbitrumDepositProcessorL1", arbitrumDepositProcessorL1Address); + const baseDepositProcessorL1 = await ethers.getContractAt("OptimismDepositProcessorL1", baseDepositProcessorL1Address); + const celoDepositProcessorL1 = await ethers.getContractAt("WormholeDepositProcessorL1", celoDepositProcessorL1Address); + const gnosisDepositProcessorL1 = await ethers.getContractAt("GnosisDepositProcessorL1", gnosisDepositProcessorL1Address); + const optimismDepositProcessorL1 = await ethers.getContractAt("OptimismDepositProcessorL1", optimismDepositProcessorL1Address); + const polygonDepositProcessorL1 = await ethers.getContractAt("PolygonDepositProcessorL1", polygonDepositProcessorL1Address); + const dispenser = await ethers.getContractAt("Dispenser", dispenserAddress); + + // Transaction signing and execution + console.log("10. EOA to set deposit processors in Dispenser"); + console.log("You are signing the following transaction: Dispenser.connect(EOA).setDepositProcessorChainIds()"); + const ethereumChainId = (await provider.getNetwork()).chainId; + const result = await dispenser.connect(EOA).setDepositProcessorChainIds([arbitrumDepositProcessorL1Address, + baseDepositProcessorL1Address, celoDepositProcessorL1Address, ethereumDepositProcessorAddress, + gnosisDepositProcessorL1Address, optimismDepositProcessorL1Address, polygonDepositProcessorL1Address], + [parsedData.arbitrumL2TargetChainId, parsedData.baseL2TargetChainId, parsedData.celoL2TargetChainId, ethereumChainId, + parsedData.gnosisL2TargetChainId, parsedData.optimisticL2TargetChainId, parsedData.polygonL2TargetChainId]); + console.log("Transaction:", result.hash); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/scripts/deployment/staking/globals_mainnet.json b/scripts/deployment/staking/globals_mainnet.json new file mode 100644 index 00000000..f39c24d8 --- /dev/null +++ b/scripts/deployment/staking/globals_mainnet.json @@ -0,0 +1 @@ +{"contractVerification":true,"useLedger":true,"derivationPath":"m/44'/60'/2'/0/0","providerName":"mainnet","olasAddress":"0x0001A500A6B18995B03f44bb040A5fFc28E45CB0","timelockAddress":"0x3C1fF68f5aa342D296d4DEe4Bb1cACCA912D95fE","dispenserAddress":"0x5650300fCBab43A0D7D02F8Cb5d0f039402593f0","arbitrumL1ERC20GatewayRouterAddress":"0x72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef","arbitrumL1ERC20GatewayAddress":"0xa3A7B6F88361F48403514059F1F16C8E78d60EeC","arbitrumInboxAddress":"0x4Dbd4fc535Ac27206064B68FfCf827b0A60BAB3f","arbitrumOutboxAddress":"0x0B9857ae2D4A3DBe74ffE1d7DF045bb7F96E4840","arbitrumBridgeAddress":"0x8315177aB297bA92A06054cE80a67Ed4DBd7ed3a","arbitrumL2TargetChainId":"42161","arbitrumDepositProcessorL1Address":"0x5e13E07006D68B097DCb5979ef5545C4f9156162","gnosisOmniBridgeAddress":"0x88ad09518695c6c3712AC10a214bE5109a655671","gnosisAMBForeignAddress":"0x4C36d2919e407f0Cc2Ee3c993ccF8ac26d9CE64e","gnosisL2TargetChainId":"100","gnosisDepositProcessorL1Address":"0xEEf2c02cFC445bFFf1c891D486424Ef3aBc66AB0","optimisticL1StandardBridgeProxyAddress":"0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1","optimisticL1CrossDomainMessengerProxyAddress":"0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1","optimisticOLASAddress":"0xFC2E6e6BCbd49ccf3A5f029c79984372DcBFE527","optimisticL2TargetChainId":"10","optimismDepositProcessorL1Address":"0xAB787ceebe8F2b8dca44e3bB744D6e63003ee978","wormholeL1CoreAddress":"0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B","wormholeL1TokenRelayerAddress":"0x3ee18B2214AFF97000D974cf647E7C347E8fa585","wormholeL1MessageRelayerAddress":"0x27428DD2d3DD32A4D7f7C497eAaa23130d894911","celoL2TargetChainId":"42220","celoWormholeL2TargetChainId":"14","celoDepositProcessorL1Address":"0x223902b6C583f18E8dc84AF4E6a8fa523d088B78","polygonRootChainManagerProxyAddress":"0xA0c68C638235ee32657e8f720a23ceC1bFc77C77","polygonFXRootAddress":"0xfe5e5D361b2ad62c541bAb87C45a0B9B018389a2","polygonCheckpointManagerAddress":"0x86E4Dc95c7FBdBf52e33D563BbDB00823894C287","polygonERC20PredicateAddress":"0x40ec5B33f54e0E8A33A975908C5BA1c14e5BbbDf","polygonL2TargetChainId":"137","polygonDepositProcessorL1Address":"0x4Ce43b82EF1298E1466D3b3Cee67BA6680bF82FB","baseL1StandardBridgeProxyAddress":"0x3154Cf16ccdb4C6d922629664174b904d80F2C35","baseL1CrossDomainMessengerProxyAddress":"0x866E82a600A1414e583f7F13623F1aC5d58b0Afa","baseOLASAddress":"0x54330d28ca3357F294334BDC454a032e7f353416","baseL2TargetChainId":"8453","baseDepositProcessorL1Address":"0x42BA1BbD797E4C90F386F03a544F3b62C1f917d0","serviceStakingFactoryAddress":"0xEBdde456EA288b49f7D5975E7659bA1Ccf607efc","ethereumDepositProcessorAddress":"0x15CD7fAeE048c7673aB818C9e582630F1a924593","arbitrumTargetDispenserL2Address":"0x10c5525F77F13b28f42c5626240c001c2D57CAd4","baseTargetDispenserL2Address":"0xcDdD9D9ABaB36fFa882530D69c73FeE5D4001C2d","celoTargetDispenserL2Address":"0xb4096d181C08DDF75f1A63918cCa0d1023C4e6C7","gnosisTargetDispenserL2Address":"0x67722c823010CEb4BED5325fE109196C0f67D053","optimismTargetDispenserL2Address":"0x04b0007b2aFb398015B76e5f22993a1fddF83644","polygonTargetDispenserL2Address":"0xf76953444C35F1FcE2F6CA1b167173357d3F5C17"} \ No newline at end of file diff --git a/scripts/deployment/staking/globals_sepolia.json b/scripts/deployment/staking/globals_sepolia.json index 7b1f6dda..78d3a9ee 100644 --- a/scripts/deployment/staking/globals_sepolia.json +++ b/scripts/deployment/staking/globals_sepolia.json @@ -1 +1 @@ -{"contractVerification":true,"useLedger":false,"derivationPath":"m/44'/60'/2'/0/0","providerName":"sepolia","olasAddress":"0xeb2725bD76f6b1569Cf1484fCa0f2D55714A085d","dispenserAddress":"0x42f43be9E5E50df51b86C5c6427223ff565f40C6","arbitrumL1ERC20GatewayRouterAddress":"0xcE18836b233C83325Cc8848CA4487e94C6288264","arbitrumL1ERC20GatewayAddress":"0x902b3E5f8F19571859F4AB1003B960a5dF693aFF","arbitrumInboxAddress":"0xaAe29B0366299461418F5324a79Afc425BE5ae21","arbitrumOutboxAddress":"0x65f07C7D521164a4d5DaC6eB8Fac8DA067A3B78F","arbitrumBridgeAddress":"0x38f918D0E9F1b721EDaA41302E399fa1B79333a9","arbitrumL2TargetChainId":"421614","arbitrumDepositProcessorL1Address":"0xACd410f51DA5aAe1fF925565FBCB6B6eedbB00E2","gnosisOmniBridgeAddress":"0x63E47C5e3303DDDCaF3b404B1CCf9Eb633652e9e","gnosisAMBForeignAddress":"0xf2546D6648BD2af6a008A7e7C1542BB240329E11","gnosisL2TargetChainId":"10200","gnosisDepositProcessorL1Address":"0x679Ce81a7bab6808534137585850dc81F90Ea8a4","optimisticL1StandardBridgeProxyAddress":"0xFBb0621E0B23b5478B630BD55a5f21f67730B0F1","optimisticL1CrossDomainMessengerProxyAddress":"0x58Cc85b8D04EA49cC6DBd3CbFFd00B4B8D6cb3ef","optimisticOLASAddress":"0x01B8b6384298D4848E3BE63D4C9D17830EeE488A","optimisticL2TargetChainId":"11155420","optimismDepositProcessorL1Address":"0xDc6B77e32e751C7d6e1d1c39A64c64a8F0049E21","wormholeL1CoreAddress":"0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78","wormholeL1TokenRelayerAddress":"0xDB5492265f6038831E89f495670FF909aDe94bd9","wormholeL1MessageRelayerAddress":"0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470","celoL2TargetChainId":"44787","celoWormholeL2TargetChainId":"14","celoWormholeDepositProcessorL1Address":"","polygonRootChainManagerProxyAddress":"0x34F5A25B627f50Bb3f5cAb72807c4D4F405a9232","polygonFXRootAddress":"0x0E13EBEdDb8cf9f5987512d5E081FdC2F5b0991e","polygonCheckpointManagerAddress":"0xbd07D7E1E93c8d4b2a261327F3C28a8EA7167209","polygonERC20PredicateAddress":"0x4258c75b752c812b7fa586bdeb259f2d4bd17f4f","polygonL2TargetChainId":"80002","polygonDepositProcessorL1Address":"0x36c1beAFBeaf65DFcF16De60867BF9525455bf4E"} \ No newline at end of file +{"contractVerification":true,"useLedger":false,"derivationPath":"m/44'/60'/2'/0/0","providerName":"sepolia","olasAddress":"0xeb2725bD76f6b1569Cf1484fCa0f2D55714A085d","timelockAddress":"0x3C1fF68f5aa342D296d4DEe4Bb1cACCA912D95fE","dispenserAddress":"0x42f43be9E5E50df51b86C5c6427223ff565f40C6","arbitrumL1ERC20GatewayRouterAddress":"0xcE18836b233C83325Cc8848CA4487e94C6288264","arbitrumL1ERC20GatewayAddress":"0x902b3E5f8F19571859F4AB1003B960a5dF693aFF","arbitrumInboxAddress":"0xaAe29B0366299461418F5324a79Afc425BE5ae21","arbitrumOutboxAddress":"0x65f07C7D521164a4d5DaC6eB8Fac8DA067A3B78F","arbitrumBridgeAddress":"0x38f918D0E9F1b721EDaA41302E399fa1B79333a9","arbitrumL2TargetChainId":"421614","arbitrumDepositProcessorL1Address":"0xACd410f51DA5aAe1fF925565FBCB6B6eedbB00E2","gnosisOmniBridgeAddress":"0x63E47C5e3303DDDCaF3b404B1CCf9Eb633652e9e","gnosisAMBForeignAddress":"0xf2546D6648BD2af6a008A7e7C1542BB240329E11","gnosisL2TargetChainId":"10200","gnosisDepositProcessorL1Address":"0x679Ce81a7bab6808534137585850dc81F90Ea8a4","optimisticL1StandardBridgeProxyAddress":"0xFBb0621E0B23b5478B630BD55a5f21f67730B0F1","optimisticL1CrossDomainMessengerProxyAddress":"0x58Cc85b8D04EA49cC6DBd3CbFFd00B4B8D6cb3ef","optimisticOLASAddress":"0x01B8b6384298D4848E3BE63D4C9D17830EeE488A","optimisticL2TargetChainId":"11155420","optimismDepositProcessorL1Address":"0xDc6B77e32e751C7d6e1d1c39A64c64a8F0049E21","wormholeL1CoreAddress":"0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78","wormholeL1TokenRelayerAddress":"0xDB5492265f6038831E89f495670FF909aDe94bd9","wormholeL1MessageRelayerAddress":"0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470","celoL2TargetChainId":"44787","celoWormholeL2TargetChainId":"14","celoWormholeDepositProcessorL1Address":"","polygonRootChainManagerProxyAddress":"0x34F5A25B627f50Bb3f5cAb72807c4D4F405a9232","polygonFXRootAddress":"0x0E13EBEdDb8cf9f5987512d5E081FdC2F5b0991e","polygonCheckpointManagerAddress":"0xbd07D7E1E93c8d4b2a261327F3C28a8EA7167209","polygonERC20PredicateAddress":"0x4258c75b752c812b7fa586bdeb259f2d4bd17f4f","polygonL2TargetChainId":"80002","polygonDepositProcessorL1Address":"0x36c1beAFBeaf65DFcF16De60867BF9525455bf4E","serviceStakingFactoryAddress":"0x01187451346d46D6fd2e6647a2980E0d6C06d4Da"} \ No newline at end of file diff --git a/scripts/deployment/staking/gnosis/deploy_031_change_owner.js b/scripts/deployment/staking/gnosis/deploy_031_change_owner.js new file mode 100644 index 00000000..5170247f --- /dev/null +++ b/scripts/deployment/staking/gnosis/deploy_031_change_owner.js @@ -0,0 +1,48 @@ +/*global process*/ + +const { ethers } = require("hardhat"); +const { LedgerSigner } = require("@anders-t/ethers-ledger"); + +async function main() { + const fs = require("fs"); + const globalsFile = "globals.json"; + const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); + let parsedData = JSON.parse(dataFromJSON); + const useLedger = parsedData.useLedger; + const derivationPath = parsedData.derivationPath; + const providerName = parsedData.providerName; + const gnosisTargetDispenserL2Address = parsedData.gnosisTargetDispenserL2Address; + const bridgeMediatorAddress = parsedData.bridgeMediatorAddress; + + let networkURL = parsedData.networkURL; + const provider = new ethers.providers.JsonRpcProvider(networkURL); + const signers = await ethers.getSigners(); + + let EOA; + if (useLedger) { + EOA = new LedgerSigner(provider, derivationPath); + } else { + EOA = signers[0]; + } + // EOA address + const deployer = await EOA.getAddress(); + console.log("EOA is:", deployer); + + // Transaction signing and execution + console.log("31. EOA to change owner in GnosisTargetDispenserL2"); + const gnosisTargetDispenserL2 = await ethers.getContractAt("GnosisTargetDispenserL2", gnosisTargetDispenserL2Address); + console.log("You are signing the following transaction: GnosisTargetDispenserL2.connect(EOA).changeOwner()"); + const result = await gnosisTargetDispenserL2.connect(EOA).changeOwner(bridgeMediatorAddress); + + // Transaction details + console.log("Contract deployment: GnosisTargetDispenserL2"); + console.log("Contract address:", gnosisTargetDispenserL2.address); + console.log("Transaction:", result.hash); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/scripts/deployment/staking/gnosis/globals_gnosis_mainnet.json b/scripts/deployment/staking/gnosis/globals_gnosis_mainnet.json new file mode 100644 index 00000000..8697e959 --- /dev/null +++ b/scripts/deployment/staking/gnosis/globals_gnosis_mainnet.json @@ -0,0 +1 @@ +{"contractVerification":true,"useLedger":true,"derivationPath":"m/44'/60'/2'/0/0","providerName":"gnosis","networkURL":"https://rpc.gnosischain.com","gasPriceInGwei":"5","olasAddress":"0xcE11e14225575945b8E6Dc0D4F2dD4C570f79d9f","serviceStakingFactoryAddress":"0xb0228CA253A88Bc8eb4ca70BCAC8f87b381f4700","bridgeMediatorAddress":"0x15bd56669F57192a97dF41A2aa8f4403e9491776","gnosisAMBHomeAddress":"0x75Df5AF045d91108662D8080fD1FEFAd6aA0bb59","l1ChainId":"1","gnosisDepositProcessorL1Address":"0xEEf2c02cFC445bFFf1c891D486424Ef3aBc66AB0","gnosisTargetDispenserL2Address":"0x67722c823010CEb4BED5325fE109196C0f67D053"} \ No newline at end of file diff --git a/scripts/deployment/staking/optimistic/deploy_41_change_owner.js b/scripts/deployment/staking/optimistic/deploy_41_change_owner.js new file mode 100644 index 00000000..5213fc69 --- /dev/null +++ b/scripts/deployment/staking/optimistic/deploy_41_change_owner.js @@ -0,0 +1,48 @@ +/*global process*/ + +const { ethers } = require("hardhat"); +const { LedgerSigner } = require("@anders-t/ethers-ledger"); + +async function main() { + const fs = require("fs"); + const globalsFile = "globals.json"; + const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); + let parsedData = JSON.parse(dataFromJSON); + const useLedger = parsedData.useLedger; + const derivationPath = parsedData.derivationPath; + const providerName = parsedData.providerName; + const optimismTargetDispenserL2Address = parsedData.optimismTargetDispenserL2Address; + const bridgeMediatorAddress = parsedData.bridgeMediatorAddress; + + let networkURL = parsedData.networkURL; + const provider = new ethers.providers.JsonRpcProvider(networkURL); + const signers = await ethers.getSigners(); + + let EOA; + if (useLedger) { + EOA = new LedgerSigner(provider, derivationPath); + } else { + EOA = signers[0]; + } + // EOA address + const deployer = await EOA.getAddress(); + console.log("EOA is:", deployer); + + // Transaction signing and execution + console.log("41. EOA to change owner in OptimismTargetDispenserL2"); + const optimismTargetDispenserL2 = await ethers.getContractAt("OptimismTargetDispenserL2", optimismTargetDispenserL2Address); + console.log("You are signing the following transaction: OptimismTargetDispenserL2.connect(EOA).changeOwner()"); + const result = await optimismTargetDispenserL2.connect(EOA).changeOwner(bridgeMediatorAddress); + + // Transaction details + console.log("Contract deployment: OptimismTargetDispenserL2"); + console.log("Contract address:", optimismTargetDispenserL2.address); + console.log("Transaction:", result.hash); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/scripts/deployment/staking/optimistic/globals_optimistic_mainnet.json b/scripts/deployment/staking/optimistic/globals_optimistic_mainnet.json new file mode 100644 index 00000000..d8a04c79 --- /dev/null +++ b/scripts/deployment/staking/optimistic/globals_optimistic_mainnet.json @@ -0,0 +1 @@ +{"contractVerification":true,"useLedger":true,"derivationPath":"m/44'/60'/2'/0/0","providerName":"optimistic","networkURL":"https://optimism.drpc.org","gasPriceInGwei":"2","olasAddress":"0xFC2E6e6BCbd49ccf3A5f029c79984372DcBFE527","serviceStakingFactoryAddress":"0xa45E64d13A30a51b91ae0eb182e88a40e9b18eD8","bridgeMediatorAddress":"0x87c511c8aE3fAF0063b3F3CF9C6ab96c4AA5C60c","optimisticL2CrossDomainMessengerAddress":"0x4200000000000000000000000000000000000007","l1ChainId":"1","optimismDepositProcessorL1Address":"0xAB787ceebe8F2b8dca44e3bB744D6e63003ee978","optimismTargetDispenserL2Address":"0x04b0007b2aFb398015B76e5f22993a1fddF83644"} \ No newline at end of file diff --git a/scripts/deployment/staking/optimistic/send_tokens_and_message.js b/scripts/deployment/staking/optimistic/send_tokens_and_message.js index cc8c1dc9..23433dd7 100644 --- a/scripts/deployment/staking/optimistic/send_tokens_and_message.js +++ b/scripts/deployment/staking/optimistic/send_tokens_and_message.js @@ -55,7 +55,7 @@ const main = async () => { await tx.wait(); // tx back: https://sepolia-optimism.etherscan.io/tx/0x08ff60b3ef506e0f34e5941953608fa5bec1a13d7e0a175084245aa622edf7e0 - // tx result: + // tx result: https://sepolia.etherscan.io/tx/0xcd6ad253a6f869899f25f5d69d8261dbabd1fe49d9fce69cbcd3672064bb49dc // https://docs.optimism.io/builders/app-developers/tutorials/cross-dom-solidity#interact-with-the-l2-greeter // https://github.com/t4sk/notes/tree/main/op diff --git a/scripts/deployment/staking/polygon/deploy_06_polygon_targer_dispenser.js b/scripts/deployment/staking/polygon/deploy_06_polygon_targer_dispenser.js index 10b7f502..45cbeab6 100644 --- a/scripts/deployment/staking/polygon/deploy_06_polygon_targer_dispenser.js +++ b/scripts/deployment/staking/polygon/deploy_06_polygon_targer_dispenser.js @@ -48,7 +48,7 @@ async function main() { const polygonTargetDispenserL2 = await PolygonTargetDispenserL2.connect(EOA).deploy(parsedData.olasAddress, parsedData.serviceStakingFactoryAddress, parsedData.polygonFXChildAddress, parsedData.polygonDepositProcessorL1Address, parsedData.l1ChainId, { gasPrice }); - const result = await polygonTargetDispenserL2.deployed(); + let result = await polygonTargetDispenserL2.deployed(); // Transaction details console.log("Contract deployment: PolygonTargetDispenserL2"); @@ -62,6 +62,10 @@ async function main() { parsedData.polygonTargetDispenserL2Address = polygonTargetDispenserL2.address; fs.writeFileSync(globalsFile, JSON.stringify(parsedData)); + console.log("You are signing the following transaction: PolygonTargetDispenserL2.connect(EOA).setFxRootTunnel()"); + result = await polygonTargetDispenserL2.setFxRootTunnel(parsedData.polygonDepositProcessorL1Address); + console.log("Transaction:", result.hash); + // Contract verification if (parsedData.contractVerification) { const execSync = require("child_process").execSync; diff --git a/scripts/deployment/staking/polygon/deploy_61_change_owner.js b/scripts/deployment/staking/polygon/deploy_61_change_owner.js new file mode 100644 index 00000000..7a15c82b --- /dev/null +++ b/scripts/deployment/staking/polygon/deploy_61_change_owner.js @@ -0,0 +1,48 @@ +/*global process*/ + +const { ethers } = require("hardhat"); +const { LedgerSigner } = require("@anders-t/ethers-ledger"); + +async function main() { + const fs = require("fs"); + const globalsFile = "globals.json"; + const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); + let parsedData = JSON.parse(dataFromJSON); + const useLedger = parsedData.useLedger; + const derivationPath = parsedData.derivationPath; + const providerName = parsedData.providerName; + const polygonTargetDispenserL2Address = parsedData.polygonTargetDispenserL2Address; + const bridgeMediatorAddress = parsedData.bridgeMediatorAddress; + + let networkURL = parsedData.networkURL; + const provider = new ethers.providers.JsonRpcProvider(networkURL); + const signers = await ethers.getSigners(); + + let EOA; + if (useLedger) { + EOA = new LedgerSigner(provider, derivationPath); + } else { + EOA = signers[0]; + } + // EOA address + const deployer = await EOA.getAddress(); + console.log("EOA is:", deployer); + + // Transaction signing and execution + console.log("61. EOA to change owner in PolygonTargetDispenserL2"); + const polygonTargetDispenserL2 = await ethers.getContractAt("PolygonTargetDispenserL2", polygonTargetDispenserL2Address); + console.log("You are signing the following transaction: PolygonTargetDispenserL2.connect(EOA).changeOwner()"); + const result = await polygonTargetDispenserL2.connect(EOA).changeOwner(bridgeMediatorAddress); + + // Transaction details + console.log("Contract deployment: PolygonTargetDispenserL2"); + console.log("Contract address:", polygonTargetDispenserL2.address); + console.log("Transaction:", result.hash); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/scripts/deployment/staking/polygon/globals_polygon_mainnet.json b/scripts/deployment/staking/polygon/globals_polygon_mainnet.json new file mode 100644 index 00000000..41760b04 --- /dev/null +++ b/scripts/deployment/staking/polygon/globals_polygon_mainnet.json @@ -0,0 +1 @@ +{"contractVerification":true,"useLedger":true,"derivationPath":"m/44'/60'/2'/0/0","providerName":"polygon","networkURL":"https://polygon-mainnet.g.alchemy.com/v2/","gasPriceInGwei":"5","olasAddress":"0xFEF5d947472e72Efbb2E388c730B7428406F2F95","serviceStakingFactoryAddress":"0x46C0D07F55d4F9B5Eed2Fc9680B5953e5fd7b461","bridgeMediatorAddress":"0x9338b5153AE39BB89f50468E608eD9d764B755fD","polygonFXChildAddress":"0x8397259c983751DAf40400790063935a11afa28a","l1ChainId":"1","polygonDepositProcessorL1Address":"0x4Ce43b82EF1298E1466D3b3Cee67BA6680bF82FB","polygonTargetDispenserL2Address":"0xf76953444C35F1FcE2F6CA1b167173357d3F5C17"} \ No newline at end of file diff --git a/scripts/deployment/staking/verify_05_wormhole_deposit_processor.js b/scripts/deployment/staking/verify_05_celo_deposit_processor.js similarity index 100% rename from scripts/deployment/staking/verify_05_wormhole_deposit_processor.js rename to scripts/deployment/staking/verify_05_celo_deposit_processor.js diff --git a/scripts/deployment/staking/verify_07_base_deposit_processor.js b/scripts/deployment/staking/verify_07_base_deposit_processor.js new file mode 100644 index 00000000..c7855344 --- /dev/null +++ b/scripts/deployment/staking/verify_07_base_deposit_processor.js @@ -0,0 +1,13 @@ +const fs = require("fs"); +const globalsFile = "globals.json"; +const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); +const parsedData = JSON.parse(dataFromJSON); + +module.exports = [ + parsedData.olasAddress, + parsedData.dispenserAddress, + parsedData.baseL1StandardBridgeProxyAddress, + parsedData.baseL1CrossDomainMessengerProxyAddress, + parsedData.baseL2TargetChainId, + parsedData.baseOLASAddress +]; \ No newline at end of file diff --git a/scripts/deployment/staking/verify_08_ethereum_deposit_processor.js b/scripts/deployment/staking/verify_08_ethereum_deposit_processor.js new file mode 100644 index 00000000..d1a3c206 --- /dev/null +++ b/scripts/deployment/staking/verify_08_ethereum_deposit_processor.js @@ -0,0 +1,11 @@ +const fs = require("fs"); +const globalsFile = "globals.json"; +const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); +const parsedData = JSON.parse(dataFromJSON); + +module.exports = [ + parsedData.olasAddress, + parsedData.dispenserAddress, + parsedData.serviceStakingFactoryAddress, + parsedData.timelockAddress +]; \ No newline at end of file diff --git a/scripts/deployment/staking/wormhole/bridge_new_token.js b/scripts/deployment/staking/wormhole/test/bridge_new_token.js similarity index 100% rename from scripts/deployment/staking/wormhole/bridge_new_token.js rename to scripts/deployment/staking/wormhole/test/bridge_new_token.js diff --git a/scripts/deployment/staking/wormhole/deploy_00_mock_olas_as_erc20_ownerless.js b/scripts/deployment/staking/wormhole/test/deploy_00_mock_olas_as_erc20_ownerless.js similarity index 100% rename from scripts/deployment/staking/wormhole/deploy_00_mock_olas_as_erc20_ownerless.js rename to scripts/deployment/staking/wormhole/test/deploy_00_mock_olas_as_erc20_ownerless.js diff --git a/scripts/deployment/staking/wormhole/deploy_01_mock_dispenser.js b/scripts/deployment/staking/wormhole/test/deploy_01_mock_dispenser.js similarity index 94% rename from scripts/deployment/staking/wormhole/deploy_01_mock_dispenser.js rename to scripts/deployment/staking/wormhole/test/deploy_01_mock_dispenser.js index a035270c..a7b7d733 100644 --- a/scripts/deployment/staking/wormhole/deploy_01_mock_dispenser.js +++ b/scripts/deployment/staking/wormhole/test/deploy_01_mock_dispenser.js @@ -63,7 +63,7 @@ async function main() { // Contract verification if (parsedData.contractVerification) { const execSync = require("child_process").execSync; - execSync("npx hardhat verify --constructor-args scripts/deployment/staking/wormhole/verify_01_mock_dispenser.js --network " + providerName + " " + dispenser.address, { encoding: "utf-8" }); + execSync("npx hardhat verify --constructor-args scripts/deployment/staking/wormhole/test/verify_01_mock_dispenser.js --network " + providerName + " " + dispenser.address, { encoding: "utf-8" }); } } diff --git a/scripts/deployment/staking/wormhole/deploy_05_celo_wormhole_targer_dispenser.js b/scripts/deployment/staking/wormhole/test/deploy_05_celo_wormhole_targer_dispenser.js similarity index 94% rename from scripts/deployment/staking/wormhole/deploy_05_celo_wormhole_targer_dispenser.js rename to scripts/deployment/staking/wormhole/test/deploy_05_celo_wormhole_targer_dispenser.js index 3bb9c756..342a2bbd 100644 --- a/scripts/deployment/staking/wormhole/deploy_05_celo_wormhole_targer_dispenser.js +++ b/scripts/deployment/staking/wormhole/test/deploy_05_celo_wormhole_targer_dispenser.js @@ -64,7 +64,7 @@ async function main() { // Contract verification if (parsedData.contractVerification) { const execSync = require("child_process").execSync; - execSync("npx hardhat verify --constructor-args scripts/deployment/staking/wormhole/verify_05_celo_wormhole_target_dispenser.js --network " + providerName + " " + wormholeTargetDispenserL2.address, { encoding: "utf-8" }); + execSync("npx hardhat verify --constructor-args scripts/deployment/staking/wormhole/test/verify_05_celo_wormhole_target_dispenser.js --network " + providerName + " " + wormholeTargetDispenserL2.address, { encoding: "utf-8" }); } } diff --git a/scripts/deployment/staking/wormhole/deploy_05_polygon_wormhole_deposit_processor.js b/scripts/deployment/staking/wormhole/test/deploy_05_polygon_wormhole_deposit_processor.js similarity index 94% rename from scripts/deployment/staking/wormhole/deploy_05_polygon_wormhole_deposit_processor.js rename to scripts/deployment/staking/wormhole/test/deploy_05_polygon_wormhole_deposit_processor.js index 3b2cc674..b3f41be9 100644 --- a/scripts/deployment/staking/wormhole/deploy_05_polygon_wormhole_deposit_processor.js +++ b/scripts/deployment/staking/wormhole/test/deploy_05_polygon_wormhole_deposit_processor.js @@ -64,7 +64,7 @@ async function main() { // Contract verification if (parsedData.contractVerification) { const execSync = require("child_process").execSync; - execSync("npx hardhat verify --constructor-args scripts/deployment/staking/wormhole/verify_05_polygon_wormhole_deposit_processor.js --network " + providerName + " " + wormholeDepositProcessorL1.address, { encoding: "utf-8" }); + execSync("npx hardhat verify --constructor-args scripts/deployment/staking/wormhole/test/verify_05_polygon_wormhole_deposit_processor.js --network " + providerName + " " + wormholeDepositProcessorL1.address, { encoding: "utf-8" }); } } diff --git a/scripts/deployment/staking/wormhole/globals_celo_mainnet.json b/scripts/deployment/staking/wormhole/test/globals_celo_mainnet.json similarity index 100% rename from scripts/deployment/staking/wormhole/globals_celo_mainnet.json rename to scripts/deployment/staking/wormhole/test/globals_celo_mainnet.json diff --git a/scripts/deployment/staking/wormhole/globals_polygon_mainnet.json b/scripts/deployment/staking/wormhole/test/globals_polygon_mainnet.json similarity index 100% rename from scripts/deployment/staking/wormhole/globals_polygon_mainnet.json rename to scripts/deployment/staking/wormhole/test/globals_polygon_mainnet.json diff --git a/scripts/deployment/staking/wormhole/send_tokens_and_message.js b/scripts/deployment/staking/wormhole/test/send_tokens_and_message.js similarity index 100% rename from scripts/deployment/staking/wormhole/send_tokens_and_message.js rename to scripts/deployment/staking/wormhole/test/send_tokens_and_message.js diff --git a/scripts/deployment/staking/wormhole/verify_01_mock_dispenser.js b/scripts/deployment/staking/wormhole/test/verify_01_mock_dispenser.js similarity index 100% rename from scripts/deployment/staking/wormhole/verify_01_mock_dispenser.js rename to scripts/deployment/staking/wormhole/test/verify_01_mock_dispenser.js diff --git a/scripts/deployment/staking/wormhole/test/verify_05_celo_wormhole_target_dispenser.js b/scripts/deployment/staking/wormhole/test/verify_05_celo_wormhole_target_dispenser.js new file mode 100644 index 00000000..3028f790 --- /dev/null +++ b/scripts/deployment/staking/wormhole/test/verify_05_celo_wormhole_target_dispenser.js @@ -0,0 +1,14 @@ +const fs = require("fs"); +const globalsFile = "globals.json"; +const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); +const parsedData = JSON.parse(dataFromJSON); + +module.exports = [ + parsedData.olasAddress, + parsedData.serviceStakingFactoryAddress, + parsedData.wormholeL2MessageRelayer, + parsedData.celoWormholeDepositProcessorL1Address, + parsedData.wormholel1ChainId, + parsedData.wormholeL2CoreAddress, + parsedData.wormholeL2TokenRelayerAddress +]; \ No newline at end of file diff --git a/scripts/deployment/staking/wormhole/verify_05_polygon_wormhole_deposit_processor.js b/scripts/deployment/staking/wormhole/test/verify_05_polygon_wormhole_deposit_processor.js similarity index 100% rename from scripts/deployment/staking/wormhole/verify_05_polygon_wormhole_deposit_processor.js rename to scripts/deployment/staking/wormhole/test/verify_05_polygon_wormhole_deposit_processor.js diff --git a/scripts/deployment/verify_07_dispenser.js b/scripts/deployment/verify_07_dispenser.js index f8cc6de3..b5cdd7e7 100644 --- a/scripts/deployment/verify_07_dispenser.js +++ b/scripts/deployment/verify_07_dispenser.js @@ -4,8 +4,22 @@ const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); const parsedData = JSON.parse(dataFromJSON); const tokenomicsProxyAddress = parsedData.tokenomicsProxyAddress; const treasuryAddress = parsedData.treasuryAddress; +const olasAddress = parsedData.olasAddress; +const voteWeightingAddress = parsedData.voteWeightingAddress; +const retainerAddress = parsedData.retainerAddress; +const maxNumClaimingEpochs = parsedData.maxNumClaimingEpochs; +const maxNumStakingTargets = parsedData.maxNumStakingTargets; +const minStakingWeight = parsedData.minStakingWeight; +const maxStakingIncentive = parsedData.maxStakingIncentive; module.exports = [ + olasAddress, tokenomicsProxyAddress, - treasuryAddress + treasuryAddress, + voteWeightingAddress, + retainerAddress, + maxNumClaimingEpochs, + maxNumStakingTargets, + minStakingWeight, + maxStakingIncentive ]; \ No newline at end of file diff --git a/scripts/proposals/proposal_09_change_dispenser_and_disable_previous_one.js b/scripts/proposals/proposal_09_change_dispenser_and_disable_previous_one.js new file mode 100644 index 00000000..f3a93114 --- /dev/null +++ b/scripts/proposals/proposal_09_change_dispenser_and_disable_previous_one.js @@ -0,0 +1,69 @@ +/*global process*/ + +const { ethers } = require("hardhat"); + +async function main() { + const fs = require("fs"); + const globalsFile = "globals.json"; + const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); + let parsedData = JSON.parse(dataFromJSON); + const providerName = parsedData.providerName; + + const provider = await ethers.providers.getDefaultProvider(providerName); + + // Get all the necessary contract addresses + const tokenomicsProxyAddress = parsedData.tokenomicsProxyAddress; + const treasuryAddress = parsedData.treasuryAddress; + const dispenserAddress = parsedData.dispenserAddress; + const arbitrumDepositProcessorL1Address = parsedData.arbitrumDepositProcessorL1Address; + const baseDepositProcessorL1Address = parsedData.baseDepositProcessorL1Address; + const celoDepositProcessorL1Address = parsedData.celoDepositProcessorL1Address; + const ethereumDepositProcessorAddress = parsedData.ethereumDepositProcessorAddress; + const gnosisDepositProcessorL1Address = parsedData.gnosisDepositProcessorL1Address; + const optimismDepositProcessorL1Address = parsedData.optimismDepositProcessorL1Address; + const polygonDepositProcessorL1Address = parsedData.polygonDepositProcessorL1Address; + const minStakingWeight = parsedData.minStakingWeight; + const maxStakingIncentive = parsedData.maxStakingIncentive; + + // Get contract instances + const tokenomics = await ethers.getContractAt("Tokenomics", tokenomicsProxyAddress); + const treasury = await ethers.getContractAt("Treasury", treasuryAddress); + + const oldDispenserAddress = "0xeED0000fE94d7cfeF4Dc0CA86a223f0F603A61B8"; + const dispenserJSON = "abis/0.8.18/Dispenser.json"; + const contractFromJSON = fs.readFileSync(dispenserJSON, "utf8"); + const parsedFile = JSON.parse(contractFromJSON); + const abi = parsedFile["abi"]; + const oldDispenser = new ethers.Contract(oldDispenserAddress, abi, provider); + + const AddressZero = ethers.constants.AddressZero; + const AddressNull = "0x000000000000000000000000000000000000dEaD"; + + // Proposal preparation + console.log("Proposal 9. Change dispenser address in tokenomics and treasury, disable old Dispenser"); + const targets = [tokenomicsProxyAddress, tokenomicsProxyAddress, treasuryAddress, oldDispenserAddress, + oldDispenserAddress]; + const values = [0, 0, 0, 0, 0]; + const callDatas = [ + tokenomics.interface.encodeFunctionData("changeManagers", [AddressZero, AddressZero, dispenserAddress]), + tokenomics.interface.encodeFunctionData("changeStakingParams", [maxStakingIncentive, minStakingWeight]), + treasury.interface.encodeFunctionData("changeManagers", [AddressZero, AddressZero, dispenserAddress]), + oldDispenser.interface.encodeFunctionData("changeManagers", [AddressNull, AddressNull]), + oldDispenser.interface.encodeFunctionData("changeOwner", [AddressNull]) + ]; + + const description = "Change Dispenser address in Tokenomics and Treasury, disable old Dispenser"; + + // Proposal details + console.log("targets:", targets); + console.log("values:", values); + console.log("call datas:", callDatas); + console.log("description:", description); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/test/Depository.t.sol b/test/Depository.t.sol index 0036156a..4971f5b2 100644 --- a/test/Depository.t.sol +++ b/test/Depository.t.sol @@ -6,8 +6,9 @@ import {ZuniswapV2Factory} from "zuniswapv2/ZuniswapV2Factory.sol"; import {ZuniswapV2Router} from "zuniswapv2/ZuniswapV2Router.sol"; import {ZuniswapV2Pair} from "zuniswapv2/ZuniswapV2Pair.sol"; import {Depository} from "../contracts/Depository.sol"; -import {GenericBondCalculator} from "../contracts/GenericBondCalculator.sol"; +import {BondCalculator, DiscountParams} from "../contracts/BondCalculator.sol"; import {MockTokenomics} from "../contracts/test/MockTokenomics.sol"; +import {MockVE} from "../contracts/test/MockVE.sol"; import {Treasury} from "../contracts/Treasury.sol"; import {MockERC20} from "../lib/zuniswapv2/lib/solmate/src/test/utils/mocks/MockERC20.sol"; @@ -20,7 +21,8 @@ contract BaseSetup is Test { MockTokenomics internal tokenomics; Treasury internal treasury; Depository internal depository; - GenericBondCalculator internal genericBondCalculator; + BondCalculator internal bondCalculator; + MockVE internal ve; address payable[] internal users; address internal deployer; @@ -56,11 +58,16 @@ contract BaseSetup is Test { tokenomics = new MockTokenomics(); // Correct depository address is missing here, it will be defined just one line below treasury = new Treasury(address(olas), address(tokenomics), deployer, deployer); - // Deploy generic bond calculator contract - genericBondCalculator = new GenericBondCalculator(address(olas), address(tokenomics)); + // veOLAS + ve = new MockVE(); + // Deploy bond calculator contract + DiscountParams memory discountParams; + discountParams.targetVotingPower = 10 ether; + discountParams.targetNewUnits = 10; + bondCalculator = new BondCalculator(address(olas), address(tokenomics), address(ve), discountParams); // Deploy depository contract depository = new Depository("Depository", "OLAS_BOND", "baseURI", address(olas), address(tokenomics), - address(treasury), address(genericBondCalculator)); + address(treasury), address(bondCalculator)); // Change depository contract addresses to the correct ones treasury.changeManagers(address(0), address(depository), address(0)); diff --git a/test/Depository2BondCalculator.js b/test/Depository2BondCalculator.js index 37004f6c..6c49513d 100644 --- a/test/Depository2BondCalculator.js +++ b/test/Depository2BondCalculator.js @@ -264,6 +264,10 @@ describe("Depository LP 2 Bond Calculator", async () => { defaultDiscountParams.weightFactors[3] = 1000; // Now able to change discount params await bondCalculator.changeDiscountParams(defaultDiscountParams); + + + const checkDiscountParams = await bondCalculator.getDiscountParams(); + expect(checkDiscountParams.weightFactors[3]).to.equal(defaultDiscountParams.weightFactors[3]); }); }); diff --git a/test/Depository2GenericBondCalculator.js b/test/Depository2GenericBondCalculator.js index 1f0ae270..91f14ce4 100644 --- a/test/Depository2GenericBondCalculator.js +++ b/test/Depository2GenericBondCalculator.js @@ -18,7 +18,7 @@ describe("Depository LP 2 Generic Bond Calculator", async () => { let olasFactory; let depositoryFactory; let tokenomicsFactory; - let genericBondCalculator; + let bondCalculator; let router; let factory; @@ -29,6 +29,7 @@ describe("Depository LP 2 Generic Bond Calculator", async () => { let treasury; let treasuryFactory; let tokenomics; + let ve; let epochLen = 86400 * 10; let defaultPriceLP = "2" + decimals; @@ -40,10 +41,16 @@ describe("Depository LP 2 Generic Bond Calculator", async () => { let vesting = oneWeek; - var productId = 0; + let productId = 0; let first; let id; + const discountParams = { + targetVotingPower: ethers.utils.parseEther("10"), + targetNewUnits: 10, + weightFactors: new Array(4).fill(0) + }; + let attackDepositFactory; let attackDeposit; @@ -64,22 +71,28 @@ describe("Depository LP 2 Generic Bond Calculator", async () => { dai = await erc20Token.deploy(); olas = await olasFactory.deploy(); + + // Voting Escrow mock + const VE = await ethers.getContractFactory("MockVE"); + ve = await VE.deploy(); + await ve.deployed(); + // Correct treasury address is missing here, it will be defined just one line below tokenomics = await tokenomicsFactory.deploy(); await tokenomics.initializeTokenomics(olas.address, deployer.address, deployer.address, deployer.address, - deployer.address, epochLen, deployer.address, deployer.address, deployer.address, AddressZero); + ve.address, epochLen, deployer.address, deployer.address, deployer.address, AddressZero); // Correct depository address is missing here, it will be defined just one line below treasury = await treasuryFactory.deploy(olas.address, tokenomics.address, deployer.address, deployer.address); // Change bond fraction to 100% in these tests await tokenomics.changeIncentiveFractions(66, 34, 100, 0, 0, 0); // Deploy generic bond calculator contract - const GenericBondCalculator = await ethers.getContractFactory("GenericBondCalculator"); - genericBondCalculator = await GenericBondCalculator.deploy(olas.address, tokenomics.address); - await genericBondCalculator.deployed(); + const BondCalculator = await ethers.getContractFactory("BondCalculator"); + bondCalculator = await BondCalculator.deploy(olas.address, tokenomics.address, ve.address, discountParams); + await bondCalculator.deployed(); // Deploy depository contract depository = await depositoryFactory.deploy("Depository", "OLAS_BOND", baseURI, olas.address, - tokenomics.address, treasury.address, genericBondCalculator.address); + tokenomics.address, treasury.address, bondCalculator.address); // Deploy Attack example attackDeposit = await attackDepositFactory.deploy(); @@ -220,7 +233,7 @@ describe("Depository LP 2 Generic Bond Calculator", async () => { // Trying to change bond calculator to a zero address that results in no change await depository.connect(deployer).changeBondCalculator(AddressZero); - expect(await depository.bondCalculator()).to.equal(genericBondCalculator.address); + expect(await depository.bondCalculator()).to.equal(bondCalculator.address); // Change bond calculator address await depository.connect(deployer).changeBondCalculator(account.address); diff --git a/test/DepositoryGenericBondCalculator.js b/test/DepositoryGenericBondCalculator.js index 22082e6a..666ac7d2 100644 --- a/test/DepositoryGenericBondCalculator.js +++ b/test/DepositoryGenericBondCalculator.js @@ -18,7 +18,7 @@ describe("Depository LP Generic Bond Calculator", async () => { let olasFactory; let depositoryFactory; let tokenomicsFactory; - let genericBondCalculator; + let bondCalculator; let router; let factory; @@ -29,6 +29,7 @@ describe("Depository LP Generic Bond Calculator", async () => { let treasury; let treasuryFactory; let tokenomics; + let ve; let epochLen = 86400 * 10; let defaultPriceLP = "2" + decimals; @@ -45,6 +46,12 @@ describe("Depository LP Generic Bond Calculator", async () => { let first; let id; + const discountParams = { + targetVotingPower: ethers.utils.parseEther("10"), + targetNewUnits: 10, + weightFactors: new Array(4).fill(0) + }; + let attackDepositFactory; let attackDeposit; @@ -65,22 +72,28 @@ describe("Depository LP Generic Bond Calculator", async () => { dai = await erc20Token.deploy(); olas = await olasFactory.deploy(); + + // Voting Escrow mock + const VE = await ethers.getContractFactory("MockVE"); + ve = await VE.deploy(); + await ve.deployed(); + // Correct treasury address is missing here, it will be defined just one line below tokenomics = await tokenomicsFactory.deploy(); await tokenomics.initializeTokenomics(olas.address, deployer.address, deployer.address, deployer.address, - deployer.address, epochLen, deployer.address, deployer.address, deployer.address, AddressZero); + ve.address, epochLen, deployer.address, deployer.address, deployer.address, AddressZero); // Correct depository address is missing here, it will be defined just one line below treasury = await treasuryFactory.deploy(olas.address, tokenomics.address, deployer.address, deployer.address); // Change bond fraction to 100% in these tests await tokenomics.changeIncentiveFractions(66, 34, 100, 0, 0, 0); // Deploy generic bond calculator contract - const GenericBondCalculator = await ethers.getContractFactory("GenericBondCalculator"); - genericBondCalculator = await GenericBondCalculator.deploy(olas.address, tokenomics.address); - await genericBondCalculator.deployed(); + const BondCalculator = await ethers.getContractFactory("BondCalculator"); + bondCalculator = await BondCalculator.deploy(olas.address, tokenomics.address, ve.address, discountParams); + await bondCalculator.deployed(); // Deploy depository contract depository = await depositoryFactory.deploy("Depository", "OLAS_BOND", baseURI, olas.address, - tokenomics.address, treasury.address, genericBondCalculator.address); + tokenomics.address, treasury.address, bondCalculator.address); // Deploy Attack example attackDeposit = await attackDepositFactory.deploy(); @@ -242,7 +255,7 @@ describe("Depository LP Generic Bond Calculator", async () => { // Trying to change bond calculator to a zero address that results in no change await depository.connect(deployer).changeBondCalculator(AddressZero); - expect(await depository.bondCalculator()).to.equal(genericBondCalculator.address); + expect(await depository.bondCalculator()).to.equal(bondCalculator.address); // Change bond calculator address await depository.connect(deployer).changeBondCalculator(account.address); @@ -250,13 +263,13 @@ describe("Depository LP Generic Bond Calculator", async () => { }); it("Should fail if any of bond calculator input addresses is a zero address", async function () { - const GenericBondCalculator = await ethers.getContractFactory("GenericBondCalculator"); + const BondCalculator = await ethers.getContractFactory("BondCalculator"); await expect( - GenericBondCalculator.deploy(AddressZero, tokenomics.address) - ).to.be.revertedWithCustomError(genericBondCalculator, "ZeroAddress"); + BondCalculator.deploy(AddressZero, tokenomics.address, AddressZero, discountParams) + ).to.be.revertedWithCustomError(bondCalculator, "ZeroAddress"); await expect( - GenericBondCalculator.deploy(olas.address, AddressZero) - ).to.be.revertedWithCustomError(genericBondCalculator, "ZeroAddress"); + BondCalculator.deploy(olas.address, AddressZero, AddressZero, discountParams) + ).to.be.revertedWithCustomError(bondCalculator, "ZeroAddress"); }); }); @@ -920,7 +933,7 @@ describe("Depository LP Generic Bond Calculator", async () => { // Now change the depository contract address const newDepository = await depositoryFactory.deploy("Depository", "OLAS_BOND", baseURI, olas.address, - tokenomics.address, treasury.address, genericBondCalculator.address); + tokenomics.address, treasury.address, bondCalculator.address); // Change to a new depository address await treasury.changeManagers(AddressZero, newDepository.address, AddressZero); diff --git a/test/Dispenser.t.sol b/test/Dispenser.t.sol index d9a12bfb..da8c5918 100644 --- a/test/Dispenser.t.sol +++ b/test/Dispenser.t.sol @@ -33,6 +33,7 @@ contract BaseSetup is Test { uint256 internal initialMint = 10_000_000_000e18; uint256 internal largeApproval = 1_000_000_000_000e18; uint256 epochLen = 30 days; + uint256 delta = 100; function setUp() public virtual { emptyArray = new uint256[](0); @@ -106,8 +107,8 @@ contract DispenserTest is BaseSetup { assertEq(reward, 0); assertEq(topUp, 0); - // Lock OLAS balances with Voting Escrow - ve.setWeightedBalance(tokenomics.veOLASThreshold()); + // Lock OLAS balances with Voting Escrow for a bigger amount compared with top-ups inflation + ve.setWeightedBalance(tokenomics.inflationPerSecond() * 365 days); ve.createLock(deployer); // Change the first service owner to the deployer (same for components and agents) @@ -173,20 +174,20 @@ contract DispenserTest is BaseSetup { balanceETH = address(deployer).balance - balanceETH; balanceOLAS = olas.balanceOf(deployer) - balanceOLAS; assertEq(balanceETH, accountRewards); - assertEq(balanceOLAS, accountTopUps); + assertLt(accountTopUps - balanceOLAS, delta); } /// @dev Deposit incentives for 2 services in a loop to go through a specified amount of time. /// @notice Assume that no single donation is bigger than 2^64 - 1. /// @param amount0 Amount to donate to the first service. /// @param amount1 Amount to donate to the second service. - function testIncentivesLoopDirect(uint64 amount0, uint64 amount1) public { + function testLoopDirectIncentives(uint64 amount0, uint64 amount1) public { // Amounts must be meaningful vm.assume(amount0 > treasury.minAcceptedETH()); vm.assume(amount1 > treasury.minAcceptedETH()); - // Lock OLAS balances with Voting Escrow - ve.setWeightedBalance(tokenomics.veOLASThreshold()); + // Lock OLAS balances with Voting Escrow for a bigger amount compared with top-ups inflation + ve.setWeightedBalance(tokenomics.getInflationForYear(4)); ve.createLock(deployer); // Change the first service owner to the deployer (same for components and agents) @@ -264,7 +265,7 @@ contract DispenserTest is BaseSetup { balanceETH = address(deployer).balance - balanceETH; balanceOLAS = olas.balanceOf(deployer) - balanceOLAS; assertEq(balanceETH, accountRewards); - assertEq(balanceOLAS, accountTopUps); + assertLt(accountTopUps - balanceOLAS, delta); } } @@ -277,8 +278,8 @@ contract DispenserTest is BaseSetup { vm.assume(amount0 > treasury.minAcceptedETH()); vm.assume(amount1 > treasury.minAcceptedETH()); - // Lock OLAS balances with Voting Escrow - ve.setWeightedBalance(tokenomics.veOLASThreshold()); + // Lock OLAS balances with Voting Escrow for a bigger amount compared with top-ups inflation + ve.setWeightedBalance(tokenomics.getInflationForYear(4)); ve.createLock(deployer); // Change the first service owner to the deployer (same for components and agents) @@ -341,7 +342,7 @@ contract DispenserTest is BaseSetup { balanceETH = address(deployer).balance - balanceETH; balanceOLAS = olas.balanceOf(deployer) - balanceOLAS; assertEq(balanceETH, accountRewards); - assertEq(balanceOLAS, accountTopUps); + assertLt(accountTopUps - balanceOLAS, delta); // Zero previously calculated rewards and top-ups rewards[0] = 0; diff --git a/test/DispenserDevIncentives.js b/test/DispenserDevIncentives.js index fecbf5f0..e3a20d79 100644 --- a/test/DispenserDevIncentives.js +++ b/test/DispenserDevIncentives.js @@ -225,12 +225,11 @@ describe("DispenserDevIncentives", async () => { await helpers.time.increase(epochLen + 10); await tokenomics.connect(deployer).checkpoint(); - // Get tokenomcis parameters from the previous epoch + // Get tokenomics parameters from the previous epoch let lastPoint = Number(await tokenomics.epochCounter()) - 1; // Get the epoch point of the last epoch let ep = await tokenomics.mapEpochTokenomics(lastPoint); expect(await tokenomics.devsPerCapital()).to.greaterThan(0); - expect(ep.idf).to.greaterThan(0); // Get the unit points of the last epoch let up = [await tokenomics.getUnitPoint(lastPoint, 0), await tokenomics.getUnitPoint(lastPoint, 1)]; expect(up[0].rewardUnitFraction + up[1].rewardUnitFraction + ep.rewardTreasuryFraction).to.equal(100); @@ -260,6 +259,121 @@ describe("DispenserDevIncentives", async () => { // Start new epoch and calculate tokenomics parameters and rewards await tokenomics.connect(deployer).checkpoint(); + // Get the last settled epoch counter + lastPoint = Number(await tokenomics.epochCounter()) - 1; + // Get the epoch point of the last epoch + ep = await tokenomics.mapEpochTokenomics(lastPoint); + // Get the unit points of the last epoch + up = [await tokenomics.getUnitPoint(lastPoint, 0), await tokenomics.getUnitPoint(lastPoint, 1)]; + // Calculate rewards based on the points information + const percentFraction = ethers.BigNumber.from(100); + let rewards = [ + ethers.BigNumber.from(ep.totalDonationsETH).mul(ethers.BigNumber.from(up[0].rewardUnitFraction)).div(percentFraction), + ethers.BigNumber.from(ep.totalDonationsETH).mul(ethers.BigNumber.from(up[1].rewardUnitFraction)).div(percentFraction) + ]; + let accountRewards = rewards[0].add(rewards[1]); + expect(accountRewards).to.greaterThan(0); + + // Since minWeightedBalance < top-ups inflation per epoch, the max top-ups can be equal to minWeightedBalance + let accountTopUps = minWeightedBalance; + expect(accountTopUps).to.greaterThan(0); + + // Check for the incentive balances of component and agent such that their pending relative incentives are non-zero + let incentiveBalances = await tokenomics.mapUnitIncentives(0, 1); + expect(Number(incentiveBalances.pendingRelativeReward)).to.greaterThan(0); + expect(Number(incentiveBalances.pendingRelativeTopUp)).to.greaterThan(0); + incentiveBalances = await tokenomics.mapUnitIncentives(1, 1); + expect(incentiveBalances.pendingRelativeReward).to.greaterThan(0); + expect(incentiveBalances.pendingRelativeTopUp).to.greaterThan(0); + + // Get deployer incentives information + const result = await tokenomics.getOwnerIncentives(deployer.address, [0, 1], [1, 1]); + // Get accumulated rewards and top-ups + const checkedReward = ethers.BigNumber.from(result.reward); + const checkedTopUp = ethers.BigNumber.from(result.topUp); + // Check if they match with what was written to the tokenomics point with owner reward and top-up fractions + // Theoretical values must always be bigger than calculated ones (since round-off error is due to flooring) + expect(Math.abs(Number(accountRewards.sub(checkedReward)))).to.lessThan(delta); + expect(Math.abs(Number(accountTopUps.sub(checkedTopUp)))).to.lessThan(delta); + + // Simulate claiming rewards and top-ups for owners and check their correctness + const claimedOwnerIncentives = await dispenser.connect(deployer).callStatic.claimOwnerIncentives([0, 1], [1, 1]); + // Get accumulated rewards and top-ups + let claimedReward = ethers.BigNumber.from(claimedOwnerIncentives.reward); + let claimedTopUp = ethers.BigNumber.from(claimedOwnerIncentives.topUp); + + // Check if they match with what was written to the tokenomics point with owner reward and top-up fractions + expect(claimedReward).to.lessThanOrEqual(accountRewards); + expect(Math.abs(Number(accountRewards.sub(claimedReward)))).to.lessThan(delta); + expect(claimedTopUp).to.lessThanOrEqual(accountTopUps); + expect(Math.abs(Number(accountTopUps.sub(claimedTopUp)))).to.lessThan(delta); + + // Claim rewards and top-ups + const balanceBeforeTopUps = ethers.BigNumber.from(await olas.balanceOf(deployer.address)); + await dispenser.connect(deployer).claimOwnerIncentives([0, 1], [1, 1]); + const balanceAfterTopUps = ethers.BigNumber.from(await olas.balanceOf(deployer.address)); + + // Check the OLAS balance after receiving incentives + const balance = balanceAfterTopUps.sub(balanceBeforeTopUps); + expect(balance).to.lessThanOrEqual(accountTopUps); + expect(Math.abs(Number(accountTopUps.sub(balance)))).to.lessThan(delta); + + // Restore to the state of the snapshot + await snapshot.restore(); + }); + + it("Claim incentives for unit owners with donation voting power bigger than the inflation", async () => { + // Take a snapshot of the current state of the blockchain + const snapshot = await helpers.takeSnapshot(); + + // Try to claim empty incentives + await expect( + dispenser.connect(deployer).claimOwnerIncentives([], []) + ).to.be.revertedWithCustomError(dispenser, "ClaimIncentivesFailed"); + + // Try to claim incentives for non-existent components + await expect( + dispenser.connect(deployer).claimOwnerIncentives([0], [0]) + ).to.be.revertedWithCustomError(tokenomics, "WrongUnitId"); + + // Skip the number of seconds for 2 epochs + await helpers.time.increase(epochLen + 10); + await tokenomics.connect(deployer).checkpoint(); + + // Get tokenomics parameters from the previous epoch + let lastPoint = Number(await tokenomics.epochCounter()) - 1; + // Get the epoch point of the last epoch + let ep = await tokenomics.mapEpochTokenomics(lastPoint); + expect(await tokenomics.devsPerCapital()).to.greaterThan(0); + // Get the unit points of the last epoch + let up = [await tokenomics.getUnitPoint(lastPoint, 0), await tokenomics.getUnitPoint(lastPoint, 1)]; + expect(up[0].rewardUnitFraction + up[1].rewardUnitFraction + ep.rewardTreasuryFraction).to.equal(100); + + await helpers.time.increase(epochLen + 10); + await tokenomics.connect(deployer).checkpoint(); + + // Send ETH to treasury + const amount = ethers.utils.parseEther("1000"); + await deployer.sendTransaction({to: treasury.address, value: amount}); + + // Lock OLAS balances with Voting Escrow for a bigger amount compared with top-ups inflation + const inflationPerYear = await tokenomics.getInflationForYear(0); + await ve.setWeightedBalance(inflationPerYear.toString()); + await ve.createLock(deployer.address); + + // Change the first service owner to the deployer (same for components and agents) + await serviceRegistry.changeUnitOwner(1, deployer.address); + await componentRegistry.changeUnitOwner(1, deployer.address); + await agentRegistry.changeUnitOwner(1, deployer.address); + + // Send donations to services + await treasury.connect(deployer).depositServiceDonationsETH([1, 2], [regDepositFromServices, regDepositFromServices], + {value: twoRegDepositFromServices}); + // Move more than one epoch in time + await helpers.time.increase(epochLen + 10); + // Start new epoch and calculate tokenomics parameters and rewards + await tokenomics.connect(deployer).checkpoint(); + // Get the last settled epoch counter lastPoint = Number(await tokenomics.epochCounter()) - 1; // Get the epoch point of the last epoch @@ -344,12 +458,11 @@ describe("DispenserDevIncentives", async () => { await helpers.time.increase(epochLen + 10); await tokenomics.connect(deployer).checkpoint(); - // Get tokenomcis parameters from the previous epoch + // Get tokenomics parameters from the previous epoch let lastPoint = Number(await tokenomics.epochCounter()) - 1; // Get the epoch point of the last epoch let ep = await tokenomics.mapEpochTokenomics(lastPoint); expect(await tokenomics.devsPerCapital()).to.greaterThan(0); - expect(ep.idf).to.greaterThan(0); // Get the unit points of the last epoch let up = [await tokenomics.getUnitPoint(lastPoint, 0), await tokenomics.getUnitPoint(lastPoint, 1)]; expect(up[0].rewardUnitFraction + up[1].rewardUnitFraction + ep.rewardTreasuryFraction).to.equal(100); @@ -361,9 +474,9 @@ describe("DispenserDevIncentives", async () => { const amount = ethers.utils.parseEther("1000"); await deployer.sendTransaction({to: treasury.address, value: amount}); - // Lock OLAS balances with Voting Escrow - const minWeightedBalance = await tokenomics.veOLASThreshold(); - await ve.setWeightedBalance(minWeightedBalance.toString()); + // Lock OLAS balances with Voting Escrow for a bigger amount compared with top-ups inflation + const inflationPerYear = await tokenomics.getInflationForYear(0); + await ve.setWeightedBalance(inflationPerYear.toString()); await ve.createLock(signers[1].address); // Change the first service owner to the deployer (same for components and agents) @@ -508,9 +621,10 @@ describe("DispenserDevIncentives", async () => { expect(checkedTopUp).to.equal(0); // EPOCH 2 with donations and top-ups - // Return the ability for the service owner to have enough veOLAS for the owner top-ups - const minWeightedBalance = await tokenomics.veOLASThreshold(); - await ve.setWeightedBalance(minWeightedBalance.toString()); + // Return the ability to donate + // Lock OLAS balances with Voting Escrow for a bigger amount compared with top-ups inflation + const inflationPerYear = await tokenomics.getInflationForYear(0); + await ve.setWeightedBalance(inflationPerYear.toString()); await ve.createLock(deployer.address); // Increase the time to more than the length of the epoch @@ -592,9 +706,9 @@ describe("DispenserDevIncentives", async () => { await helpers.time.increase(epochLen + 10); await tokenomics.connect(deployer).checkpoint(); - // Lock OLAS balances with Voting Escrow - const minWeightedBalance = await tokenomics.veOLASThreshold(); - await ve.setWeightedBalance(minWeightedBalance.toString()); + // Lock OLAS balances with Voting Escrow for a bigger amount compared with top-ups inflation + const inflationPerYear = await tokenomics.getInflationForYear(0); + await ve.setWeightedBalance(inflationPerYear.toString()); await ve.createLock(deployer.address); let totalAccountTopUps = ethers.BigNumber.from(0); @@ -668,9 +782,9 @@ describe("DispenserDevIncentives", async () => { const amount = ethers.utils.parseEther("1000"); await deployer.sendTransaction({to: treasury.address, value: amount}); - // Lock OLAS balances with Voting Escrow - const minWeightedBalance = await tokenomics.veOLASThreshold(); - await ve.setWeightedBalance(minWeightedBalance.toString()); + // Lock OLAS balances with Voting Escrow for a bigger amount compared with top-ups inflation + const inflationPerYear = await tokenomics.getInflationForYear(0); + await ve.setWeightedBalance(inflationPerYear.toString()); await ve.createLock(deployer.address); // Change the first service owner to the deployer (same for components and agents) @@ -767,9 +881,9 @@ describe("DispenserDevIncentives", async () => { const amount = ethers.utils.parseEther("1000"); await deployer.sendTransaction({to: treasury.address, value: amount}); - // Lock OLAS balances with Voting Escrow - const minWeightedBalance = await tokenomics.veOLASThreshold(); - await ve.setWeightedBalance(minWeightedBalance.toString()); + // Lock OLAS balances with Voting Escrow for a bigger amount compared with top-ups inflation + const inflationPerYear = await tokenomics.getInflationForYear(0); + await ve.setWeightedBalance(inflationPerYear.toString()); await ve.createLock(deployer.address); // Change the first service owner to the deployer (same for components and agents) @@ -866,9 +980,9 @@ describe("DispenserDevIncentives", async () => { const amount = ethers.utils.parseEther("1000"); await deployer.sendTransaction({to: treasury.address, value: amount}); - // Lock OLAS balances with Voting Escrow - const minWeightedBalance = await tokenomics.veOLASThreshold(); - await ve.setWeightedBalance(minWeightedBalance.toString()); + // Lock OLAS balances with Voting Escrow for a bigger amount compared with top-ups inflation + const inflationPerYear = await tokenomics.getInflationForYear(0); + await ve.setWeightedBalance(inflationPerYear.toString()); await ve.createLock(deployer.address); // Change the first service owner to the deployer (same for components and agents) @@ -965,9 +1079,9 @@ describe("DispenserDevIncentives", async () => { const amount = ethers.utils.parseEther("1000"); await deployer.sendTransaction({to: treasury.address, value: amount}); - // Lock OLAS balances with Voting Escrow - const minWeightedBalance = await tokenomics.veOLASThreshold(); - await ve.setWeightedBalance(minWeightedBalance.toString()); + // Lock OLAS balances with Voting Escrow for a bigger amount compared with top-ups inflation + const inflationPerYear = await tokenomics.getInflationForYear(0); + await ve.setWeightedBalance(inflationPerYear.toString()); await ve.createLock(deployer.address); // Change the first service owner to the deployer (same for components and agents) @@ -1083,9 +1197,9 @@ describe("DispenserDevIncentives", async () => { const amount = ethers.utils.parseEther("1000"); await deployer.sendTransaction({to: treasury.address, value: amount}); - // Lock OLAS balances with Voting Escrow - const minWeightedBalance = await tokenomics.veOLASThreshold(); - await ve.setWeightedBalance(minWeightedBalance.toString()); + // Lock OLAS balances with Voting Escrow for a bigger amount compared with top-ups inflation + const inflationPerYear = await tokenomics.getInflationForYear(0); + await ve.setWeightedBalance(inflationPerYear.toString()); await ve.createLock(deployer.address); // Change the first service owner to the deployer (same for components and agents) @@ -1165,7 +1279,12 @@ describe("DispenserDevIncentives", async () => { const amount = ethers.utils.parseEther("1000"); await deployer.sendTransaction({to: treasury.address, value: amount}); - // Lock OLAS balances with Voting Escrow for the attacker + // Unset attack mode in order to receive initial funds + await attacker.setAttackMode(false); + await deployer.sendTransaction({to: attacker.address, value: amount}); + await attacker.setAttackMode(true); + + // Lock OLAS balances for attacker await ve.createLock(attacker.address); // Change the first service owner to the attacker (same for components and agents) @@ -1174,7 +1293,7 @@ describe("DispenserDevIncentives", async () => { await agentRegistry.changeUnitOwner(1, attacker.address); // Send donations to services - await treasury.connect(deployer).depositServiceDonationsETH([1, 2], [regDepositFromServices, regDepositFromServices], + await attacker.depositServiceDonationsETH([1, 2], [regDepositFromServices, regDepositFromServices], {value: twoRegDepositFromServices}); // Move more than one epoch in time await helpers.time.increase(epochLen + 10); diff --git a/test/Tokenomics.js b/test/Tokenomics.js index c95b6134..3f27433b 100644 --- a/test/Tokenomics.js +++ b/test/Tokenomics.js @@ -1020,7 +1020,7 @@ describe("Tokenomics", async () => { await snapshot.restore(); }); - it("Get to the epoch before the end of the OLAS year and try to change maxBond or epochLen", async () => { + it("Get to two epochs before the end of the OLAS year and try to change epochLen", async () => { // Take a snapshot of the current state of the blockchain const snapshot = await helpers.takeSnapshot(); @@ -1030,7 +1030,7 @@ describe("Tokenomics", async () => { const yearChangeTime = timeLaunch + oneYear; // Get to the time of more than one epoch length before the year change (1.5 epoch length) - let timeEpochBeforeYearChange = yearChangeTime - epochLen - epochLen / 2; + const timeEpochBeforeYearChange = yearChangeTime - epochLen - epochLen / 2; await helpers.time.increaseTo(timeEpochBeforeYearChange); await tokenomics.checkpoint(); @@ -1041,12 +1041,23 @@ describe("Tokenomics", async () => { await helpers.time.increase(epochLen); await tokenomics.checkpoint(); expect(await tokenomics.epochLen()).to.equal(2 * epochLen); - // Restore the state of the blockchain back to the time half of the epoch before one epoch left for the current year - snapshotInternal.restore(); + + // Restore to the state of the snapshot + await snapshot.restore(); + }); + + it("Get to the epoch before the end of the OLAS year and try to change epochLen", async () => { + // Take a snapshot of the current state of the blockchain + const snapshot = await helpers.takeSnapshot(); + + // OLAS starting time + const timeLaunch = Number(await tokenomics.timeLaunch()); + // One year time from the launch + const yearChangeTime = timeLaunch + oneYear; // Get to the time of the half epoch length before the year change // Meaning that the year does not change yet during the current epoch, but it will during the next one - timeEpochBeforeYearChange += epochLen; + const timeEpochBeforeYearChange = yearChangeTime - epochLen / 2; await helpers.time.increaseTo(timeEpochBeforeYearChange); await tokenomics.checkpoint();