From 21ab9c1648f0905be439d2c25ac0fd6b27f12f9a Mon Sep 17 00:00:00 2001 From: "Julian M. Rodriguez" <56316686+julianmrodri@users.noreply.github.com> Date: Mon, 6 May 2024 11:37:31 -0300 Subject: [PATCH] Merge final 3.4.0 into fuzz (#1135) Co-authored-by: Taylor Brent Co-authored-by: brr Co-authored-by: Akshat Mittal Co-authored-by: pmckelvy1 Co-authored-by: omahs <73983677+omahs@users.noreply.github.com> Co-authored-by: Julian M. Rodriguez Co-authored-by: celest <109610497+0xCeletia@users.noreply.github.com> --- .openzeppelin/mainnet.json | 3238 +++++++++++++++++ common/blockchain-utils.ts | 17 +- common/configuration.ts | 16 +- contracts/facade/facets/ActFacet.sol | 3 +- contracts/facade/facets/ReadFacet.sol | 13 +- contracts/interfaces/IFacade.sol | 7 +- contracts/p1/StRSR.sol | 2 +- .../CurveAppreciatingRTokenFiatCollateral.sol | 4 +- .../assets/curve/CurveRecursiveCollateral.sol | 193 + .../assets/curve/stakedao/IStakeDAO.sol | 20 + .../stakedao/StakeDAORecursiveCollateral.sol | 59 + .../morpho-aave/MorphoFiatCollateral.sol | 2 +- .../MorphoSelfReferentialCollateral.sol | 17 +- docs/deployment-variables.md | 77 +- package.json | 9 +- run.sh | 1 + .../addresses/1-tmp-assets-collateral.json | 122 + scripts/addresses/1-tmp-deployments.json | 38 + .../8453-tmp-assets-collateral.json | 25 +- .../base-3.4.0/8453-tmp-deployments.json | 38 + .../1-tmp-assets-collateral.json | 103 +- .../mainnet-3.4.0/1-tmp-deployments.json | 38 + scripts/deploy.ts | 13 +- scripts/deployment/common.ts | 1 - .../phase1-core/0_setup_deployments.ts | 2 +- .../phase1-core/1_deploy_libraries.ts | 4 +- .../phase1-facade/2_deploy_actFacet.ts | 2 +- .../phase2-assets/assets/deploy_stg.ts | 4 +- .../collaterals/deploy_convex_ethplus_eth.ts | 5 +- .../deploy_convex_rToken_metapool_plugin.ts | 2 - .../deploy_convex_stable_metapool_plugin.ts | 2 - .../collaterals/deploy_curve_stable_plugin.ts | 2 +- .../deploy_stakedao_usdc_usdcplus.ts | 105 + .../deploy_stargate_usdc_collateral.ts | 1 + scripts/deployment/utils.ts | 29 +- scripts/refresh-whales.ts | 158 + scripts/verification/6_verify_collateral.ts | 30 +- .../verify_convex_ethplus_eth.ts | 5 +- .../collateral-plugins/verify_morpho.ts | 8 +- .../collateral-plugins/verify_sdai.ts | 4 +- .../collateral-plugins/verify_sfrax.ts | 4 +- .../verify_stakedao_usdc_usdcplus.ts | 80 + .../verify_yearn_v2_curve_usdc.ts | 15 +- scripts/verify_etherscan.ts | 8 +- scripts/whalesConfig.ts | 65 + tasks/deployment/create-deployer-registry.ts | 2 +- .../deployment/deploy-governor-anastasius.ts | 43 + tasks/index.ts | 7 +- tasks/testing/tenderly.ts | 64 - .../upgrade-checker-utils/upgrades/2_1_0.ts | 233 -- .../upgrade-checker-utils/upgrades/3_0_0.ts | 464 --- tasks/upgrades/validate-upgrade.ts | 14 +- tasks/{testing => validation}/mint-tokens.ts | 0 .../print-invariants.ts | 0 tasks/validation/proposal-validator.ts | 316 ++ tasks/validation/proposals/3_4_0.ts | 169 + ...8432860995231621586111571059800714939.json | 14 + ...8997429824418248202790423910218544052.json | 85 + tasks/validation/test-proposal.ts | 85 + .../utils}/constants.ts | 0 tasks/validation/utils/governance.ts | 262 ++ .../utils}/logs.ts | 0 tasks/validation/utils/oracles.ts | 145 + .../utils}/rewards.ts | 14 +- .../utils}/rtokens.ts | 2 +- tasks/validation/utils/trades.ts | 400 ++ .../utils}/upgrades/3_3_0_plugins.ts | 0 tasks/validation/whales/whales_1.json | 158 + tasks/validation/whales/whales_31337.json | 140 + tasks/validation/whales/whales_8453.json | 54 + test/Facade.test.ts | 10 +- test/ZTradingExtremes.test.ts | 32 +- test/fixtures.ts | 15 + test/integration/fork-block-numbers.ts | 2 +- .../compoundv3/CometTestSuite.test.ts | 7 +- .../curve/collateralTests.ts | 11 +- .../individual-collateral/curve/constants.ts | 19 +- ...xAppreciatingRTokenSelfReferential.test.ts | 9 +- .../curve/cvx/helpers.ts | 13 +- .../StakeDAORecursiveCollateral.test.ts | 311 ++ .../curve/stakedao/helpers.ts | 82 + .../MorphoAAVEFiatCollateral.test.ts | 22 +- .../MorphoAaveV2TokenisedDeposit.test.ts | 2 +- .../morpho-aave/mintCollateralTo.ts | 9 +- utils/env.ts | 1 + yarn.lock | 195 +- 86 files changed, 7009 insertions(+), 993 deletions(-) create mode 100644 contracts/plugins/assets/curve/CurveRecursiveCollateral.sol create mode 100644 contracts/plugins/assets/curve/stakedao/IStakeDAO.sol create mode 100644 contracts/plugins/assets/curve/stakedao/StakeDAORecursiveCollateral.sol create mode 100755 run.sh create mode 100644 scripts/addresses/1-tmp-assets-collateral.json create mode 100644 scripts/addresses/1-tmp-deployments.json create mode 100644 scripts/addresses/base-3.4.0/8453-tmp-deployments.json create mode 100644 scripts/addresses/mainnet-3.4.0/1-tmp-deployments.json create mode 100644 scripts/deployment/phase2-assets/collaterals/deploy_stakedao_usdc_usdcplus.ts create mode 100644 scripts/refresh-whales.ts create mode 100644 scripts/verification/collateral-plugins/verify_stakedao_usdc_usdcplus.ts create mode 100644 scripts/whalesConfig.ts create mode 100644 tasks/deployment/deploy-governor-anastasius.ts delete mode 100644 tasks/testing/tenderly.ts delete mode 100644 tasks/testing/upgrade-checker-utils/upgrades/2_1_0.ts delete mode 100644 tasks/testing/upgrade-checker-utils/upgrades/3_0_0.ts rename tasks/{testing => validation}/mint-tokens.ts (100%) rename tasks/{testing => validation}/print-invariants.ts (100%) create mode 100644 tasks/validation/proposal-validator.ts create mode 100644 tasks/validation/proposals/3_4_0.ts create mode 100644 tasks/validation/proposals/proposal-19635069547141631801899721667815895344178432860995231621586111571059800714939.json create mode 100644 tasks/validation/proposals/proposal-57514285674680658177308923843884653494858997429824418248202790423910218544052.json create mode 100644 tasks/validation/test-proposal.ts rename tasks/{testing/upgrade-checker-utils => validation/utils}/constants.ts (100%) create mode 100644 tasks/validation/utils/governance.ts rename tasks/{testing/upgrade-checker-utils => validation/utils}/logs.ts (100%) create mode 100644 tasks/validation/utils/oracles.ts rename tasks/{testing/upgrade-checker-utils => validation/utils}/rewards.ts (87%) rename tasks/{testing/upgrade-checker-utils => validation/utils}/rtokens.ts (99%) create mode 100644 tasks/validation/utils/trades.ts rename tasks/{testing/upgrade-checker-utils => validation/utils}/upgrades/3_3_0_plugins.ts (100%) create mode 100644 tasks/validation/whales/whales_1.json create mode 100644 tasks/validation/whales/whales_31337.json create mode 100644 tasks/validation/whales/whales_8453.json create mode 100644 test/plugins/individual-collateral/curve/stakedao/StakeDAORecursiveCollateral.test.ts create mode 100644 test/plugins/individual-collateral/curve/stakedao/helpers.ts diff --git a/.openzeppelin/mainnet.json b/.openzeppelin/mainnet.json index ed9459b7e3..7e50e1dc38 100644 --- a/.openzeppelin/mainnet.json +++ b/.openzeppelin/mainnet.json @@ -6928,6 +6928,3244 @@ } } } + }, + "7b21ba261eaa32c050f596075a3105499b91bb6fc0858682955d346a59ef20bb": { + "address": "0x24a4B37F9c40fB0E80ec436Df2e9989FBAFa8bB7", + "txHash": "0x55ae51af7516c2715f9e54dafff171f7d677e6dab413c46ea76c2b611aa8cb9d", + "layout": { + "solcVersion": "0.8.19", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC165Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41" + }, + { + "label": "_roles", + "offset": 0, + "slot": "101", + "type": "t_mapping(t_bytes32,t_struct(RoleData)3730_storage)", + "contract": "AccessControlUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:57" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)49_storage", + "contract": "AccessControlUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:260" + }, + { + "label": "longFreezes", + "offset": 0, + "slot": "151", + "type": "t_mapping(t_address,t_uint256)", + "contract": "Auth", + "src": "contracts/mixins/Auth.sol:36" + }, + { + "label": "unfreezeAt", + "offset": 0, + "slot": "152", + "type": "t_uint48", + "contract": "Auth", + "src": "contracts/mixins/Auth.sol:38" + }, + { + "label": "shortFreeze", + "offset": 6, + "slot": "152", + "type": "t_uint48", + "contract": "Auth", + "src": "contracts/mixins/Auth.sol:39" + }, + { + "label": "longFreeze", + "offset": 12, + "slot": "152", + "type": "t_uint48", + "contract": "Auth", + "src": "contracts/mixins/Auth.sol:40" + }, + { + "label": "tradingPaused", + "offset": 18, + "slot": "152", + "type": "t_bool", + "contract": "Auth", + "src": "contracts/mixins/Auth.sol:45", + "renamedFrom": "paused" + }, + { + "label": "issuancePaused", + "offset": 19, + "slot": "152", + "type": "t_bool", + "contract": "Auth", + "src": "contracts/mixins/Auth.sol:46" + }, + { + "label": "__gap", + "offset": 0, + "slot": "153", + "type": "t_array(t_uint256)48_storage", + "contract": "Auth", + "src": "contracts/mixins/Auth.sol:225" + }, + { + "label": "rToken", + "offset": 0, + "slot": "201", + "type": "t_contract(IRToken)32962", + "contract": "ComponentRegistry", + "src": "contracts/mixins/ComponentRegistry.sol:33" + }, + { + "label": "stRSR", + "offset": 0, + "slot": "202", + "type": "t_contract(IStRSR)33299", + "contract": "ComponentRegistry", + "src": "contracts/mixins/ComponentRegistry.sol:41" + }, + { + "label": "assetRegistry", + "offset": 0, + "slot": "203", + "type": "t_contract(IAssetRegistry)31093", + "contract": "ComponentRegistry", + "src": "contracts/mixins/ComponentRegistry.sol:49" + }, + { + "label": "basketHandler", + "offset": 0, + "slot": "204", + "type": "t_contract(IBasketHandler)31467", + "contract": "ComponentRegistry", + "src": "contracts/mixins/ComponentRegistry.sol:57" + }, + { + "label": "backingManager", + "offset": 0, + "slot": "205", + "type": "t_contract(IBackingManager)31200", + "contract": "ComponentRegistry", + "src": "contracts/mixins/ComponentRegistry.sol:65" + }, + { + "label": "distributor", + "offset": 0, + "slot": "206", + "type": "t_contract(IDistributor)31987", + "contract": "ComponentRegistry", + "src": "contracts/mixins/ComponentRegistry.sol:73" + }, + { + "label": "rsrTrader", + "offset": 0, + "slot": "207", + "type": "t_contract(IRevenueTrader)33090", + "contract": "ComponentRegistry", + "src": "contracts/mixins/ComponentRegistry.sol:81" + }, + { + "label": "rTokenTrader", + "offset": 0, + "slot": "208", + "type": "t_contract(IRevenueTrader)33090", + "contract": "ComponentRegistry", + "src": "contracts/mixins/ComponentRegistry.sol:89" + }, + { + "label": "furnace", + "offset": 0, + "slot": "209", + "type": "t_contract(IFurnace)32300", + "contract": "ComponentRegistry", + "src": "contracts/mixins/ComponentRegistry.sol:97" + }, + { + "label": "broker", + "offset": 0, + "slot": "210", + "type": "t_contract(IBroker)31622", + "contract": "ComponentRegistry", + "src": "contracts/mixins/ComponentRegistry.sol:105" + }, + { + "label": "__gap", + "offset": 0, + "slot": "211", + "type": "t_array(t_uint256)40_storage", + "contract": "ComponentRegistry", + "src": "contracts/mixins/ComponentRegistry.sol:118" + }, + { + "label": "__gap", + "offset": 0, + "slot": "251", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC1967UpgradeUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol:169" + }, + { + "label": "__gap", + "offset": 0, + "slot": "301", + "type": "t_array(t_uint256)50_storage", + "contract": "UUPSUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol:111" + }, + { + "label": "rsr", + "offset": 0, + "slot": "351", + "type": "t_contract(IERC20)16483", + "contract": "MainP1", + "src": "contracts/p1/Main.sol:19" + }, + { + "label": "__gap", + "offset": 0, + "slot": "352", + "type": "t_array(t_uint256)49_storage", + "contract": "MainP1", + "src": "contracts/p1/Main.sol:70" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_uint256)40_storage": { + "label": "uint256[40]", + "numberOfBytes": "1280" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_contract(IAssetRegistry)31093": { + "label": "contract IAssetRegistry", + "numberOfBytes": "20" + }, + "t_contract(IBackingManager)31200": { + "label": "contract IBackingManager", + "numberOfBytes": "20" + }, + "t_contract(IBasketHandler)31467": { + "label": "contract IBasketHandler", + "numberOfBytes": "20" + }, + "t_contract(IBroker)31622": { + "label": "contract IBroker", + "numberOfBytes": "20" + }, + "t_contract(IDistributor)31987": { + "label": "contract IDistributor", + "numberOfBytes": "20" + }, + "t_contract(IERC20)16483": { + "label": "contract IERC20", + "numberOfBytes": "20" + }, + "t_contract(IFurnace)32300": { + "label": "contract IFurnace", + "numberOfBytes": "20" + }, + "t_contract(IRToken)32962": { + "label": "contract IRToken", + "numberOfBytes": "20" + }, + "t_contract(IRevenueTrader)33090": { + "label": "contract IRevenueTrader", + "numberOfBytes": "20" + }, + "t_contract(IStRSR)33299": { + "label": "contract IStRSR", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_struct(RoleData)3730_storage)": { + "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)", + "numberOfBytes": "32" + }, + "t_struct(RoleData)3730_storage": { + "label": "struct AccessControlUpgradeable.RoleData", + "members": [ + { + "label": "members", + "type": "t_mapping(t_address,t_bool)", + "offset": 0, + "slot": "0" + }, + { + "label": "adminRole", + "type": "t_bytes32", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint48": { + "label": "uint48", + "numberOfBytes": "6" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } + }, + "9e6f4198309784cc2a3e363639954bc4a3130f1b175b95d43a9fe332ca0bf7ca": { + "address": "0xbF1C0206de440b2cF76Ea4405e1DbF2fC227a463", + "txHash": "0x4ab68d516f640ed8fee76a1fa33e751388d98def56e38380618f8f68c5fc6131", + "layout": { + "solcVersion": "0.8.19", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC1967UpgradeUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol:169" + }, + { + "label": "__gap", + "offset": 0, + "slot": "101", + "type": "t_array(t_uint256)50_storage", + "contract": "UUPSUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol:111" + }, + { + "label": "main", + "offset": 0, + "slot": "151", + "type": "t_contract(IMain)32744", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:21" + }, + { + "label": "__gap", + "offset": 0, + "slot": "152", + "type": "t_array(t_uint256)49_storage", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:69" + }, + { + "label": "basketHandler", + "offset": 0, + "slot": "201", + "type": "t_contract(IBasketHandler)31467", + "contract": "AssetRegistryP1", + "src": "contracts/p1/AssetRegistry.sol:19" + }, + { + "label": "backingManager", + "offset": 0, + "slot": "202", + "type": "t_contract(IBackingManager)31200", + "contract": "AssetRegistryP1", + "src": "contracts/p1/AssetRegistry.sol:20" + }, + { + "label": "_erc20s", + "offset": 0, + "slot": "203", + "type": "t_struct(AddressSet)25226_storage", + "contract": "AssetRegistryP1", + "src": "contracts/p1/AssetRegistry.sol:23" + }, + { + "label": "assets", + "offset": 0, + "slot": "205", + "type": "t_mapping(t_contract(IERC20)16483,t_contract(IAsset)30826)", + "contract": "AssetRegistryP1", + "src": "contracts/p1/AssetRegistry.sol:26" + }, + { + "label": "lastRefresh", + "offset": 0, + "slot": "206", + "type": "t_uint48", + "contract": "AssetRegistryP1", + "src": "contracts/p1/AssetRegistry.sol:30" + }, + { + "label": "__gap", + "offset": 0, + "slot": "207", + "type": "t_array(t_uint256)46_storage", + "contract": "AssetRegistryP1", + "src": "contracts/p1/AssetRegistry.sol:237" + } + ], + "types": { + "t_array(t_bytes32)dyn_storage": { + "label": "bytes32[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)46_storage": { + "label": "uint256[46]", + "numberOfBytes": "1472" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_contract(IAsset)30826": { + "label": "contract IAsset", + "numberOfBytes": "20" + }, + "t_contract(IBackingManager)31200": { + "label": "contract IBackingManager", + "numberOfBytes": "20" + }, + "t_contract(IBasketHandler)31467": { + "label": "contract IBasketHandler", + "numberOfBytes": "20" + }, + "t_contract(IERC20)16483": { + "label": "contract IERC20", + "numberOfBytes": "20" + }, + "t_contract(IMain)32744": { + "label": "contract IMain", + "numberOfBytes": "20" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_contract(IERC20)16483,t_contract(IAsset)30826)": { + "label": "mapping(contract IERC20 => contract IAsset)", + "numberOfBytes": "32" + }, + "t_struct(AddressSet)25226_storage": { + "label": "struct EnumerableSet.AddressSet", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)24911_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Set)24911_storage": { + "label": "struct EnumerableSet.Set", + "members": [ + { + "label": "_values", + "type": "t_array(t_bytes32)dyn_storage", + "offset": 0, + "slot": "0" + }, + { + "label": "_indexes", + "type": "t_mapping(t_bytes32,t_uint256)", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint48": { + "label": "uint48", + "numberOfBytes": "6" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } + }, + "dccc8209182e300c142d833ea5134cffa74c8c66d5db877c4e0f6dbd41138cd2": { + "address": "0x20C801869e578E71F2298649870765Aa81f7DC69", + "txHash": "0xbdfc558729b1f69ed8077a9f593db9be5b4a6ef0c2e349bdbf3946dd39320fdc", + "layout": { + "solcVersion": "0.8.19", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC1967UpgradeUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol:169" + }, + { + "label": "__gap", + "offset": 0, + "slot": "101", + "type": "t_array(t_uint256)50_storage", + "contract": "UUPSUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol:111" + }, + { + "label": "main", + "offset": 0, + "slot": "151", + "type": "t_contract(IMain)32744", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:21" + }, + { + "label": "__gap", + "offset": 0, + "slot": "152", + "type": "t_array(t_uint256)49_storage", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:69" + }, + { + "label": "_status", + "offset": 0, + "slot": "201", + "type": "t_uint256", + "contract": "ReentrancyGuardUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:38" + }, + { + "label": "__gap", + "offset": 0, + "slot": "202", + "type": "t_array(t_uint256)49_storage", + "contract": "ReentrancyGuardUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:88" + }, + { + "label": "broker", + "offset": 0, + "slot": "251", + "type": "t_contract(IBroker)31622", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:26" + }, + { + "label": "trades", + "offset": 0, + "slot": "252", + "type": "t_mapping(t_contract(IERC20)16483,t_contract(ITrade)33446)", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:29" + }, + { + "label": "tradesOpen", + "offset": 0, + "slot": "253", + "type": "t_uint48", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:30" + }, + { + "label": "maxTradeSlippage", + "offset": 6, + "slot": "253", + "type": "t_uint192", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:33" + }, + { + "label": "minTradeVolume", + "offset": 0, + "slot": "254", + "type": "t_uint192", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:34" + }, + { + "label": "tradesNonce", + "offset": 0, + "slot": "255", + "type": "t_uint256", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:37" + }, + { + "label": "__gap", + "offset": 0, + "slot": "256", + "type": "t_array(t_uint256)45_storage", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:164" + }, + { + "label": "assetRegistry", + "offset": 0, + "slot": "301", + "type": "t_contract(IAssetRegistry)31093", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:25" + }, + { + "label": "basketHandler", + "offset": 0, + "slot": "302", + "type": "t_contract(IBasketHandler)31467", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:26" + }, + { + "label": "distributor", + "offset": 0, + "slot": "303", + "type": "t_contract(IDistributor)31987", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:27" + }, + { + "label": "rToken", + "offset": 0, + "slot": "304", + "type": "t_contract(IRToken)32962", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:28" + }, + { + "label": "rsr", + "offset": 0, + "slot": "305", + "type": "t_contract(IERC20)16483", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:29" + }, + { + "label": "stRSR", + "offset": 0, + "slot": "306", + "type": "t_contract(IStRSR)33299", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:30" + }, + { + "label": "rsrTrader", + "offset": 0, + "slot": "307", + "type": "t_contract(IRevenueTrader)33090", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:31" + }, + { + "label": "rTokenTrader", + "offset": 0, + "slot": "308", + "type": "t_contract(IRevenueTrader)33090", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:32" + }, + { + "label": "tradingDelay", + "offset": 20, + "slot": "308", + "type": "t_uint48", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:36" + }, + { + "label": "backingBuffer", + "offset": 0, + "slot": "309", + "type": "t_uint192", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:37" + }, + { + "label": "furnace", + "offset": 0, + "slot": "310", + "type": "t_contract(IFurnace)32300", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:40" + }, + { + "label": "tradeEnd", + "offset": 0, + "slot": "311", + "type": "t_mapping(t_enum(TradeKind)31495,t_uint48)", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:41" + }, + { + "label": "tokensOut", + "offset": 0, + "slot": "312", + "type": "t_mapping(t_contract(IERC20)16483,t_uint192)", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:44" + }, + { + "label": "__gap", + "offset": 0, + "slot": "313", + "type": "t_array(t_uint256)38_storage", + "contract": "BackingManagerP1", + "src": "contracts/p1/BackingManager.sol:344" + } + ], + "types": { + "t_array(t_uint256)38_storage": { + "label": "uint256[38]", + "numberOfBytes": "1216" + }, + "t_array(t_uint256)45_storage": { + "label": "uint256[45]", + "numberOfBytes": "1440" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(IAssetRegistry)31093": { + "label": "contract IAssetRegistry", + "numberOfBytes": "20" + }, + "t_contract(IBasketHandler)31467": { + "label": "contract IBasketHandler", + "numberOfBytes": "20" + }, + "t_contract(IBroker)31622": { + "label": "contract IBroker", + "numberOfBytes": "20" + }, + "t_contract(IDistributor)31987": { + "label": "contract IDistributor", + "numberOfBytes": "20" + }, + "t_contract(IERC20)16483": { + "label": "contract IERC20", + "numberOfBytes": "20" + }, + "t_contract(IFurnace)32300": { + "label": "contract IFurnace", + "numberOfBytes": "20" + }, + "t_contract(IMain)32744": { + "label": "contract IMain", + "numberOfBytes": "20" + }, + "t_contract(IRToken)32962": { + "label": "contract IRToken", + "numberOfBytes": "20" + }, + "t_contract(IRevenueTrader)33090": { + "label": "contract IRevenueTrader", + "numberOfBytes": "20" + }, + "t_contract(IStRSR)33299": { + "label": "contract IStRSR", + "numberOfBytes": "20" + }, + "t_contract(ITrade)33446": { + "label": "contract ITrade", + "numberOfBytes": "20" + }, + "t_enum(TradeKind)31495": { + "label": "enum TradeKind", + "members": [ + "DUTCH_AUCTION", + "BATCH_AUCTION" + ], + "numberOfBytes": "1" + }, + "t_mapping(t_contract(IERC20)16483,t_contract(ITrade)33446)": { + "label": "mapping(contract IERC20 => contract ITrade)", + "numberOfBytes": "32" + }, + "t_mapping(t_contract(IERC20)16483,t_uint192)": { + "label": "mapping(contract IERC20 => uint192)", + "numberOfBytes": "32" + }, + "t_mapping(t_enum(TradeKind)31495,t_uint48)": { + "label": "mapping(enum TradeKind => uint48)", + "numberOfBytes": "32" + }, + "t_uint192": { + "label": "uint192", + "numberOfBytes": "24" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint48": { + "label": "uint48", + "numberOfBytes": "6" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } + }, + "8b6036debddeb199ea8fa112563fdd30275fcf05f63c69b0dc63a65819654697": { + "address": "0xeE7FC703f84AE2CE30475333c57E56d3A7D3AdBC", + "txHash": "0x482861a6731e61d438d5525fa01047083c9013c238eea65628185ce356ce9797", + "layout": { + "solcVersion": "0.8.19", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC1967UpgradeUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol:169" + }, + { + "label": "__gap", + "offset": 0, + "slot": "101", + "type": "t_array(t_uint256)50_storage", + "contract": "UUPSUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol:111" + }, + { + "label": "main", + "offset": 0, + "slot": "151", + "type": "t_contract(IMain)14381", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:21" + }, + { + "label": "__gap", + "offset": 0, + "slot": "152", + "type": "t_array(t_uint256)49_storage", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:69" + }, + { + "label": "assetRegistry", + "offset": 0, + "slot": "201", + "type": "t_contract(IAssetRegistry)13147", + "contract": "BasketHandlerP1", + "src": "contracts/p1/BasketHandler.sol:35" + }, + { + "label": "backingManager", + "offset": 0, + "slot": "202", + "type": "t_contract(IBackingManager)13254", + "contract": "BasketHandlerP1", + "src": "contracts/p1/BasketHandler.sol:36" + }, + { + "label": "rsr", + "offset": 0, + "slot": "203", + "type": "t_contract(IERC20)6312", + "contract": "BasketHandlerP1", + "src": "contracts/p1/BasketHandler.sol:37" + }, + { + "label": "rToken", + "offset": 0, + "slot": "204", + "type": "t_contract(IRToken)14599", + "contract": "BasketHandlerP1", + "src": "contracts/p1/BasketHandler.sol:38" + }, + { + "label": "stRSR", + "offset": 0, + "slot": "205", + "type": "t_contract(IStRSR)14912", + "contract": "BasketHandlerP1", + "src": "contracts/p1/BasketHandler.sol:39" + }, + { + "label": "config", + "offset": 0, + "slot": "206", + "type": "t_struct(BasketConfig)24356_storage", + "contract": "BasketHandlerP1", + "src": "contracts/p1/BasketHandler.sol:43" + }, + { + "label": "basket", + "offset": 0, + "slot": "210", + "type": "t_struct(Basket)24366_storage", + "contract": "BasketHandlerP1", + "src": "contracts/p1/BasketHandler.sol:47" + }, + { + "label": "nonce", + "offset": 0, + "slot": "212", + "type": "t_uint48", + "contract": "BasketHandlerP1", + "src": "contracts/p1/BasketHandler.sol:49" + }, + { + "label": "timestamp", + "offset": 6, + "slot": "212", + "type": "t_uint48", + "contract": "BasketHandlerP1", + "src": "contracts/p1/BasketHandler.sol:50" + }, + { + "label": "disabled", + "offset": 12, + "slot": "212", + "type": "t_bool", + "contract": "BasketHandlerP1", + "src": "contracts/p1/BasketHandler.sol:54" + }, + { + "label": "_targetNames", + "offset": 0, + "slot": "213", + "type": "t_struct(Bytes32Set)9523_storage", + "contract": "BasketHandlerP1", + "src": "contracts/p1/BasketHandler.sol:60" + }, + { + "label": "_newBasket", + "offset": 0, + "slot": "215", + "type": "t_struct(Basket)24366_storage", + "contract": "BasketHandlerP1", + "src": "contracts/p1/BasketHandler.sol:61" + }, + { + "label": "warmupPeriod", + "offset": 0, + "slot": "217", + "type": "t_uint48", + "contract": "BasketHandlerP1", + "src": "contracts/p1/BasketHandler.sol:67" + }, + { + "label": "lastStatusTimestamp", + "offset": 6, + "slot": "217", + "type": "t_uint48", + "contract": "BasketHandlerP1", + "src": "contracts/p1/BasketHandler.sol:71" + }, + { + "label": "lastStatus", + "offset": 12, + "slot": "217", + "type": "t_enum(CollateralStatus)12930", + "contract": "BasketHandlerP1", + "src": "contracts/p1/BasketHandler.sol:72" + }, + { + "label": "basketHistory", + "offset": 0, + "slot": "218", + "type": "t_mapping(t_uint48,t_struct(Basket)24366_storage)", + "contract": "BasketHandlerP1", + "src": "contracts/p1/BasketHandler.sol:78" + }, + { + "label": "_targetAmts", + "offset": 0, + "slot": "219", + "type": "t_struct(Bytes32ToUintMap)9105_storage", + "contract": "BasketHandlerP1", + "src": "contracts/p1/BasketHandler.sol:81" + }, + { + "label": "reweightable", + "offset": 0, + "slot": "222", + "type": "t_bool", + "contract": "BasketHandlerP1", + "src": "contracts/p1/BasketHandler.sol:87" + }, + { + "label": "lastCollateralized", + "offset": 1, + "slot": "222", + "type": "t_uint48", + "contract": "BasketHandlerP1", + "src": "contracts/p1/BasketHandler.sol:89" + }, + { + "label": "__gap", + "offset": 0, + "slot": "223", + "type": "t_array(t_uint256)36_storage", + "contract": "BasketHandlerP1", + "src": "contracts/p1/BasketHandler.sol:728" + } + ], + "types": { + "t_array(t_bytes32)dyn_storage": { + "label": "bytes32[]", + "numberOfBytes": "32" + }, + "t_array(t_contract(IERC20)6312)dyn_storage": { + "label": "contract IERC20[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)36_storage": { + "label": "uint256[36]", + "numberOfBytes": "1152" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_contract(IAssetRegistry)13147": { + "label": "contract IAssetRegistry", + "numberOfBytes": "20" + }, + "t_contract(IBackingManager)13254": { + "label": "contract IBackingManager", + "numberOfBytes": "20" + }, + "t_contract(IERC20)6312": { + "label": "contract IERC20", + "numberOfBytes": "20" + }, + "t_contract(IMain)14381": { + "label": "contract IMain", + "numberOfBytes": "20" + }, + "t_contract(IRToken)14599": { + "label": "contract IRToken", + "numberOfBytes": "20" + }, + "t_contract(IStRSR)14912": { + "label": "contract IStRSR", + "numberOfBytes": "20" + }, + "t_enum(CollateralStatus)12930": { + "label": "enum CollateralStatus", + "members": [ + "SOUND", + "IFFY", + "DISABLED" + ], + "numberOfBytes": "1" + }, + "t_mapping(t_bytes32,t_bytes32)": { + "label": "mapping(bytes32 => bytes32)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_struct(BackupConfig)24336_storage)": { + "label": "mapping(bytes32 => struct BackupConfig)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_contract(IERC20)6312,t_bytes32)": { + "label": "mapping(contract IERC20 => bytes32)", + "numberOfBytes": "32" + }, + "t_mapping(t_contract(IERC20)6312,t_uint192)": { + "label": "mapping(contract IERC20 => uint192)", + "numberOfBytes": "32" + }, + "t_mapping(t_uint48,t_struct(Basket)24366_storage)": { + "label": "mapping(uint48 => struct Basket)", + "numberOfBytes": "32" + }, + "t_struct(BackupConfig)24336_storage": { + "label": "struct BackupConfig", + "members": [ + { + "label": "max", + "type": "t_uint256", + "offset": 0, + "slot": "0" + }, + { + "label": "erc20s", + "type": "t_array(t_contract(IERC20)6312)dyn_storage", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Basket)24366_storage": { + "label": "struct Basket", + "members": [ + { + "label": "erc20s", + "type": "t_array(t_contract(IERC20)6312)dyn_storage", + "offset": 0, + "slot": "0" + }, + { + "label": "refAmts", + "type": "t_mapping(t_contract(IERC20)6312,t_uint192)", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_struct(BasketConfig)24356_storage": { + "label": "struct BasketConfig", + "members": [ + { + "label": "erc20s", + "type": "t_array(t_contract(IERC20)6312)dyn_storage", + "offset": 0, + "slot": "0" + }, + { + "label": "targetAmts", + "type": "t_mapping(t_contract(IERC20)6312,t_uint192)", + "offset": 0, + "slot": "1" + }, + { + "label": "targetNames", + "type": "t_mapping(t_contract(IERC20)6312,t_bytes32)", + "offset": 0, + "slot": "2" + }, + { + "label": "backups", + "type": "t_mapping(t_bytes32,t_struct(BackupConfig)24336_storage)", + "offset": 0, + "slot": "3" + } + ], + "numberOfBytes": "128" + }, + "t_struct(Bytes32Set)9523_storage": { + "label": "struct EnumerableSet.Bytes32Set", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)9329_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Bytes32ToBytes32Map)8076_storage": { + "label": "struct EnumerableMap.Bytes32ToBytes32Map", + "members": [ + { + "label": "_keys", + "type": "t_struct(Bytes32Set)9523_storage", + "offset": 0, + "slot": "0" + }, + { + "label": "_values", + "type": "t_mapping(t_bytes32,t_bytes32)", + "offset": 0, + "slot": "2" + } + ], + "numberOfBytes": "96" + }, + "t_struct(Bytes32ToUintMap)9105_storage": { + "label": "struct EnumerableMap.Bytes32ToUintMap", + "members": [ + { + "label": "_inner", + "type": "t_struct(Bytes32ToBytes32Map)8076_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "96" + }, + "t_struct(Set)9329_storage": { + "label": "struct EnumerableSet.Set", + "members": [ + { + "label": "_values", + "type": "t_array(t_bytes32)dyn_storage", + "offset": 0, + "slot": "0" + }, + { + "label": "_indexes", + "type": "t_mapping(t_bytes32,t_uint256)", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint192": { + "label": "uint192", + "numberOfBytes": "24" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint48": { + "label": "uint48", + "numberOfBytes": "6" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } + }, + "8fac727ec1a54b397875c4baa54e123813976105c25207a68c511e4572cc5270": { + "address": "0x62BD44b05542bfF1E59A01Bf7151F533e1c9C12c", + "txHash": "0xd57d5c2b310bb77d7ebb7a4b13affdb8dcb80400f1caacf6776ad17e761aafcb", + "layout": { + "solcVersion": "0.8.19", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC1967UpgradeUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol:169" + }, + { + "label": "__gap", + "offset": 0, + "slot": "101", + "type": "t_array(t_uint256)50_storage", + "contract": "UUPSUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol:111" + }, + { + "label": "main", + "offset": 0, + "slot": "151", + "type": "t_contract(IMain)32744", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:21" + }, + { + "label": "__gap", + "offset": 0, + "slot": "152", + "type": "t_array(t_uint256)49_storage", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:69" + }, + { + "label": "backingManager", + "offset": 0, + "slot": "201", + "type": "t_contract(IBackingManager)31200", + "contract": "BrokerP1", + "src": "contracts/p1/Broker.sol:30" + }, + { + "label": "rsrTrader", + "offset": 0, + "slot": "202", + "type": "t_contract(IRevenueTrader)33090", + "contract": "BrokerP1", + "src": "contracts/p1/Broker.sol:31" + }, + { + "label": "rTokenTrader", + "offset": 0, + "slot": "203", + "type": "t_contract(IRevenueTrader)33090", + "contract": "BrokerP1", + "src": "contracts/p1/Broker.sol:32" + }, + { + "label": "batchTradeImplementation", + "offset": 0, + "slot": "204", + "type": "t_contract(ITrade)33446", + "contract": "BrokerP1", + "src": "contracts/p1/Broker.sol:36", + "renamedFrom": "tradeImplementation" + }, + { + "label": "gnosis", + "offset": 0, + "slot": "205", + "type": "t_contract(IGnosis)32400", + "contract": "BrokerP1", + "src": "contracts/p1/Broker.sol:39" + }, + { + "label": "batchAuctionLength", + "offset": 20, + "slot": "205", + "type": "t_uint48", + "contract": "BrokerP1", + "src": "contracts/p1/Broker.sol:43", + "renamedFrom": "auctionLength" + }, + { + "label": "batchTradeDisabled", + "offset": 26, + "slot": "205", + "type": "t_bool", + "contract": "BrokerP1", + "src": "contracts/p1/Broker.sol:49", + "renamedFrom": "disabled" + }, + { + "label": "trades", + "offset": 0, + "slot": "206", + "type": "t_mapping(t_address,t_bool)", + "contract": "BrokerP1", + "src": "contracts/p1/Broker.sol:52" + }, + { + "label": "dutchTradeImplementation", + "offset": 0, + "slot": "207", + "type": "t_contract(ITrade)33446", + "contract": "BrokerP1", + "src": "contracts/p1/Broker.sol:57" + }, + { + "label": "dutchAuctionLength", + "offset": 20, + "slot": "207", + "type": "t_uint48", + "contract": "BrokerP1", + "src": "contracts/p1/Broker.sol:60" + }, + { + "label": "dutchTradeDisabled", + "offset": 0, + "slot": "208", + "type": "t_mapping(t_contract(IERC20Metadata)17135,t_bool)", + "contract": "BrokerP1", + "src": "contracts/p1/Broker.sol:63" + }, + { + "label": "rToken", + "offset": 0, + "slot": "209", + "type": "t_contract(IRToken)32962", + "contract": "BrokerP1", + "src": "contracts/p1/Broker.sol:67" + }, + { + "label": "__gap", + "offset": 0, + "slot": "210", + "type": "t_array(t_uint256)41_storage", + "contract": "BrokerP1", + "src": "contracts/p1/Broker.sol:293" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_uint256)41_storage": { + "label": "uint256[41]", + "numberOfBytes": "1312" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(IBackingManager)31200": { + "label": "contract IBackingManager", + "numberOfBytes": "20" + }, + "t_contract(IERC20Metadata)17135": { + "label": "contract IERC20Metadata", + "numberOfBytes": "20" + }, + "t_contract(IGnosis)32400": { + "label": "contract IGnosis", + "numberOfBytes": "20" + }, + "t_contract(IMain)32744": { + "label": "contract IMain", + "numberOfBytes": "20" + }, + "t_contract(IRToken)32962": { + "label": "contract IRToken", + "numberOfBytes": "20" + }, + "t_contract(IRevenueTrader)33090": { + "label": "contract IRevenueTrader", + "numberOfBytes": "20" + }, + "t_contract(ITrade)33446": { + "label": "contract ITrade", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "numberOfBytes": "32" + }, + "t_mapping(t_contract(IERC20Metadata)17135,t_bool)": { + "label": "mapping(contract IERC20Metadata => bool)", + "numberOfBytes": "32" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint48": { + "label": "uint48", + "numberOfBytes": "6" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } + }, + "cd59c74dbbcdccc4cd63cefc93f3019c084744d14f3d461de54da1299450e0e1": { + "address": "0x44a42A0F14128E81a21c5fc4322a9f91fF83b4Ee", + "txHash": "0x26e6e2921870e316864a24a50664451ab836dbbff52f917b8885e647577f639a", + "layout": { + "solcVersion": "0.8.19", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC1967UpgradeUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol:169" + }, + { + "label": "__gap", + "offset": 0, + "slot": "101", + "type": "t_array(t_uint256)50_storage", + "contract": "UUPSUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol:111" + }, + { + "label": "main", + "offset": 0, + "slot": "151", + "type": "t_contract(IMain)32744", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:21" + }, + { + "label": "__gap", + "offset": 0, + "slot": "152", + "type": "t_array(t_uint256)49_storage", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:69" + }, + { + "label": "destinations", + "offset": 0, + "slot": "201", + "type": "t_struct(AddressSet)25226_storage", + "contract": "DistributorP1", + "src": "contracts/p1/Distributor.sol:17" + }, + { + "label": "distribution", + "offset": 0, + "slot": "203", + "type": "t_mapping(t_address,t_struct(RevenueShare)31925_storage)", + "contract": "DistributorP1", + "src": "contracts/p1/Distributor.sol:18" + }, + { + "label": "rsr", + "offset": 0, + "slot": "204", + "type": "t_contract(IERC20)16483", + "contract": "DistributorP1", + "src": "contracts/p1/Distributor.sol:36" + }, + { + "label": "rToken", + "offset": 0, + "slot": "205", + "type": "t_contract(IERC20)16483", + "contract": "DistributorP1", + "src": "contracts/p1/Distributor.sol:37" + }, + { + "label": "furnace", + "offset": 0, + "slot": "206", + "type": "t_contract(IFurnace)32300", + "contract": "DistributorP1", + "src": "contracts/p1/Distributor.sol:38" + }, + { + "label": "stRSR", + "offset": 0, + "slot": "207", + "type": "t_contract(IStRSR)33299", + "contract": "DistributorP1", + "src": "contracts/p1/Distributor.sol:39" + }, + { + "label": "rTokenTrader", + "offset": 0, + "slot": "208", + "type": "t_address", + "contract": "DistributorP1", + "src": "contracts/p1/Distributor.sol:40" + }, + { + "label": "rsrTrader", + "offset": 0, + "slot": "209", + "type": "t_address", + "contract": "DistributorP1", + "src": "contracts/p1/Distributor.sol:41" + }, + { + "label": "__gap", + "offset": 0, + "slot": "210", + "type": "t_array(t_uint256)44_storage", + "contract": "DistributorP1", + "src": "contracts/p1/Distributor.sol:221" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_bytes32)dyn_storage": { + "label": "bytes32[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)44_storage": { + "label": "uint256[44]", + "numberOfBytes": "1408" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_contract(IERC20)16483": { + "label": "contract IERC20", + "numberOfBytes": "20" + }, + "t_contract(IFurnace)32300": { + "label": "contract IFurnace", + "numberOfBytes": "20" + }, + "t_contract(IMain)32744": { + "label": "contract IMain", + "numberOfBytes": "20" + }, + "t_contract(IStRSR)33299": { + "label": "contract IStRSR", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_struct(RevenueShare)31925_storage)": { + "label": "mapping(address => struct RevenueShare)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_struct(AddressSet)25226_storage": { + "label": "struct EnumerableSet.AddressSet", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)24911_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "64" + }, + "t_struct(RevenueShare)31925_storage": { + "label": "struct RevenueShare", + "members": [ + { + "label": "rTokenDist", + "type": "t_uint16", + "offset": 0, + "slot": "0" + }, + { + "label": "rsrDist", + "type": "t_uint16", + "offset": 2, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(Set)24911_storage": { + "label": "struct EnumerableSet.Set", + "members": [ + { + "label": "_values", + "type": "t_array(t_bytes32)dyn_storage", + "offset": 0, + "slot": "0" + }, + { + "label": "_indexes", + "type": "t_mapping(t_bytes32,t_uint256)", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } + }, + "f3b89b86d7a085af5b9ca363d5e9c7f8afdc97e72ba2840ad16f99aeb3cba1ad": { + "address": "0x845B8b0a1c6DB8318414d708Da25fA28d4a0dc81", + "txHash": "0x13bb5807f03b3bd20917a96e3efa348ca3e1d65fedcaef56a8fc017f11a4aab6", + "layout": { + "solcVersion": "0.8.19", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC1967UpgradeUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol:169" + }, + { + "label": "__gap", + "offset": 0, + "slot": "101", + "type": "t_array(t_uint256)50_storage", + "contract": "UUPSUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol:111" + }, + { + "label": "main", + "offset": 0, + "slot": "151", + "type": "t_contract(IMain)32744", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:21" + }, + { + "label": "__gap", + "offset": 0, + "slot": "152", + "type": "t_array(t_uint256)49_storage", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:69" + }, + { + "label": "rToken", + "offset": 0, + "slot": "201", + "type": "t_contract(IRToken)32962", + "contract": "FurnaceP1", + "src": "contracts/p1/Furnace.sol:17" + }, + { + "label": "ratio", + "offset": 0, + "slot": "202", + "type": "t_uint192", + "contract": "FurnaceP1", + "src": "contracts/p1/Furnace.sol:20" + }, + { + "label": "lastPayout", + "offset": 24, + "slot": "202", + "type": "t_uint48", + "contract": "FurnaceP1", + "src": "contracts/p1/Furnace.sol:23" + }, + { + "label": "lastPayoutBal", + "offset": 0, + "slot": "203", + "type": "t_uint256", + "contract": "FurnaceP1", + "src": "contracts/p1/Furnace.sol:24" + }, + { + "label": "__gap", + "offset": 0, + "slot": "204", + "type": "t_array(t_uint256)47_storage", + "contract": "FurnaceP1", + "src": "contracts/p1/Furnace.sol:97" + } + ], + "types": { + "t_array(t_uint256)47_storage": { + "label": "uint256[47]", + "numberOfBytes": "1504" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(IMain)32744": { + "label": "contract IMain", + "numberOfBytes": "20" + }, + "t_contract(IRToken)32962": { + "label": "contract IRToken", + "numberOfBytes": "20" + }, + "t_uint192": { + "label": "uint192", + "numberOfBytes": "24" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint48": { + "label": "uint48", + "numberOfBytes": "6" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } + }, + "80d51dee0982bc46becfd81417c9fe6bc95c4e550828a74d7f6a34e2c815cb58": { + "address": "0xc60a7Cd6fce24d0c3637A1dCBC8B0f9A9BFF6a7c", + "txHash": "0xb25791e42791b88557be95faa37265a89b32d2c898b054ac724e81eabd79f548", + "layout": { + "solcVersion": "0.8.19", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC1967UpgradeUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol:169" + }, + { + "label": "__gap", + "offset": 0, + "slot": "101", + "type": "t_array(t_uint256)50_storage", + "contract": "UUPSUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol:111" + }, + { + "label": "main", + "offset": 0, + "slot": "151", + "type": "t_contract(IMain)32744", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:21" + }, + { + "label": "__gap", + "offset": 0, + "slot": "152", + "type": "t_array(t_uint256)49_storage", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:69" + }, + { + "label": "_status", + "offset": 0, + "slot": "201", + "type": "t_uint256", + "contract": "ReentrancyGuardUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:38" + }, + { + "label": "__gap", + "offset": 0, + "slot": "202", + "type": "t_array(t_uint256)49_storage", + "contract": "ReentrancyGuardUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:88" + }, + { + "label": "broker", + "offset": 0, + "slot": "251", + "type": "t_contract(IBroker)31622", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:26" + }, + { + "label": "trades", + "offset": 0, + "slot": "252", + "type": "t_mapping(t_contract(IERC20)16483,t_contract(ITrade)33446)", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:29" + }, + { + "label": "tradesOpen", + "offset": 0, + "slot": "253", + "type": "t_uint48", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:30" + }, + { + "label": "maxTradeSlippage", + "offset": 6, + "slot": "253", + "type": "t_uint192", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:33" + }, + { + "label": "minTradeVolume", + "offset": 0, + "slot": "254", + "type": "t_uint192", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:34" + }, + { + "label": "tradesNonce", + "offset": 0, + "slot": "255", + "type": "t_uint256", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:37" + }, + { + "label": "__gap", + "offset": 0, + "slot": "256", + "type": "t_array(t_uint256)45_storage", + "contract": "TradingP1", + "src": "contracts/p1/mixins/Trading.sol:164" + }, + { + "label": "tokenToBuy", + "offset": 0, + "slot": "301", + "type": "t_contract(IERC20)16483", + "contract": "RevenueTraderP1", + "src": "contracts/p1/RevenueTrader.sol:19" + }, + { + "label": "assetRegistry", + "offset": 0, + "slot": "302", + "type": "t_contract(IAssetRegistry)31093", + "contract": "RevenueTraderP1", + "src": "contracts/p1/RevenueTrader.sol:20" + }, + { + "label": "distributor", + "offset": 0, + "slot": "303", + "type": "t_contract(IDistributor)31987", + "contract": "RevenueTraderP1", + "src": "contracts/p1/RevenueTrader.sol:21" + }, + { + "label": "backingManager", + "offset": 0, + "slot": "304", + "type": "t_contract(IBackingManager)31200", + "contract": "RevenueTraderP1", + "src": "contracts/p1/RevenueTrader.sol:22" + }, + { + "label": "furnace", + "offset": 0, + "slot": "305", + "type": "t_contract(IFurnace)32300", + "contract": "RevenueTraderP1", + "src": "contracts/p1/RevenueTrader.sol:23" + }, + { + "label": "rToken", + "offset": 0, + "slot": "306", + "type": "t_contract(IRToken)32962", + "contract": "RevenueTraderP1", + "src": "contracts/p1/RevenueTrader.sol:24" + }, + { + "label": "rsr", + "offset": 0, + "slot": "307", + "type": "t_contract(IERC20)16483", + "contract": "RevenueTraderP1", + "src": "contracts/p1/RevenueTrader.sol:25" + }, + { + "label": "__gap", + "offset": 0, + "slot": "308", + "type": "t_array(t_uint256)43_storage", + "contract": "RevenueTraderP1", + "src": "contracts/p1/RevenueTrader.sol:204" + } + ], + "types": { + "t_array(t_uint256)43_storage": { + "label": "uint256[43]", + "numberOfBytes": "1376" + }, + "t_array(t_uint256)45_storage": { + "label": "uint256[45]", + "numberOfBytes": "1440" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(IAssetRegistry)31093": { + "label": "contract IAssetRegistry", + "numberOfBytes": "20" + }, + "t_contract(IBackingManager)31200": { + "label": "contract IBackingManager", + "numberOfBytes": "20" + }, + "t_contract(IBroker)31622": { + "label": "contract IBroker", + "numberOfBytes": "20" + }, + "t_contract(IDistributor)31987": { + "label": "contract IDistributor", + "numberOfBytes": "20" + }, + "t_contract(IERC20)16483": { + "label": "contract IERC20", + "numberOfBytes": "20" + }, + "t_contract(IFurnace)32300": { + "label": "contract IFurnace", + "numberOfBytes": "20" + }, + "t_contract(IMain)32744": { + "label": "contract IMain", + "numberOfBytes": "20" + }, + "t_contract(IRToken)32962": { + "label": "contract IRToken", + "numberOfBytes": "20" + }, + "t_contract(ITrade)33446": { + "label": "contract ITrade", + "numberOfBytes": "20" + }, + "t_mapping(t_contract(IERC20)16483,t_contract(ITrade)33446)": { + "label": "mapping(contract IERC20 => contract ITrade)", + "numberOfBytes": "32" + }, + "t_uint192": { + "label": "uint192", + "numberOfBytes": "24" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint48": { + "label": "uint48", + "numberOfBytes": "6" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } + }, + "e5163e65dc1206da906aa4c21b9a5e763b011d2f5d15c9e15780f15f8fc3c011": { + "address": "0x784955641292b0014BC9eF82321300f0b6C7E36d", + "txHash": "0xe760a00d29baf4ee46c4fd2ca081618a9c6a632af7c95c67d1c352d214001d7a", + "layout": { + "solcVersion": "0.8.19", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC1967UpgradeUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol:169" + }, + { + "label": "__gap", + "offset": 0, + "slot": "101", + "type": "t_array(t_uint256)50_storage", + "contract": "UUPSUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol:111" + }, + { + "label": "main", + "offset": 0, + "slot": "151", + "type": "t_contract(IMain)14381", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:21" + }, + { + "label": "__gap", + "offset": 0, + "slot": "152", + "type": "t_array(t_uint256)49_storage", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:69" + }, + { + "label": "_balances", + "offset": 0, + "slot": "201", + "type": "t_mapping(t_address,t_uint256)", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:40" + }, + { + "label": "_allowances", + "offset": 0, + "slot": "202", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:42" + }, + { + "label": "_totalSupply", + "offset": 0, + "slot": "203", + "type": "t_uint256", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:44" + }, + { + "label": "_name", + "offset": 0, + "slot": "204", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:46" + }, + { + "label": "_symbol", + "offset": 0, + "slot": "205", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:47" + }, + { + "label": "__gap", + "offset": 0, + "slot": "206", + "type": "t_array(t_uint256)45_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:376" + }, + { + "label": "_hashedName", + "offset": 0, + "slot": "251", + "type": "t_bytes32", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol:40", + "renamedFrom": "_HASHED_NAME" + }, + { + "label": "_hashedVersion", + "offset": 0, + "slot": "252", + "type": "t_bytes32", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol:42", + "renamedFrom": "_HASHED_VERSION" + }, + { + "label": "_name", + "offset": 0, + "slot": "253", + "type": "t_string_storage", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol:44" + }, + { + "label": "_version", + "offset": 0, + "slot": "254", + "type": "t_string_storage", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol:45" + }, + { + "label": "__gap", + "offset": 0, + "slot": "255", + "type": "t_array(t_uint256)48_storage", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol:204" + }, + { + "label": "_nonces", + "offset": 0, + "slot": "303", + "type": "t_mapping(t_address,t_struct(Counter)2449_storage)", + "contract": "ERC20PermitUpgradeable", + "src": "contracts/vendor/ERC20PermitUpgradeable.sol:37" + }, + { + "label": "_PERMIT_TYPEHASH_DEPRECATED_SLOT", + "offset": 0, + "slot": "304", + "type": "t_bytes32", + "contract": "ERC20PermitUpgradeable", + "src": "contracts/vendor/ERC20PermitUpgradeable.sol:51", + "renamedFrom": "_PERMIT_TYPEHASH" + }, + { + "label": "__gap", + "offset": 0, + "slot": "305", + "type": "t_array(t_uint256)48_storage", + "contract": "ERC20PermitUpgradeable", + "src": "contracts/vendor/ERC20PermitUpgradeable.sol:129" + }, + { + "label": "mandate", + "offset": 0, + "slot": "353", + "type": "t_string_storage", + "contract": "RTokenP1", + "src": "contracts/p1/RToken.sol:44" + }, + { + "label": "assetRegistry", + "offset": 0, + "slot": "354", + "type": "t_contract(IAssetRegistry)13147", + "contract": "RTokenP1", + "src": "contracts/p1/RToken.sol:47" + }, + { + "label": "basketHandler", + "offset": 0, + "slot": "355", + "type": "t_contract(IBasketHandler)13521", + "contract": "RTokenP1", + "src": "contracts/p1/RToken.sol:48" + }, + { + "label": "backingManager", + "offset": 0, + "slot": "356", + "type": "t_contract(IBackingManager)13254", + "contract": "RTokenP1", + "src": "contracts/p1/RToken.sol:49" + }, + { + "label": "furnace", + "offset": 0, + "slot": "357", + "type": "t_contract(IFurnace)13937", + "contract": "RTokenP1", + "src": "contracts/p1/RToken.sol:50" + }, + { + "label": "basketsNeeded", + "offset": 0, + "slot": "358", + "type": "t_uint192", + "contract": "RTokenP1", + "src": "contracts/p1/RToken.sol:55" + }, + { + "label": "issuanceThrottle", + "offset": 0, + "slot": "359", + "type": "t_struct(Throttle)17605_storage", + "contract": "RTokenP1", + "src": "contracts/p1/RToken.sol:58" + }, + { + "label": "redemptionThrottle", + "offset": 0, + "slot": "363", + "type": "t_struct(Throttle)17605_storage", + "contract": "RTokenP1", + "src": "contracts/p1/RToken.sol:59" + }, + { + "label": "__gap", + "offset": 0, + "slot": "367", + "type": "t_array(t_uint256)42_storage", + "contract": "RTokenP1", + "src": "contracts/p1/RToken.sol:539" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_uint256)42_storage": { + "label": "uint256[42]", + "numberOfBytes": "1344" + }, + "t_array(t_uint256)45_storage": { + "label": "uint256[45]", + "numberOfBytes": "1440" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_contract(IAssetRegistry)13147": { + "label": "contract IAssetRegistry", + "numberOfBytes": "20" + }, + "t_contract(IBackingManager)13254": { + "label": "contract IBackingManager", + "numberOfBytes": "20" + }, + "t_contract(IBasketHandler)13521": { + "label": "contract IBasketHandler", + "numberOfBytes": "20" + }, + "t_contract(IFurnace)13937": { + "label": "contract IFurnace", + "numberOfBytes": "20" + }, + "t_contract(IMain)14381": { + "label": "contract IMain", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_mapping(t_address,t_uint256))": { + "label": "mapping(address => mapping(address => uint256))", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(Counter)2449_storage)": { + "label": "mapping(address => struct CountersUpgradeable.Counter)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(Counter)2449_storage": { + "label": "struct CountersUpgradeable.Counter", + "members": [ + { + "label": "_value", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(Params)17597_storage": { + "label": "struct ThrottleLib.Params", + "members": [ + { + "label": "amtRate", + "type": "t_uint256", + "offset": 0, + "slot": "0" + }, + { + "label": "pctRate", + "type": "t_uint192", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Throttle)17605_storage": { + "label": "struct ThrottleLib.Throttle", + "members": [ + { + "label": "params", + "type": "t_struct(Params)17597_storage", + "offset": 0, + "slot": "0" + }, + { + "label": "lastTimestamp", + "type": "t_uint48", + "offset": 0, + "slot": "2" + }, + { + "label": "lastAvailable", + "type": "t_uint256", + "offset": 0, + "slot": "3" + } + ], + "numberOfBytes": "128" + }, + "t_uint192": { + "label": "uint192", + "numberOfBytes": "24" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint48": { + "label": "uint48", + "numberOfBytes": "6" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } + }, + "45d0e7dbbbcc04b6b1815cbc2791be5136c957c2c8ec0ba5bcb55adb44b812ef": { + "address": "0xE433673648c94FEC0706E5AC95d4f4097f58B5fb", + "txHash": "0x1fa44a3042b46d9622c2e8a53792575ef312497d14ce749313f51d80ed83cf5c", + "layout": { + "solcVersion": "0.8.19", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC1967UpgradeUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol:169" + }, + { + "label": "__gap", + "offset": 0, + "slot": "101", + "type": "t_array(t_uint256)50_storage", + "contract": "UUPSUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol:111" + }, + { + "label": "main", + "offset": 0, + "slot": "151", + "type": "t_contract(IMain)14381", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:21" + }, + { + "label": "__gap", + "offset": 0, + "slot": "152", + "type": "t_array(t_uint256)49_storage", + "contract": "ComponentP1", + "src": "contracts/p1/mixins/Component.sol:69" + }, + { + "label": "_hashedName", + "offset": 0, + "slot": "201", + "type": "t_bytes32", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol:40", + "renamedFrom": "_HASHED_NAME" + }, + { + "label": "_hashedVersion", + "offset": 0, + "slot": "202", + "type": "t_bytes32", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol:42", + "renamedFrom": "_HASHED_VERSION" + }, + { + "label": "_name", + "offset": 0, + "slot": "203", + "type": "t_string_storage", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol:44" + }, + { + "label": "_version", + "offset": 0, + "slot": "204", + "type": "t_string_storage", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol:45" + }, + { + "label": "__gap", + "offset": 0, + "slot": "205", + "type": "t_array(t_uint256)48_storage", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol:204" + }, + { + "label": "name", + "offset": 0, + "slot": "253", + "type": "t_string_storage", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:45" + }, + { + "label": "symbol", + "offset": 0, + "slot": "254", + "type": "t_string_storage", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:46" + }, + { + "label": "assetRegistry", + "offset": 0, + "slot": "255", + "type": "t_contract(IAssetRegistry)13147", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:51" + }, + { + "label": "backingManager", + "offset": 0, + "slot": "256", + "type": "t_contract(IBackingManager)13254", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:52" + }, + { + "label": "basketHandler", + "offset": 0, + "slot": "257", + "type": "t_contract(IBasketHandler)13521", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:53" + }, + { + "label": "rsr", + "offset": 0, + "slot": "258", + "type": "t_contract(IERC20)6312", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:54" + }, + { + "label": "era", + "offset": 0, + "slot": "259", + "type": "t_uint256", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:59" + }, + { + "label": "stakes", + "offset": 0, + "slot": "260", + "type": "t_mapping(t_uint256,t_mapping(t_address,t_uint256))", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:63" + }, + { + "label": "totalStakes", + "offset": 0, + "slot": "261", + "type": "t_uint256", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:64" + }, + { + "label": "stakeRSR", + "offset": 0, + "slot": "262", + "type": "t_uint256", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:65" + }, + { + "label": "stakeRate", + "offset": 0, + "slot": "263", + "type": "t_uint192", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:66" + }, + { + "label": "_allowances", + "offset": 0, + "slot": "264", + "type": "t_mapping(t_uint256,t_mapping(t_address,t_mapping(t_address,t_uint256)))", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:71" + }, + { + "label": "draftEra", + "offset": 0, + "slot": "265", + "type": "t_uint256", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:76" + }, + { + "label": "draftQueues", + "offset": 0, + "slot": "266", + "type": "t_mapping(t_uint256,t_mapping(t_address,t_array(t_struct(CumulativeDraft)21316_storage)dyn_storage))", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:84" + }, + { + "label": "firstRemainingDraft", + "offset": 0, + "slot": "267", + "type": "t_mapping(t_uint256,t_mapping(t_address,t_uint256))", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:85" + }, + { + "label": "totalDrafts", + "offset": 0, + "slot": "268", + "type": "t_uint256", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:86" + }, + { + "label": "draftRSR", + "offset": 0, + "slot": "269", + "type": "t_uint256", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:87" + }, + { + "label": "draftRate", + "offset": 0, + "slot": "270", + "type": "t_uint192", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:88" + }, + { + "label": "_nonces", + "offset": 0, + "slot": "271", + "type": "t_mapping(t_address,t_struct(Counter)2449_storage)", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:126" + }, + { + "label": "_delegationNonces", + "offset": 0, + "slot": "272", + "type": "t_mapping(t_address,t_struct(Counter)2449_storage)", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:128" + }, + { + "label": "unstakingDelay", + "offset": 0, + "slot": "273", + "type": "t_uint48", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:138" + }, + { + "label": "rewardRatio", + "offset": 6, + "slot": "273", + "type": "t_uint192", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:139" + }, + { + "label": "payoutLastPaid", + "offset": 0, + "slot": "274", + "type": "t_uint48", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:150" + }, + { + "label": "rsrRewardsAtLastPayout", + "offset": 0, + "slot": "275", + "type": "t_uint256", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:153" + }, + { + "label": "leaked", + "offset": 0, + "slot": "276", + "type": "t_uint192", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:159" + }, + { + "label": "lastWithdrawRefresh", + "offset": 24, + "slot": "276", + "type": "t_uint48", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:160" + }, + { + "label": "withdrawalLeak", + "offset": 0, + "slot": "277", + "type": "t_uint192", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:161" + }, + { + "label": "__gap", + "offset": 0, + "slot": "278", + "type": "t_array(t_uint256)28_storage", + "contract": "StRSRP1", + "src": "contracts/p1/StRSR.sol:999" + }, + { + "label": "_delegates", + "offset": 0, + "slot": "306", + "type": "t_mapping(t_address,t_address)", + "contract": "StRSRP1Votes", + "src": "contracts/p1/StRSRVotes.sol:34" + }, + { + "label": "_eras", + "offset": 0, + "slot": "307", + "type": "t_array(t_struct(Checkpoint)23525_storage)dyn_storage", + "contract": "StRSRP1Votes", + "src": "contracts/p1/StRSRVotes.sol:37" + }, + { + "label": "_checkpoints", + "offset": 0, + "slot": "308", + "type": "t_mapping(t_uint256,t_mapping(t_address,t_array(t_struct(Checkpoint)23525_storage)dyn_storage))", + "contract": "StRSRP1Votes", + "src": "contracts/p1/StRSRVotes.sol:41" + }, + { + "label": "_totalSupplyCheckpoints", + "offset": 0, + "slot": "309", + "type": "t_mapping(t_uint256,t_array(t_struct(Checkpoint)23525_storage)dyn_storage)", + "contract": "StRSRP1Votes", + "src": "contracts/p1/StRSRVotes.sol:43" + }, + { + "label": "__gap", + "offset": 0, + "slot": "310", + "type": "t_array(t_uint256)46_storage", + "contract": "StRSRP1Votes", + "src": "contracts/p1/StRSRVotes.sol:300" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)23525_storage)dyn_storage": { + "label": "struct StRSRP1Votes.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_struct(CumulativeDraft)21316_storage)dyn_storage": { + "label": "struct StRSRP1.CumulativeDraft[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)28_storage": { + "label": "uint256[28]", + "numberOfBytes": "896" + }, + "t_array(t_uint256)46_storage": { + "label": "uint256[46]", + "numberOfBytes": "1472" + }, + "t_array(t_uint256)48_storage": { + "label": "uint256[48]", + "numberOfBytes": "1536" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_contract(IAssetRegistry)13147": { + "label": "contract IAssetRegistry", + "numberOfBytes": "20" + }, + "t_contract(IBackingManager)13254": { + "label": "contract IBackingManager", + "numberOfBytes": "20" + }, + "t_contract(IBasketHandler)13521": { + "label": "contract IBasketHandler", + "numberOfBytes": "20" + }, + "t_contract(IERC20)6312": { + "label": "contract IERC20", + "numberOfBytes": "20" + }, + "t_contract(IMain)14381": { + "label": "contract IMain", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_address)": { + "label": "mapping(address => address)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_array(t_struct(Checkpoint)23525_storage)dyn_storage)": { + "label": "mapping(address => struct StRSRP1Votes.Checkpoint[])", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_array(t_struct(CumulativeDraft)21316_storage)dyn_storage)": { + "label": "mapping(address => struct StRSRP1.CumulativeDraft[])", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_mapping(t_address,t_uint256))": { + "label": "mapping(address => mapping(address => uint256))", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(Counter)2449_storage)": { + "label": "mapping(address => struct CountersUpgradeable.Counter)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_array(t_struct(Checkpoint)23525_storage)dyn_storage)": { + "label": "mapping(uint256 => struct StRSRP1Votes.Checkpoint[])", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_mapping(t_address,t_array(t_struct(Checkpoint)23525_storage)dyn_storage))": { + "label": "mapping(uint256 => mapping(address => struct StRSRP1Votes.Checkpoint[]))", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_mapping(t_address,t_array(t_struct(CumulativeDraft)21316_storage)dyn_storage))": { + "label": "mapping(uint256 => mapping(address => struct StRSRP1.CumulativeDraft[]))", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_mapping(t_address,t_mapping(t_address,t_uint256)))": { + "label": "mapping(uint256 => mapping(address => mapping(address => uint256)))", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_mapping(t_address,t_uint256))": { + "label": "mapping(uint256 => mapping(address => uint256))", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)23525_storage": { + "label": "struct StRSRP1Votes.Checkpoint", + "members": [ + { + "label": "fromTimepoint", + "type": "t_uint48", + "offset": 0, + "slot": "0" + }, + { + "label": "val", + "type": "t_uint224", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Counter)2449_storage": { + "label": "struct CountersUpgradeable.Counter", + "members": [ + { + "label": "_value", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(CumulativeDraft)21316_storage": { + "label": "struct StRSRP1.CumulativeDraft", + "members": [ + { + "label": "drafts", + "type": "t_uint176", + "offset": 0, + "slot": "0" + }, + { + "label": "availableAt", + "type": "t_uint64", + "offset": 22, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint176": { + "label": "uint176", + "numberOfBytes": "22" + }, + "t_uint192": { + "label": "uint192", + "numberOfBytes": "24" + }, + "t_uint224": { + "label": "uint224", + "numberOfBytes": "28" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint48": { + "label": "uint48", + "numberOfBytes": "6" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } } } } diff --git a/common/blockchain-utils.ts b/common/blockchain-utils.ts index 0b426b568c..bf34e006b4 100644 --- a/common/blockchain-utils.ts +++ b/common/blockchain-utils.ts @@ -1,8 +1,9 @@ +import { useEnv } from '#/utils/env' import { BigNumber } from 'ethers' import { HardhatRuntimeEnvironment } from 'hardhat/types' // getChainId: Returns current chain Id -export const getChainId = async (hre: HardhatRuntimeEnvironment) => { +export const getChainId = async (hre: HardhatRuntimeEnvironment): Promise => { let _chainId try { _chainId = await hre.network.provider.send('eth_chainId') @@ -17,6 +18,20 @@ export const getChainId = async (hre: HardhatRuntimeEnvironment) => { if (_chainId.startsWith('0x')) { _chainId = BigNumber.from(_chainId).toString() } + + if (useEnv('FORK') && _chainId === '31337') { + switch (useEnv('FORK_NETWORK').toLowerCase()) { + case 'mainnet': + _chainId = '1' + break; + case 'base': + _chainId = '8453' + break; + case 'arbitrum': + _chainId = '42161' + break; + } + } return _chainId } diff --git a/common/configuration.ts b/common/configuration.ts index d52398b321..a314f24af4 100644 --- a/common/configuration.ts +++ b/common/configuration.ts @@ -57,6 +57,8 @@ export interface ITokens { RSR?: string CRV?: string CVX?: string + SDT?: string + USDCPLUS?: string ETHPLUS?: string ankrETH?: string frxETH?: string @@ -65,6 +67,7 @@ export interface ITokens { wstETH?: string rETH?: string cUSDCv3?: string + wcUSDCv3?: string cUSDbCv3?: string ONDO?: string sFRAX?: string @@ -103,6 +106,8 @@ export interface ITokens { Re7WETH?: string } +export type ITokensKeys = Array; + export interface IFeeds { stETHETH?: string stETHUSD?: string @@ -125,11 +130,12 @@ export interface IPools { crveUSDFRAXBP?: string crvTriCrypto?: string crvMIM3Pool?: string + sdUSDCUSDCPlus?: string } interface INetworkConfig { name: string - tokens: ITokens + tokens: ITokens & IPools chainlinkFeeds: ITokens & ICurrencies & IFeeds AAVE_LENDING_POOL?: string AAVE_INCENTIVES?: string @@ -202,6 +208,8 @@ export const networkConfig: { [key: string]: INetworkConfig } = { RSR: '0x320623b8E4fF03373931769A31Fc52A4E78B5d70', CRV: '0xD533a949740bb3306d119CC777fa900bA034cd52', CVX: '0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B', + SDT: '0x73968b9a57c6E53d41345FD57a6E6ae27d6CDB2F', + USDCPLUS: '0xFc0B1EEf20e4c68B3DCF36c4537Cfa7Ce46CA70b', ETHPLUS: '0xE72B141DF173b999AE7c1aDcbF60Cc9833Ce56a8', ankrETH: '0xE95A203B1a91a908F9B9CE46459d101078c2c3cb', frxETH: '0x5E8422345238F34275888049021821E8E08CAa1f', @@ -210,6 +218,7 @@ export const networkConfig: { [key: string]: INetworkConfig } = { wstETH: '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0', rETH: '0xae78736Cd615f374D3085123A210448E74Fc6393', cUSDCv3: '0xc3d688B66703497DAA19211EEdff47f25384cdc3', + wcUSDCv3: '0xfBD1a538f5707C0D67a16ca4e3Fc711B80BD931A', ONDO: '0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3', sFRAX: '0xA663B02CF0a4b149d2aD41910CB81e23e1c41c32', sDAI: '0x83f20f44975d03b1b09e64809b757c47f942beea', @@ -231,6 +240,7 @@ export const networkConfig: { [key: string]: INetworkConfig } = { steakPYUSD: '0xbEEF02e5E13584ab96848af90261f0C8Ee04722a', bbUSDT: '0x2C25f6C25770fFEC5959D34B94Bf898865e5D6b1', Re7WETH: '0x78Fc2c2eD1A4cDb5402365934aE5648aDAd094d0', + sdUSDCUSDCPlus: '0x9bbF31E99F30c38a5003952206C31EEa77540BeF', }, chainlinkFeeds: { RSR: '0x759bBC1be8F90eE6457C44abc7d443842a976d02', @@ -327,6 +337,7 @@ export const networkConfig: { [key: string]: INetworkConfig } = { wstETH: '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0', rETH: '0xae78736Cd615f374D3085123A210448E74Fc6393', cUSDCv3: '0xc3d688B66703497DAA19211EEdff47f25384cdc3', + wcUSDCv3: '0xfBD1a538f5707C0D67a16ca4e3Fc711B80BD931A', ONDO: '0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3', sDAI: '0x83f20f44975d03b1b09e64809b757c47f942beea', cbETH: '0xBe9895146f7AF43049ca1c1AE358B0541Ea49704', @@ -477,6 +488,7 @@ export const networkConfig: { [key: string]: INetworkConfig } = { cbETH: '0x2ae3f1ec7f1f5012cfeab0185bfc7aa3cf0dec22', cUSDbCv3: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf', cUSDCv3: '0xb125E6687d4313864e53df431d5425969c15Eb2F', + wcUSDCv3: '0xA694f7177C6c839C951C74C797283B35D0A486c8', aBasUSDC: '0x4e65fE4DbA92790696d040ac24Aa414708F5c0AB', saBasUSDC: '0x184460704886f9F2A7F3A0c2887680867954dC6E', // our wrapper aWETHv3: '0xD4a0e0b9149BCee3C920d2E00b5dE09138fd8bb7', @@ -674,6 +686,8 @@ export const MIN_THROTTLE_AMT_RATE = BigNumber.from(10).pow(18) export const MAX_THROTTLE_AMT_RATE = BigNumber.from(10).pow(48) export const MAX_THROTTLE_PCT_RATE = BigNumber.from(10).pow(18) export const GNOSIS_MAX_TOKENS = BigNumber.from(7).mul(BigNumber.from(10).pow(28)) +export const MAX_BASKET_SIZE = 100 +export const MAX_BACKUP_SIZE = 64 // Timestamps export const MAX_ORACLE_TIMEOUT = BigNumber.from(2).pow(48).sub(1).sub(300) diff --git a/contracts/facade/facets/ActFacet.sol b/contracts/facade/facets/ActFacet.sol index bbcf1cfec9..7294859c2e 100644 --- a/contracts/facade/facets/ActFacet.sol +++ b/contracts/facade/facets/ActFacet.sol @@ -6,7 +6,6 @@ import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/utils/Multicall.sol"; import "../../plugins/trading/DutchTrade.sol"; import "../../plugins/trading/GnosisTrade.sol"; -import "../../interfaces/IActFacet.sol"; import "../../interfaces/IBackingManager.sol"; /** @@ -17,7 +16,7 @@ import "../../interfaces/IBackingManager.sol"; * @custom:static-call - Use ethers callStatic() to get result after update; do not execute */ // slither-disable-start -contract ActFacet is IActFacet, Multicall { +contract ActFacet is Multicall { using Address for address; using SafeERC20 for IERC20; using FixLib for uint192; diff --git a/contracts/facade/facets/ReadFacet.sol b/contracts/facade/facets/ReadFacet.sol index 9a2501203e..a4083a4b94 100644 --- a/contracts/facade/facets/ReadFacet.sol +++ b/contracts/facade/facets/ReadFacet.sol @@ -5,7 +5,6 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../../plugins/trading/DutchTrade.sol"; import "../../interfaces/IAsset.sol"; import "../../interfaces/IAssetRegistry.sol"; -import "../../interfaces/IReadFacet.sol"; import "../../interfaces/IRToken.sol"; import "../../interfaces/IStRSR.sol"; import "../../libraries/Fixed.sol"; @@ -22,7 +21,7 @@ import "./MaxIssuableFacet.sol"; * @custom:static-call - Use ethers callStatic() to get result after update; do not execute */ // slither-disable-start -contract ReadFacet is MaxIssuableFacet { +contract ReadFacet { using FixLib for uint192; // === Static Calls === @@ -247,6 +246,12 @@ contract ReadFacet is MaxIssuableFacet { // === Views === + struct Pending { + uint256 index; + uint256 availableAt; + uint256 amount; + } + /// @param draftEra {draftEra} The draft era to query unstakings for /// @param account The account for the query /// @return unstakings {qRSR} All the pending StRSR unstakings for an account, in RSR @@ -254,7 +259,7 @@ contract ReadFacet is MaxIssuableFacet { RTokenP1 rToken, uint256 draftEra, address account - ) external view returns (IReadFacet.Pending[] memory unstakings) { + ) external view returns (Pending[] memory unstakings) { StRSRP1 stRSR = StRSRP1(address(rToken.main().stRSR())); uint256 left = stRSR.firstRemainingDraft(draftEra, account); uint256 right = stRSR.draftQueueLen(draftEra, account); @@ -271,7 +276,7 @@ contract ReadFacet is MaxIssuableFacet { } // {qRSR} = {qDrafts} / {qDrafts/qRSR} - unstakings[i] = IReadFacet.Pending(i + left, availableAt, diff.div(draftRate)); + unstakings[i] = Pending(i + left, availableAt, diff.div(draftRate)); } } diff --git a/contracts/interfaces/IFacade.sol b/contracts/interfaces/IFacade.sol index afd227acd3..e1d846884f 100644 --- a/contracts/interfaces/IFacade.sol +++ b/contracts/interfaces/IFacade.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: BlueOak-1.0.0 pragma solidity 0.8.19; -import "./IActFacet.sol"; -import "./IReadFacet.sol"; +import "../facade/facets/ActFacet.sol"; +import "../facade/facets/ReadFacet.sol"; +import "../facade/facets/MaxIssuableFacet.sol"; interface IFacade { event SelectorSaved(address indexed facet, bytes4 indexed selector); @@ -14,6 +15,6 @@ interface IFacade { } // solhint-disable-next-line no-empty-blocks -interface TestIFacade is IFacade, IActFacet, IReadFacet { +abstract contract TestIFacade is IFacade, ActFacet, MaxIssuableFacet, ReadFacet { } diff --git a/contracts/p1/StRSR.sol b/contracts/p1/StRSR.sol index ab04f46d18..62d9d899f6 100644 --- a/contracts/p1/StRSR.sol +++ b/contracts/p1/StRSR.sol @@ -16,7 +16,7 @@ import "./mixins/Component.sol"; // solhint-disable max-states-count -/* +/** * @title StRSRP1 * @notice StRSR is an ERC20 token contract that allows people to stake their RSR as * over-collateralization behind an RToken. As compensation stakers receive a share of revenues diff --git a/contracts/plugins/assets/curve/CurveAppreciatingRTokenFiatCollateral.sol b/contracts/plugins/assets/curve/CurveAppreciatingRTokenFiatCollateral.sol index 88a50019ca..a4ce5e60d2 100644 --- a/contracts/plugins/assets/curve/CurveAppreciatingRTokenFiatCollateral.sol +++ b/contracts/plugins/assets/curve/CurveAppreciatingRTokenFiatCollateral.sol @@ -89,9 +89,7 @@ contract CurveAppreciatingRTokenFiatCollateral is CurveStableCollateral { // Check RToken status try pairedBasketHandler.isReady() returns (bool isReady) { - if (!isReady) { - markStatus(CollateralStatus.IFFY); - } else if (low == 0 || _anyDepeggedInPool() || _anyDepeggedOutsidePool()) { + if (!isReady || low == 0 || _anyDepeggedInPool() || _anyDepeggedOutsidePool()) { // If the price is below the default-threshold price, default eventually // uint192(+/-) is the same as Fix.plus/minus markStatus(CollateralStatus.IFFY); diff --git a/contracts/plugins/assets/curve/CurveRecursiveCollateral.sol b/contracts/plugins/assets/curve/CurveRecursiveCollateral.sol new file mode 100644 index 0000000000..d07190c57a --- /dev/null +++ b/contracts/plugins/assets/curve/CurveRecursiveCollateral.sol @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: BlueOak-1.0.0 +pragma solidity 0.8.19; + +import "@openzeppelin/contracts/utils/math/Math.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; +import "../../../interfaces/IRToken.sol"; +import "../../../libraries/Fixed.sol"; +import "../curve/CurveStableCollateral.sol"; +import "../OracleLib.sol"; + +/** + * @title CurveRecursiveCollateral + * @notice Collateral plugin for a CurveLP token for a pool between a + * a USD reference token and a USD RToken. + * + * Note: + * - The RToken _must_ be the same RToken using this plugin as collateral! + * - The RToken SHOULD have an RSR overcollateralization layer. DO NOT USE WITHOUT RSR! + * - The LP token should be worth ~2x the reference token. Do not use with 1x lpTokens. + * + * tok = ConvexStakingWrapper or CurveGaugeWrapper + * ref = coins(0) in the pool + * tar = USD + * UoA = USD + */ +contract CurveRecursiveCollateral is CurveStableCollateral { + using OracleLib for AggregatorV3Interface; + using FixLib for uint192; + + IRToken internal immutable rToken; // token1 + + /// @param config.erc20 must be of type ConvexStakingWrapper or CurveGaugeWrapper + /// @param config.chainlinkFeed Feed units: {UoA/ref} + constructor( + CollateralConfig memory config, + uint192 revenueHiding, + PTConfiguration memory ptConfig + ) CurveStableCollateral(config, revenueHiding, ptConfig) { + rToken = IRToken(address(token1)); + + // {ref/tok} LP token's virtual price + exposedReferencePrice = _safeWrap(curvePool.get_virtual_price()).mul(revenueShowing); + } + + /// Can revert, used by other contract functions in order to catch errors + /// Should not return FIX_MAX for low + /// Should only return FIX_MAX for high if low is 0 + /// @return low {UoA/tok} The low price estimate + /// @return high {UoA/tok} The high price estimate + /// @return {target/ref} Unused. Always 0 + function tryPrice() + external + view + virtual + override + returns ( + uint192 low, + uint192 high, + uint192 + ) + { + // This pricing method is MEV-resistant, but only gives a lower-bound + // for the value of the LP token collateral. It could be that the pool is + // very imbalanced, in which case the LP token could be worth more than this + // method says it is. + + // Get reference token price + (uint192 refLow, uint192 refHigh) = this.tokenPrice(0); // reference token + + // Multiply by the underlyingRefPerTok() + uint192 rate = underlyingRefPerTok(); + low = refLow.mul(rate, FLOOR); + high = refHigh.mul(rate, CEIL); + + assert(low <= high); // not obviously true by inspection + return (low, high, 0); + } + + /// Should not revert + /// Refresh exchange rates and update default status. + /// Have to override to add custom default checks + function refresh() public virtual override { + CollateralStatus oldStatus = status(); + + try this.underlyingRefPerTok() returns (uint192) { + // Instead of ensuring the underlyingRefPerTok is up-only, solely check + // that the pool's virtual price is up-only. Otherwise this collateral + // would create default cascades. + + // {ref/tok} + uint192 virtualPrice = _safeWrap(curvePool.get_virtual_price()); + + // {ref/tok} = {ref/tok} * {1} + uint192 hiddenReferencePrice = virtualPrice.mul(revenueShowing); + + // uint192(<) is equivalent to Fix.lt + if (virtualPrice < exposedReferencePrice) { + exposedReferencePrice = virtualPrice; + markStatus(CollateralStatus.DISABLED); + } else if (hiddenReferencePrice > exposedReferencePrice) { + exposedReferencePrice = hiddenReferencePrice; + } + + // Check for soft default + save prices + try this.tryPrice() returns (uint192 low, uint192 high, uint192) { + // {UoA/tok}, {UoA/tok}, {UoA/tok} + // (0, 0) is a valid price; (0, FIX_MAX) is unpriced + + // Save prices if priced + if (high < FIX_MAX) { + savedLowPrice = low; + savedHighPrice = high; + lastSave = uint48(block.timestamp); + } else { + // must be unpriced + // untested: + // validated in other plugins, cost to test here is high + assert(low == 0); + } + + // If the price is below the default-threshold price, default eventually + // uint192(+/-) is the same as Fix.plus/minus + if (low == 0 || _anyDepeggedInPool() || _anyDepeggedOutsidePool()) { + markStatus(CollateralStatus.IFFY); + } else { + markStatus(CollateralStatus.SOUND); + } + } catch (bytes memory errData) { + // see: docs/solidity-style.md#Catching-Empty-Data + if (errData.length == 0) revert(); // solhint-disable-line reason-string + markStatus(CollateralStatus.IFFY); + } + } catch (bytes memory errData) { + // see: docs/solidity-style.md#Catching-Empty-Data + if (errData.length == 0) revert(); // solhint-disable-line reason-string + markStatus(CollateralStatus.DISABLED); + } + + CollateralStatus newStatus = status(); + if (oldStatus != newStatus) { + emit CollateralStatusChanged(oldStatus, newStatus); + } + } + + /// @dev Not up-only! The RToken can devalue its exchange rate peg + /// @return {ref/tok} Quantity of whole reference units per whole collateral tokens + function underlyingRefPerTok() public view virtual override returns (uint192) { + // {ref/tok} = quantity of the reference unit token in the pool per vault token + // the vault is 1:1 with the LP token + + // {lpToken@t=0/lpToken} + uint192 virtualPrice = _safeWrap(curvePool.get_virtual_price()); + // this is missing the fact that USDC+ has also appreciated in this time + + // {BU/rTok} + uint192 rTokenRate = divuu(rToken.basketsNeeded(), rToken.totalSupply()); + // not worth the gas to protect against div-by-zero + + // The rTokenRate is not up-only! We should expect decreases when other + // collateral default and there is not enough RSR stake to cover the hole. + + // {ref/tok} = {ref/lpToken} = {lpToken@t=0/lpToken} * {1} * 2{ref/lpToken@t=0} + return virtualPrice.mul(rTokenRate.sqrt()).mulu(2); // LP token worth twice as much + } + + // === Internal === + + // Override this later to implement non-standard recursive pools + function _anyDepeggedInPool() internal view virtual override returns (bool) { + // Assumption: token0 is the reference token; token1 is the RToken + + // Check reference token + try this.tokenPrice(0) returns (uint192 low, uint192 high) { + // {UoA/tok} = {UoA/tok} + {UoA/tok} + uint192 mid = (low + high) / 2; + + // If the price is below the default-threshold price, default eventually + // uint192(+/-) is the same as Fix.plus/minus + if (mid < pegBottom || mid > pegTop) return true; + } catch (bytes memory errData) { + // see: docs/solidity-style.md#Catching-Empty-Data + // untested: + // pattern validated in other plugins, cost to test is high + if (errData.length == 0) revert(); // solhint-disable-line reason-string + return true; + } + + // Ignore the status of the RToken to prevent circularity + + return false; + } +} diff --git a/contracts/plugins/assets/curve/stakedao/IStakeDAO.sol b/contracts/plugins/assets/curve/stakedao/IStakeDAO.sol new file mode 100644 index 0000000000..b53ed0dcd4 --- /dev/null +++ b/contracts/plugins/assets/curve/stakedao/IStakeDAO.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: BlueOak-1.0.0 +pragma solidity 0.8.19; + +import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; + +interface IStakeDAOGauge is IERC20Metadata { + function deposit(uint256 amount) external; + + function claimer() external view returns (IStakeDAOClaimer); + + // solhint-disable-next-line func-name-mixedcase + function reward_count() external view returns (uint256); + + // solhint-disable-next-line func-name-mixedcase + function reward_tokens(uint256 index) external view returns (IERC20Metadata); +} + +interface IStakeDAOClaimer { + function claimRewards(address[] memory gauges, bool claimVeSDT) external; +} diff --git a/contracts/plugins/assets/curve/stakedao/StakeDAORecursiveCollateral.sol b/contracts/plugins/assets/curve/stakedao/StakeDAORecursiveCollateral.sol new file mode 100644 index 0000000000..69bc291bbc --- /dev/null +++ b/contracts/plugins/assets/curve/stakedao/StakeDAORecursiveCollateral.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: BlueOak-1.0.0 +pragma solidity 0.8.19; + +import "../CurveRecursiveCollateral.sol"; +import "./IStakeDAO.sol"; + +/** + * @title StakeDAORecursiveCollateral + * @notice Collateral plugin for a StakeDAO sdUSDC+LP-f-gauge corresponding + * to a Curve pool with a reference token and an RToken. The RToken must + * be strictly up-only with respect to the reference token. + * + * tok = sdUSDC+LP-f-gauge + * ref = USDC + * tar = USD + * UoA = USD + */ +contract StakeDAORecursiveCollateral is CurveRecursiveCollateral { + using OracleLib for AggregatorV3Interface; + using FixLib for uint192; + + IStakeDAOGauge internal immutable gauge; // typed erc20 variable + IStakeDAOClaimer internal immutable claimer; + + /// @param config.erc20 must be of type IStakeDAOGauge + /// @param config.chainlinkFeed Feed units: {UoA/ref} + constructor( + CollateralConfig memory config, + uint192 revenueHiding, + PTConfiguration memory ptConfig + ) CurveRecursiveCollateral(config, revenueHiding, ptConfig) { + gauge = IStakeDAOGauge(address(config.erc20)); + claimer = gauge.claimer(); + } + + /// @custom:delegate-call + function claimRewards() external override { + uint256 count = gauge.reward_count(); + + // Save initial bals + IERC20Metadata[] memory rewardTokens = new IERC20Metadata[](count); + uint256[] memory bals = new uint256[](count); + for (uint256 i = 0; i < count; i++) { + rewardTokens[i] = gauge.reward_tokens(i); + bals[i] = rewardTokens[i].balanceOf(address(this)); + } + + // Do actual claim + address[] memory gauges = new address[](1); + gauges[0] = address(gauge); + claimer.claimRewards(gauges, false); + + // Emit balance changes + for (uint256 i = 0; i < rewardTokens.length; i++) { + IERC20Metadata rewardToken = rewardTokens[i]; + emit RewardsClaimed(rewardToken, rewardToken.balanceOf(address(this)) - bals[i]); + } + } +} diff --git a/contracts/plugins/assets/morpho-aave/MorphoFiatCollateral.sol b/contracts/plugins/assets/morpho-aave/MorphoFiatCollateral.sol index 1d8cf4b077..b3429791e7 100644 --- a/contracts/plugins/assets/morpho-aave/MorphoFiatCollateral.sol +++ b/contracts/plugins/assets/morpho-aave/MorphoFiatCollateral.sol @@ -18,7 +18,7 @@ import { shiftl_toFix, FIX_ONE } from "../../../libraries/Fixed.sol"; contract MorphoFiatCollateral is AppreciatingFiatCollateral { using OracleLib for AggregatorV3Interface; - IERC20Metadata private immutable morpho; + IERC20Metadata private immutable morpho; // MORPHO token uint256 private immutable oneShare; int8 private immutable refDecimals; diff --git a/contracts/plugins/assets/morpho-aave/MorphoSelfReferentialCollateral.sol b/contracts/plugins/assets/morpho-aave/MorphoSelfReferentialCollateral.sol index d839931ee2..2c61150119 100644 --- a/contracts/plugins/assets/morpho-aave/MorphoSelfReferentialCollateral.sol +++ b/contracts/plugins/assets/morpho-aave/MorphoSelfReferentialCollateral.sol @@ -1,14 +1,15 @@ // SPDX-License-Identifier: BlueOak-1.0.0 pragma solidity 0.8.19; -// solhint-disable-next-line max-line-length +// solhint-disable max-line-length import { AggregatorV3Interface } from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; -import { AppreciatingFiatCollateral, CollateralConfig } from "../AppreciatingFiatCollateral.sol"; +import { Asset, AppreciatingFiatCollateral, CollateralConfig, IRewardable } from "../AppreciatingFiatCollateral.sol"; import { MorphoTokenisedDeposit } from "./MorphoTokenisedDeposit.sol"; import { OracleLib } from "../OracleLib.sol"; -// solhint-disable-next-line max-line-length import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import { shiftl_toFix, FIX_ONE, FixLib, CEIL } from "../../../libraries/Fixed.sol"; +// solhint-enable max-line-length + /** * @title MorphoSelfReferentialCollateral * @notice Collateral plugin for a Morpho pool with self referential collateral, like WETH @@ -19,6 +20,7 @@ contract MorphoSelfReferentialCollateral is AppreciatingFiatCollateral { using FixLib for uint192; MorphoTokenisedDeposit public immutable vault; + IERC20Metadata private immutable morpho; // MORPHO token uint256 private immutable oneShare; int8 private immutable refDecimals; @@ -31,6 +33,7 @@ contract MorphoSelfReferentialCollateral is AppreciatingFiatCollateral { require(config.defaultThreshold == 0, "default threshold not supported"); require(address(config.erc20) != address(0), "missing erc20"); vault = MorphoTokenisedDeposit(address(config.erc20)); + morpho = IERC20Metadata(address(vault.rewardToken())); oneShare = 10**vault.decimals(); refDecimals = int8(uint8(IERC20Metadata(vault.asset()).decimals())); } @@ -64,4 +67,12 @@ contract MorphoSelfReferentialCollateral is AppreciatingFiatCollateral { function underlyingRefPerTok() public view override returns (uint192) { return shiftl_toFix(vault.convertToAssets(oneShare), -refDecimals); } + + /// Claim rewards earned by holding a balance of the ERC20 token + /// @custom:delegate-call + function claimRewards() external virtual override(Asset, IRewardable) { + uint256 _bal = morpho.balanceOf(address(this)); + IRewardable(address(erc20)).claimRewards(); + emit RewardsClaimed(morpho, morpho.balanceOf(address(this)) - _bal); + } } diff --git a/docs/deployment-variables.md b/docs/deployment-variables.md index e9d66182eb..3e73f8e65e 100644 --- a/docs/deployment-variables.md +++ b/docs/deployment-variables.md @@ -5,7 +5,7 @@ The fraction of revenues that should go towards RToken holders vs stakers, as given by the relative values of `dist.rTokenDist` and `dist.rsrDist`. This can be thought of as a single variable between 0 and 100% (during deployment). Default value: 60% to stakers and 40% to RToken holders. -Mainnet reasonable range: 0% to 100% +Reasonable range: 0% to 100% ### `minTradeVolume` @@ -21,8 +21,8 @@ This variable should NOT be interpreted to mean that auction sizes above this va This parameter can be set to zero. -Default value: `1e21` = $1k -Mainnet reasonable range: 1e19 to 1e23 +Default value: `1e21` = $1k on mainnet; `1e20` = $100 on L2s +Reasonable range: 1e19 to 1e23 #### `rTokenMaxTradeVolume` @@ -33,7 +33,7 @@ The maximum sized trade for any trade involving RToken, in terms of the unit of This parameter can be set to zero. Default value: `1e24` = $1M -Mainnet reasonable range: 1e22 to 1e27. +Reasonable range: 1e22 to 1e27. ### `rewardRatio` @@ -41,11 +41,15 @@ Dimension: `{1}` The `rewardRatio` is the fraction of the current reward amount that should be handed out per second. -Default value: `573038343750` = a half life of 14 days. +Default value: `1146076687500` = a half life of 7 days -Reasonable range: 1e10 to 1e13 +Reasonable range: 1e11 to 1e14 -To calculate: `ln(2) / (60*60*24*desired_days_in_half_life)`, and then multiply by 1e18. +To calculate: `ln(2) / (seconds in half life)`, and then multiply by 1e18. + +``` +1 week half-life: ln(2) / (7 * 24 * 60 * 60) * 1e18 = 1146076687500 +``` ### `unstakingDelay` @@ -54,7 +58,7 @@ Dimension: `{seconds}` The unstaking delay is the number of seconds that all RSR unstakings must be delayed in order to account for stakers trying to frontrun defaults. It must be longer than governance cycle, and must be long enough that RSR stakers do not unstake in advance of foreseeable basket change in order to avoid being expensed for slippage. Default value: `1209600` = 2 weeks -Mainnet reasonable range: 1 to 31536000 +Reasonable range: 1 to 31536000 ### `tradingDelay` @@ -62,8 +66,8 @@ Dimension: `{seconds}` The trading delay is how many seconds should pass after the basket has been changed before a trade can be opened. In the long term this can be set to 0 after MEV searchers are firmly integrated, but at the start it may be useful to have a delay before trading in order to avoid worst-case prices. -Default value: `7200` = 2 hours -Mainnet reasonable range: 0 to 604800 +Default value: `0` = 0s +Reasonable range: 0 to 604800 ### `warmupPeriod` @@ -72,7 +76,7 @@ Dimension: `{seconds}` The warmup period is how many seconds should pass after the basket regained the SOUND status before an RToken can be issued and/or a trade can be opened. Default value: `900` = 15 minutes -Mainnet reasonable range: 0 to 604800 +Reasonable range: 0 to 604800 ### `batchAuctionLength` @@ -81,7 +85,7 @@ Dimension: `{seconds}` The auction length is how many seconds long Gnosis EasyAuctions should be. Default value: `900` = 15 minutes -Mainnet reasonable range: 60 to 3600 +Reasonable range: 60 to 3600 ### `dutchAuctionLength` @@ -91,10 +95,8 @@ The dutch auction length is how many seconds long falling-price dutch auctions s In general, the dutchAuctionLength should be a multiple of the blocktime. This is not enforced at a smart-contract level. -Default value: `1800` = 30 minutes -Mainnet reasonable range: 300 to 3600 - -At 30 minutes, a 12-second blocktime chain would have 10.87% price drops during the first 40% of the auction, and 0.055% price drops during the second 60%. +Default value: `1800` = 30 minutes on (12s blocktime) mainnet; `900` = 15 minutes on L2s +Reasonable range: 100 to 3600 ### `backingBuffer` @@ -103,7 +105,7 @@ Dimension: `{1}` The backing buffer is a percentage value that describes how much overcollateralization to hold in the form of RToken. This buffer allows collateral tokens to be converted into RToken, which is a more efficient form of revenue production than trading each individual collateral for the desired RToken, and also adds a small buffer that can prevent RSR from being seized when there are small losses due to slippage during rebalancing. Default value: `1e15` = 0.1% -Mainnet reasonable range: 1e12 to 1e18 +Reasonable range: 1e12 to 1e18 ### `maxTradeSlippage` @@ -111,8 +113,8 @@ Dimension: `{1}` The max trade slippage is a percentage value that describes the maximum deviation from oracle prices that any trade can clear at. Oracle prices have ranges of their own; the maximum trade slippage permits additional price movement beyond the worst-case oracle price. -Default value: `0.01e18` = 1% -Mainnet reasonable range: 1e12 to 1e18 +Default value: `0.01e18` = 1% on mainnet; 0.5% on L2s (with liquidity caveats) +Reasonable range: 1e12 to 1e18 ### `shortFreeze` @@ -121,7 +123,7 @@ Dimension: `{s}` The number of seconds a short freeze lasts. Governance can freeze forever. Default value: `259200` = 3 days -Mainnet reasonable range: 3600 to 2592000 (1 hour to 1 month) +Reasonable range: 3600 to 2592000 (1 hour to 1 month) ### `longFreeze` @@ -130,7 +132,7 @@ Dimension: `{s}` The number of seconds a long freeze lasts. Long freezes can be disabled by removing all addresses from the `LONG_FREEZER` role. A long freezer has 6 charges that can be used. Default value: `604800` = 7 days -Mainnet reasonable range: 86400 to 31536000 (1 day to 1 year) +Reasonable range: 86400 to 31536000 (1 day to 1 year) ### `withdrawalLeak` @@ -140,8 +142,8 @@ The fraction of RSR stake that should be permitted to withdraw without a refresh Setting this number larger allows unstakers to save more on gas at the cost of allowing more RSR to exit improperly prior to a default. -Default value: `5e16` = 5% -Mainnet reasonable range: 0 to 25e16 (0 to 25%) +Default value: `5e16` = 5% on mainnet; 1% on L2s +Reasonable range: 0 to 25e16 (0 to 25%) ### `RToken Supply Throttles` @@ -150,15 +152,17 @@ In order to restrict the system to organic patterns of behavior, we maintain two The recommended starting values (amt-rate normalized to $USD) for these parameters are as follows: |**Parameter**|**Value**| |-------------|---------| -|issuanceThrottle.amtRate|$250k| -|issuanceThrottle.pctRate|5%| -|redemptionThrottle.amtRate|$500k| -|redemptionThrottle.pctRate|7.5%| +|issuanceThrottle.amtRate|$2m| +|issuanceThrottle.pctRate|10%| +|redemptionThrottle.amtRate|$2.5m| +|redemptionThrottle.pctRate|12.5%| Be sure to convert a $ amtRate (units of `{qUSD}`) back into RTokens (units of `{qTok}`). Note the differing units: the `amtRate` variable is in terms of `{qRTok/hour}` while the `pctRate` variable is in terms of `{1/hour}`, i.e a fraction. +**The redemption throttle must be set higher than the issuance throttle.** + #### `issuanceThrottle.amtRate` Dimension: `{qRTok/hour}` @@ -167,8 +171,9 @@ A quantity of RToken that serves as a lower-bound for how much net issuance to a Must be at least 1 whole RToken, or 1e18. Can be as large as 1e48. Set it to 1e48 if you want to effectively disable the issuance throttle altogether. -Default value: `2.5e23` = 250,000 RToken -Mainnet reasonable range: 1e23 to 1e27 +Default value: `2e24` = 2,000,000 RToken. If the RToken is not pegged to USD then this number should be discounted by a factor of the RToken price in USD. For example: an ETH-pegged RToken might use `2e24 / 4000` = 500,000 RToken. + +Reasonable range: 1e22 to 1e27 #### `issuanceThrottle.pctRate` @@ -178,8 +183,8 @@ A fraction of the RToken supply that indicates how much net issuance to allow pe Can be 0 to solely rely on `amtRate`; cannot be above 1e18. -Default value: `5e16` = 5% per hour -Mainnet reasonable range: 1e15 to 1e18 (0.1% per hour to 100% per hour) +Default value: `10e16` = 10% per hour +Reasonable range: 1e15 to 1e18 (0.1% per hour to 100% per hour) #### `redemptionThrottle.amtRate` @@ -189,8 +194,8 @@ A quantity of RToken that serves as a lower-bound for how much net redemption to Must be at least 1 whole RToken, or 1e18. Can be as large as 1e48. Set it to 1e48 if you want to effectively disable the redemption throttle altogether. -Default value: `5e23` = 500,000 RToken -Mainnet reasonable range: 1e23 to 1e27 +Default value: `2.5e24` = 2,500,000 RToken. If the RToken is not pegged to USD then this number should be discounted by a factor of the RToken price in USD. For example: an ETH-pegged RToken might use `2.5e24 / 4000` = 625,000 RToken. +Reasonable range: 1e23 to 1e27 #### `redemptionThrottle.pctRate` @@ -200,12 +205,12 @@ A fraction of the RToken supply that indicates how much net redemption to allow Can be 0 to solely rely on `amtRate`; cannot be above 1e18. -Default value: `7.5e16` = 7.5% per hour -Mainnet reasonable range: 1e15 to 1e18 (0.1% per hour to 100% per hour) +Default value: `12.5e16` = 12.5% per hour +Reasonable range: 1e15 to 1e18 (0.1% per hour to 100% per hour) ### Governance Parameters -Governance is 8 days end-to-end. +Governance is generally 8 days end-to-end. **Default values** diff --git a/package.json b/package.json index 71c32d75fe..881c4fe247 100644 --- a/package.json +++ b/package.json @@ -10,13 +10,12 @@ }, "scripts": { "compile": "hardhat compile", - "devchain": "FORK=true hardhat node --port 8546", + "devchain": "NODE_OPTIONS='--max-old-space-size=12000' FORK=true hardhat node --port 8546", "deploy:check_env": "hardhat run scripts/check_env.ts", "deploy:run": "hardhat run scripts/deploy.ts", "deploy:confirm": "hardhat run scripts/confirm.ts", "deploy:verify_etherscan": "hardhat run scripts/verify_etherscan.ts", - "eslint": "eslint test/", - "eslint:fuzz": "eslint test/fuzz", + "whales": "npx hardhat run scripts/refresh-whales.ts", "test:extreme": "EXTREME=1 PROTO_IMPL=1 npx hardhat test test/{Broker,Furnace,RTokenExtremes,ZTradingExtremes,ZZStRSR}.test.ts", "test:extreme:integration": "FORK=1 EXTREME=1 PROTO_IMPL=1 npx hardhat test test/integration/**/*.test.ts", "test:unit": "yarn test:plugins && yarn test:p0 && yarn test:p1", @@ -72,7 +71,7 @@ "@types/node": "^12.20.37", "@typescript-eslint/eslint-plugin": "5.17.0", "@typescript-eslint/parser": "5.17.0", - "axios": "^0.24.0", + "axios": "^1.6.8", "bignumber.js": "^9.1.1", "caip": "^1.1.0", "chai": "^4.3.4", @@ -118,6 +117,8 @@ "@aave/periphery-v3": "^2.5.0", "@nomicfoundation/hardhat-toolbox": "^2.0.1", "@types/isomorphic-fetch": "^0.0.36", + "axios-retry": "^4.1.0", + "cheerio": "^1.0.0-rc.12", "isomorphic-fetch": "^3.0.0" } } diff --git a/run.sh b/run.sh new file mode 100755 index 0000000000..b49a6b9040 --- /dev/null +++ b/run.sh @@ -0,0 +1 @@ +NODE_OPTIONS='--max-old-space-size=12000' FORK=true npx hardhat proposal-validator --proposalid 19635069547141631801899721667815895344178432860995231621586111571059800714939 --network hardhat --verbose \ No newline at end of file diff --git a/scripts/addresses/1-tmp-assets-collateral.json b/scripts/addresses/1-tmp-assets-collateral.json new file mode 100644 index 0000000000..b7d3762111 --- /dev/null +++ b/scripts/addresses/1-tmp-assets-collateral.json @@ -0,0 +1,122 @@ +{ + "assets": { + "stkAAVE": "0xF4493581D52671a9E04d693a68ccc61853bceEaE", + "COMP": "0x63eDdF26Bc65eDa1D1c0147ce8E23c09BE963596", + "CRV": "0xc18bF46F178F7e90b9CD8b7A8b00Af026D5ce3D3", + "CVX": "0x7ef93b20C10E6662931b32Dd9D4b85861eB2E4b8" + }, + "collateral": { + "DAI": "0xEc375F2984D21D5ddb0D82767FD8a9C4CE8Eec2F", + "USDC": "0x442f8fc98e3cc6B3d49a66f9858Ac9B6e70Dad3e", + "USDT": "0xe7Dcd101A027Ec34860ECb634a2797d0D2dc4d8b", + "USDP": "0x4C0B21Acb267f1fAE4aeFA977A26c4a63C9B35e6", + "BUSD": "0x97bb4a995b98b1BfF99046b3c518276f78fA5250", + "aDAI": "0x9ca9A9cdcE9E943608c945E7001dC89EB163991E", + "aUSDC": "0xc4240D22FFa144E2712aACF3E2cC302af0339ED0", + "aUSDT": "0x8d753659D4E4e4b4601c7F01Dc1c920cA538E333", + "aBUSD": "0x01F9A6bf339cff820cA503A56FD3705AE35c27F7", + "aUSDP": "0xda5cc207CCefD116fF167a8ABEBBd52bD67C958E", + "cDAI": "0x337E418b880bDA5860e05D632CF039B7751B907B", + "cUSDC": "0x043be931D9C4422e1cFeA528e19818dcDfdE9Ebc", + "cUSDT": "0x5ceadb6606C5D82FcCd3f9b312C018fE1f8aa6dA", + "cUSDP": "0xa0c02De8FfBb9759b9beBA5e29C82112688A0Ff4", + "cWBTC": "0xC0f89AFcb6F1c4E943aA61FFcdFc41fDcB7D84DD", + "cETH": "0x4d3A8507a8eb9036895efdD1a462210CE58DE4ad", + "WBTC": "0x832D65735E541c0404a58B741bEF5652c2B7D0Db", + "WETH": "0xADDca344c92Be84A053C5CBE8e067460767FB816", + "wstETH": "0xb7049ee9F533D32C9434101f0645E6Ea5DFe2cdb", + "rETH": "0x987f5e0f845D46262893e680b652D8aAF1B5bCc0", + "fUSDC": "0xB58D95003Af73CF76Ce349103726a51D4Ec8af17", + "fUSDT": "0xD5254b740FbEF6AAcD674936ea7Fb9f4053781aF", + "fDAI": "0xA0a620B94446a7DC8952ECf252FcC495eeC65873", + "fFRAX": "0xFd9c32198D3cf3ad3b165918FD78De3654cb22eA", + "cUSDCv3": "0x33Ba1BC07b0fafb4BBC1520B330081b91ca6bdf0", + "cvx3Pool": "0x8E5ADdC553962DAcdF48106B6218AC93DA9617b2", + "cvxPayPool": "0x5315Fbe0CEB299F53aE375f65fd9376767C8224c", + "cvxeUSDFRAXBP": "0xE529B59C1764d6E5a274099Eb660DD9e130A5481", + "cvxMIM3Pool": "0x3d21f841C0Fb125176C1DBDF0DE196b071323A75", + "cvxETHPlusETH": "0xc4a5Fb266E8081D605D87f0b1290F54B0a5Dc221", + "crveUSDFRAXBP": "0x945b0ad788dD6dB3864AB23876C68C1bf000d237", + "crvMIM3Pool": "0x692cf8CE08d03eF1f8C3dCa82F67935fa9417B62", + "crv3Pool": "0xf59a7987EDd5380cbAb30c37D1c808686f9b67B9", + "sDAI": "0x62a9DDC6FF6077E823690118eCc935d16A8de47e", + "cbETH": "0xC8b80813cad9139D0eeFe38C711a11b20147aA54", + "maUSDT": "0x2F8F8Ac64ECbAC38f212b05115836120784a29F7", + "maUSDC": "0xC5d03FB7A38E6025D9A32C7444cfbBfa18B7D656", + "maDAI": "0x7be70371e7ECd9af5A5b49015EC8F8C336B52D81", + "maWBTC": "0x75B6921925e8BD632380706e722035752ffF175d", + "maWETH": "0xA402078f0A2e077Ea2b1Fb3b6ab74F0cBA10E508", + "maStETH": "0x4a139215D9E696c0e7618a441eD3CFd12bbD8CD6", + "yvCurveUSDCcrvUSD": "0x1573416df7095F698e37A954D9e951868E526650", + "yvCurveUSDPcrvUSD": "0xb3A3552Cc52411dFF6D520C6F725E6F9e11001EF", + "sFRAX": "0x0b7DcCBceA6f985301506D575E2661bf858CdEcC", + "saEthUSDC": "0x00F820794Bda3fb01E5f159ee1fF7c8409fca5AB", + "saEthPyUSD": "0x58a41c87f8C65cf21f961b570540b176e408Cf2E", + "bbUSDT": "0x3017d881724D93783e7f065Cc5F62c81C62c36A0", + "steakUSDC": "0x4895b9aee383b5dec499F54172Ccc7Ee05FC8Bbc", + "steakPYUSD": "0xBd01C789Be742688fb73F6aE46f1320196B6c973", + "Re7WETH": "0x3421d2cB19c8E69c6FA642C43e60cD943e75Ca8b", + "cvxCrvUSDUSDC": "0x9Fc0F31e2D26C437461a9eEBfe858d17e2611Ea5", + "cvxCrvUSDUSDT": "0x69c6597690B8Df61D15F201519C03725bdec40c1", + "sfrxETH": "0x4c891fCa6319d492866672E3D2AfdAAA5bDcfF67" + }, + "erc20s": { + "stkAAVE": "0x4da27a545c0c5B758a6BA100e3a049001de870f5", + "COMP": "0xc00e94Cb662C3520282E6f5717214004A7f26888", + "DAI": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "USDC": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "USDT": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "USDP": "0x8E870D67F660D95d5be530380D0eC0bd388289E1", + "BUSD": "0x4Fabb145d64652a948d72533023f6E7A623C7C53", + "aDAI": "0x717AC7A53C6a6a5529175dff7fCc76858436f8c0", + "aUSDC": "0xa8157BF67Fd7BcDCC139CB9Bf1bd7Eb921A779D3", + "aUSDT": "0x684AA4faf9b07d5091B88c6e0a8160aCa5e6d17b", + "aBUSD": "0xf3840c4B214699F94fBB69ad3922f44176c93658", + "aUSDP": "0x5Ad7CeD3c64847980082e106390DeC3765A5f1C4", + "cDAI": "0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643", + "cUSDC": "0x39AA39c021dfbaE8faC545936693aC917d5E7563", + "cUSDT": "0xf650C3d88D12dB855b8bf7D11Be6C55A4e07dCC9", + "cUSDP": "0x041171993284df560249B57358F931D9eB7b925D", + "cWBTC": "0xccF4429DB6322D5C611ee964527D42E5d685DD6a", + "cETH": "0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5", + "WBTC": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", + "WETH": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "wstETH": "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", + "rETH": "0xae78736Cd615f374D3085123A210448E74Fc6393", + "fUSDC": "0x465a5a630482f3abD6d3b84B39B29b07214d19e5", + "fUSDT": "0x81994b9607e06ab3d5cF3AffF9a67374f05F27d7", + "fDAI": "0xe2bA8693cE7474900A045757fe0efCa900F6530b", + "fFRAX": "0x1C9A2d6b33B4826757273D47ebEe0e2DddcD978B", + "cUSDCv3": "0x27F2f159Fe990Ba83D57f39Fd69661764BEbf37a", + "cvx3Pool": "0x24CDc6b4Edd3E496b7283D94D93119983A61056a", + "cvxPayPool": "0x511daB8150966aFfE15F0a5bFfBa7F4d2b62DEd4", + "cvxeUSDFRAXBP": "0x81697e25DFf8564d9E0bC6D27edb40006b34ea2A", + "cvxMIM3Pool": "0x3e8f7EDc03E0133b95EcB4dD2f72B5027E695413", + "cvxETHPlusETH": "0xDbC0cE2321B76D3956412B36e9c0FA9B0fD176E7", + "crv3Pool": "0x8A6029C6D921dCa4fAbf6F5b2F6D14606F8Fd0aB", + "crveUSDFRAXBP": "0x3D07B9b2Aa60843470e6dAb09a0c3a31DE42E7Ea", + "crvMIM3Pool": "0xB1d0076d156D83B117De3bc63E7CE8031AB117fD", + "sDAI": "0x83f20f44975d03b1b09e64809b757c47f942beea", + "cbETH": "0xBe9895146f7AF43049ca1c1AE358B0541Ea49704", + "maUSDT": "0x9FD7165AEf369913258F4C8B19c9C350C2dE63cC", + "maUSDC": "0x6Bf3356923E6D611b8352B4895135e1Edfcf217B", + "maDAI": "0x9E5EC103944c19D7E7aBfb2947a865d51bc6947C", + "maWBTC": "0x1F423dC943738b9c31cB3d96c2A744dd7502593d", + "maWETH": "0xB7c4c4a2B7453E10d7e4e23Fa8E8D2335d09afab", + "maStETH": "0xAdc10669354aAd42A581E6F6cC8990B540AA5689", + "yvCurveUSDCcrvUSD": "0x7cA00559B978CFde81297849be6151d3ccB408A9", + "yvCurveUSDPcrvUSD": "0xF56fB6cc29F0666BDD1662FEaAE2A3C935ee3469", + "sFRAX": "0xA663B02CF0a4b149d2aD41910CB81e23e1c41c32", + "saEthUSDC": "0x0aDc69041a2B086f8772aCcE2A754f410F211bed", + "saEthPyUSD": "0x1576B2d7ef15a2ebE9C22C8765DD9c1EfeA8797b", + "bbUSDT": "0x2C25f6C25770fFEC5959D34B94Bf898865e5D6b1", + "steakUSDC": "0xBEEF01735c132Ada46AA9aA4c54623cAA92A64CB", + "steakPYUSD": "0xbEEF02e5E13584ab96848af90261f0C8Ee04722a", + "Re7WETH": "0x78Fc2c2eD1A4cDb5402365934aE5648aDAd094d0", + "cvxCrvUSDUSDC": "0x6ad24C0B8fD4B594C6009A7F7F48450d9F56c6b8", + "cvxCrvUSDUSDT": "0x5d1B749bA7f689ef9f260EDC54326C48919cA88b", + "sfrxETH": "0xac3E018457B222d93114458476f3E3416Abbe38F", + "CRV": "0xD533a949740bb3306d119CC777fa900bA034cd52", + "CVX": "0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B" + } +} diff --git a/scripts/addresses/1-tmp-deployments.json b/scripts/addresses/1-tmp-deployments.json new file mode 100644 index 0000000000..3101baf7e4 --- /dev/null +++ b/scripts/addresses/1-tmp-deployments.json @@ -0,0 +1,38 @@ +{ + "prerequisites": { + "RSR": "0x320623b8E4fF03373931769A31Fc52A4E78B5d70", + "RSR_FEED": "0x759bBC1be8F90eE6457C44abc7d443842a976d02", + "GNOSIS_EASY_AUCTION": "0x0b7fFc1f4AD541A4Ed16b40D8c37f0929158D101" + }, + "tradingLib": "0xa54544C6C36C0d776cc4F04EBB847e0BB3A11ea2", + "facade": "0x2C7ca56342177343A2954C250702Fd464f4d0613", + "facets": { + "actFacet": "0xCAB3D3d0d5544145A6BCB47e58F61368BCcAe2dB", + "readFacet": "0x823110a13eB26cB09c4Bb118DBfE4ff5f96D5526", + "maxIssuableFacet": "0x5771d976696AA180Fed276FB6571fE2f41D0b849" + }, + "facadeWriteLib": "0xDf73Cd789422040182b0C24a8b2C97bbCbba3263", + "basketLib": "0xf383dC60D29A5B9ba461F40A0606870d80d1EA88", + "facadeWrite": "0x1D94290F82D0B417B088d9F5dB316B11C9cf220C", + "deployer": "0x2204EC97D31E2C9eE62eaD9e6E2d5F7712D3f1bF", + "rsrAsset": "0x591529f039Ba48C3bEAc5090e30ceDDcb41D0EaA", + "implementations": { + "main": "0x24a4B37F9c40fB0E80ec436Df2e9989FBAFa8bB7", + "trading": { + "gnosisTrade": "0x030c9B66Ac089cB01aA2058FC8f7d9baddC9ae75", + "dutchTrade": "0x971c890ACb9EeB084f292996Be667bB9A2889AE9" + }, + "components": { + "assetRegistry": "0xbF1C0206de440b2cF76Ea4405e1DbF2fC227a463", + "backingManager": "0x20C801869e578E71F2298649870765Aa81f7DC69", + "basketHandler": "0xeE7FC703f84AE2CE30475333c57E56d3A7D3AdBC", + "broker": "0x62BD44b05542bfF1E59A01Bf7151F533e1c9C12c", + "distributor": "0x44a42A0F14128E81a21c5fc4322a9f91fF83b4Ee", + "furnace": "0x845B8b0a1c6DB8318414d708Da25fA28d4a0dc81", + "rsrTrader": "0xc60a7Cd6fce24d0c3637A1dCBC8B0f9A9BFF6a7c", + "rTokenTrader": "0xc60a7Cd6fce24d0c3637A1dCBC8B0f9A9BFF6a7c", + "rToken": "0x784955641292b0014BC9eF82321300f0b6C7E36d", + "stRSR": "0xE433673648c94FEC0706E5AC95d4f4097f58B5fb" + } + } +} diff --git a/scripts/addresses/base-3.4.0/8453-tmp-assets-collateral.json b/scripts/addresses/base-3.4.0/8453-tmp-assets-collateral.json index 6eb3b4b007..4602fbd2dd 100644 --- a/scripts/addresses/base-3.4.0/8453-tmp-assets-collateral.json +++ b/scripts/addresses/base-3.4.0/8453-tmp-assets-collateral.json @@ -1,9 +1,28 @@ { - "assets": {}, + "assets": { + "COMP": "0xB8794Fb1CCd62bFe631293163F4A3fC2d22e37e0", + "STG": "0xEE527CC63122732532d0f1ad33Ec035D30f3050f" + }, "collateral": { - "saBasUSDC": "0x0F345F57ee2b395e23390f8e1F1869D7E6C0F70e" + "DAI": "0x3E40840d0282C9F9cC7d17094b5239f87fcf18e5", + "USDC": "0xaa85216187F92a781D8F9Bcb40825E356ee2635a", + "USDbC": "0xD126741474B0348D9B0F4911573d8f543c01C2c4", + "WETH": "0x073BD162BBD05Cd2CF631B90D44239B8a367276e", + "cbETH": "0x851B461a9744f4c9E996C03072cAB6f44Fa04d0D", + "saBasUSDC": "0xC19f5d60e2Aca1174f3D5Fe189f0A69afaB76f50", + "cUSDCv3": "0xf7a9D27c3B60c78c6F6e2c2d6ED6E8B94b352461", + "wstETH": "0x8b4374005291B8FCD14C4E947604b2FB3C660A73" }, "erc20s": { - "saBasUSDC": "0x184460704886f9F2A7F3A0c2887680867954dC6E" + "COMP": "0x9e1028F5F1D5eDE59748FFceE5532509976840E0", + "DAI": "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb", + "USDC": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "USDbC": "0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA", + "WETH": "0x4200000000000000000000000000000000000006", + "cbETH": "0x2ae3f1ec7f1f5012cfeab0185bfc7aa3cf0dec22", + "saBasUSDC": "0x6F6f81e5E66f503184f2202D83a79650c3285759", + "STG": "0xE3B53AF74a4BF62Ae5511055290838050bf764Df", + "cUSDCv3": "0x53f1Df4E5591Ae35Bf738742981669c3767241FA", + "wstETH": "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452" } } diff --git a/scripts/addresses/base-3.4.0/8453-tmp-deployments.json b/scripts/addresses/base-3.4.0/8453-tmp-deployments.json new file mode 100644 index 0000000000..90ff83fd9a --- /dev/null +++ b/scripts/addresses/base-3.4.0/8453-tmp-deployments.json @@ -0,0 +1,38 @@ +{ + "prerequisites": { + "RSR": "0xaB36452DbAC151bE02b16Ca17d8919826072f64a", + "RSR_FEED": "0xAa98aE504658766Dfe11F31c5D95a0bdcABDe0b1", + "GNOSIS_EASY_AUCTION": "0xb1875Feaeea32Bbb02DE83D81772e07E37A40f02" + }, + "tradingLib": "0x6419fe6cf428150e2d8ed38a3316b1bb468f79a7", + "facade": "0xEb2071e9B542555E90E6e4E1F83fa17423583991", + "facets": { + "actFacet": "0x0eac15B9Fe585432E48Cf175571D75D111861F43", + "readFacet": "0x5Af543D6F95a98200Dd770f39A902Fe793BAeB27", + "maxIssuableFacet": "0x63FDcB1E8Ee5C4B64A5c4ce0FB97597917920cb6" + }, + "facadeWriteLib": "0x186d05580E6B7195323b5dC8c3ee9179Ad086d4C", + "basketLib": "0x182e86ad4a6139ced4f9fa4ed3f1cd9e4f7449e7", + "facadeWrite": "0x43E205A805c4be5A62C71d49de68dF60200548A0", + "deployer": "0xFD18bA9B2f9241Ce40CDE14079c1cDA1502A8D0A", + "rsrAsset": "0x02062c16c28A169D1f2F5EfA7eEDc42c3311ec23", + "implementations": { + "main": "0x2a2A842Dda2Da2170a531dfF4bD4A821321e4485", + "trading": { + "gnosisTrade": "0x93de153Ba104D15785c8d8af01AE9425960de49e", + "dutchTrade": "0x270284ecb6aF0dc521D2c8f9D77b03EEd2aace90" + }, + "components": { + "assetRegistry": "0x3DDe17cfd36e740CB7452cb2F59FC925eACb91aB", + "backingManager": "0xb5bDFF1FB47635383ABf13b78a79C8a21aA1b23E", + "basketHandler": "0xA4f1Fc88eFF9a72bCc278a2D3B79cafCc1551fb5", + "broker": "0x1cddc45cb390C3b4a739861155E8ee95b7321eD6", + "distributor": "0xba748FAF1a94B5C8De5C8Ca8D87A0906C5B0300c", + "furnace": "0xE0B810bD674132b553770064Fc90440c5A5f518d", + "rsrTrader": "0x3c2460ACa70bedf096f71Cf91fFBc0789F08503f", + "rTokenTrader": "0x3c2460ACa70bedf096f71Cf91fFBc0789F08503f", + "rToken": "0x02Ab5B6dF2c17d060EE3e95D08225Ff3A42504a5", + "stRSR": "0x4Cf200D7fA568611DD8B4BD85053ba9419982C7D" + } + } +} diff --git a/scripts/addresses/mainnet-3.4.0/1-tmp-assets-collateral.json b/scripts/addresses/mainnet-3.4.0/1-tmp-assets-collateral.json index e96d88efa0..b7d3762111 100644 --- a/scripts/addresses/mainnet-3.4.0/1-tmp-assets-collateral.json +++ b/scripts/addresses/mainnet-3.4.0/1-tmp-assets-collateral.json @@ -1,6 +1,55 @@ { - "assets": {}, + "assets": { + "stkAAVE": "0xF4493581D52671a9E04d693a68ccc61853bceEaE", + "COMP": "0x63eDdF26Bc65eDa1D1c0147ce8E23c09BE963596", + "CRV": "0xc18bF46F178F7e90b9CD8b7A8b00Af026D5ce3D3", + "CVX": "0x7ef93b20C10E6662931b32Dd9D4b85861eB2E4b8" + }, "collateral": { + "DAI": "0xEc375F2984D21D5ddb0D82767FD8a9C4CE8Eec2F", + "USDC": "0x442f8fc98e3cc6B3d49a66f9858Ac9B6e70Dad3e", + "USDT": "0xe7Dcd101A027Ec34860ECb634a2797d0D2dc4d8b", + "USDP": "0x4C0B21Acb267f1fAE4aeFA977A26c4a63C9B35e6", + "BUSD": "0x97bb4a995b98b1BfF99046b3c518276f78fA5250", + "aDAI": "0x9ca9A9cdcE9E943608c945E7001dC89EB163991E", + "aUSDC": "0xc4240D22FFa144E2712aACF3E2cC302af0339ED0", + "aUSDT": "0x8d753659D4E4e4b4601c7F01Dc1c920cA538E333", + "aBUSD": "0x01F9A6bf339cff820cA503A56FD3705AE35c27F7", + "aUSDP": "0xda5cc207CCefD116fF167a8ABEBBd52bD67C958E", + "cDAI": "0x337E418b880bDA5860e05D632CF039B7751B907B", + "cUSDC": "0x043be931D9C4422e1cFeA528e19818dcDfdE9Ebc", + "cUSDT": "0x5ceadb6606C5D82FcCd3f9b312C018fE1f8aa6dA", + "cUSDP": "0xa0c02De8FfBb9759b9beBA5e29C82112688A0Ff4", + "cWBTC": "0xC0f89AFcb6F1c4E943aA61FFcdFc41fDcB7D84DD", + "cETH": "0x4d3A8507a8eb9036895efdD1a462210CE58DE4ad", + "WBTC": "0x832D65735E541c0404a58B741bEF5652c2B7D0Db", + "WETH": "0xADDca344c92Be84A053C5CBE8e067460767FB816", + "wstETH": "0xb7049ee9F533D32C9434101f0645E6Ea5DFe2cdb", + "rETH": "0x987f5e0f845D46262893e680b652D8aAF1B5bCc0", + "fUSDC": "0xB58D95003Af73CF76Ce349103726a51D4Ec8af17", + "fUSDT": "0xD5254b740FbEF6AAcD674936ea7Fb9f4053781aF", + "fDAI": "0xA0a620B94446a7DC8952ECf252FcC495eeC65873", + "fFRAX": "0xFd9c32198D3cf3ad3b165918FD78De3654cb22eA", + "cUSDCv3": "0x33Ba1BC07b0fafb4BBC1520B330081b91ca6bdf0", + "cvx3Pool": "0x8E5ADdC553962DAcdF48106B6218AC93DA9617b2", + "cvxPayPool": "0x5315Fbe0CEB299F53aE375f65fd9376767C8224c", + "cvxeUSDFRAXBP": "0xE529B59C1764d6E5a274099Eb660DD9e130A5481", + "cvxMIM3Pool": "0x3d21f841C0Fb125176C1DBDF0DE196b071323A75", + "cvxETHPlusETH": "0xc4a5Fb266E8081D605D87f0b1290F54B0a5Dc221", + "crveUSDFRAXBP": "0x945b0ad788dD6dB3864AB23876C68C1bf000d237", + "crvMIM3Pool": "0x692cf8CE08d03eF1f8C3dCa82F67935fa9417B62", + "crv3Pool": "0xf59a7987EDd5380cbAb30c37D1c808686f9b67B9", + "sDAI": "0x62a9DDC6FF6077E823690118eCc935d16A8de47e", + "cbETH": "0xC8b80813cad9139D0eeFe38C711a11b20147aA54", + "maUSDT": "0x2F8F8Ac64ECbAC38f212b05115836120784a29F7", + "maUSDC": "0xC5d03FB7A38E6025D9A32C7444cfbBfa18B7D656", + "maDAI": "0x7be70371e7ECd9af5A5b49015EC8F8C336B52D81", + "maWBTC": "0x75B6921925e8BD632380706e722035752ffF175d", + "maWETH": "0xA402078f0A2e077Ea2b1Fb3b6ab74F0cBA10E508", + "maStETH": "0x4a139215D9E696c0e7618a441eD3CFd12bbD8CD6", + "yvCurveUSDCcrvUSD": "0x1573416df7095F698e37A954D9e951868E526650", + "yvCurveUSDPcrvUSD": "0xb3A3552Cc52411dFF6D520C6F725E6F9e11001EF", + "sFRAX": "0x0b7DcCBceA6f985301506D575E2661bf858CdEcC", "saEthUSDC": "0x00F820794Bda3fb01E5f159ee1fF7c8409fca5AB", "saEthPyUSD": "0x58a41c87f8C65cf21f961b570540b176e408Cf2E", "bbUSDT": "0x3017d881724D93783e7f065Cc5F62c81C62c36A0", @@ -12,6 +61,52 @@ "sfrxETH": "0x4c891fCa6319d492866672E3D2AfdAAA5bDcfF67" }, "erc20s": { + "stkAAVE": "0x4da27a545c0c5B758a6BA100e3a049001de870f5", + "COMP": "0xc00e94Cb662C3520282E6f5717214004A7f26888", + "DAI": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "USDC": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "USDT": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "USDP": "0x8E870D67F660D95d5be530380D0eC0bd388289E1", + "BUSD": "0x4Fabb145d64652a948d72533023f6E7A623C7C53", + "aDAI": "0x717AC7A53C6a6a5529175dff7fCc76858436f8c0", + "aUSDC": "0xa8157BF67Fd7BcDCC139CB9Bf1bd7Eb921A779D3", + "aUSDT": "0x684AA4faf9b07d5091B88c6e0a8160aCa5e6d17b", + "aBUSD": "0xf3840c4B214699F94fBB69ad3922f44176c93658", + "aUSDP": "0x5Ad7CeD3c64847980082e106390DeC3765A5f1C4", + "cDAI": "0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643", + "cUSDC": "0x39AA39c021dfbaE8faC545936693aC917d5E7563", + "cUSDT": "0xf650C3d88D12dB855b8bf7D11Be6C55A4e07dCC9", + "cUSDP": "0x041171993284df560249B57358F931D9eB7b925D", + "cWBTC": "0xccF4429DB6322D5C611ee964527D42E5d685DD6a", + "cETH": "0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5", + "WBTC": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", + "WETH": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "wstETH": "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", + "rETH": "0xae78736Cd615f374D3085123A210448E74Fc6393", + "fUSDC": "0x465a5a630482f3abD6d3b84B39B29b07214d19e5", + "fUSDT": "0x81994b9607e06ab3d5cF3AffF9a67374f05F27d7", + "fDAI": "0xe2bA8693cE7474900A045757fe0efCa900F6530b", + "fFRAX": "0x1C9A2d6b33B4826757273D47ebEe0e2DddcD978B", + "cUSDCv3": "0x27F2f159Fe990Ba83D57f39Fd69661764BEbf37a", + "cvx3Pool": "0x24CDc6b4Edd3E496b7283D94D93119983A61056a", + "cvxPayPool": "0x511daB8150966aFfE15F0a5bFfBa7F4d2b62DEd4", + "cvxeUSDFRAXBP": "0x81697e25DFf8564d9E0bC6D27edb40006b34ea2A", + "cvxMIM3Pool": "0x3e8f7EDc03E0133b95EcB4dD2f72B5027E695413", + "cvxETHPlusETH": "0xDbC0cE2321B76D3956412B36e9c0FA9B0fD176E7", + "crv3Pool": "0x8A6029C6D921dCa4fAbf6F5b2F6D14606F8Fd0aB", + "crveUSDFRAXBP": "0x3D07B9b2Aa60843470e6dAb09a0c3a31DE42E7Ea", + "crvMIM3Pool": "0xB1d0076d156D83B117De3bc63E7CE8031AB117fD", + "sDAI": "0x83f20f44975d03b1b09e64809b757c47f942beea", + "cbETH": "0xBe9895146f7AF43049ca1c1AE358B0541Ea49704", + "maUSDT": "0x9FD7165AEf369913258F4C8B19c9C350C2dE63cC", + "maUSDC": "0x6Bf3356923E6D611b8352B4895135e1Edfcf217B", + "maDAI": "0x9E5EC103944c19D7E7aBfb2947a865d51bc6947C", + "maWBTC": "0x1F423dC943738b9c31cB3d96c2A744dd7502593d", + "maWETH": "0xB7c4c4a2B7453E10d7e4e23Fa8E8D2335d09afab", + "maStETH": "0xAdc10669354aAd42A581E6F6cC8990B540AA5689", + "yvCurveUSDCcrvUSD": "0x7cA00559B978CFde81297849be6151d3ccB408A9", + "yvCurveUSDPcrvUSD": "0xF56fB6cc29F0666BDD1662FEaAE2A3C935ee3469", + "sFRAX": "0xA663B02CF0a4b149d2aD41910CB81e23e1c41c32", "saEthUSDC": "0x0aDc69041a2B086f8772aCcE2A754f410F211bed", "saEthPyUSD": "0x1576B2d7ef15a2ebE9C22C8765DD9c1EfeA8797b", "bbUSDT": "0x2C25f6C25770fFEC5959D34B94Bf898865e5D6b1", @@ -20,6 +115,8 @@ "Re7WETH": "0x78Fc2c2eD1A4cDb5402365934aE5648aDAd094d0", "cvxCrvUSDUSDC": "0x6ad24C0B8fD4B594C6009A7F7F48450d9F56c6b8", "cvxCrvUSDUSDT": "0x5d1B749bA7f689ef9f260EDC54326C48919cA88b", - "sfrxETH": "0xac3E018457B222d93114458476f3E3416Abbe38F" + "sfrxETH": "0xac3E018457B222d93114458476f3E3416Abbe38F", + "CRV": "0xD533a949740bb3306d119CC777fa900bA034cd52", + "CVX": "0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B" } -} \ No newline at end of file +} diff --git a/scripts/addresses/mainnet-3.4.0/1-tmp-deployments.json b/scripts/addresses/mainnet-3.4.0/1-tmp-deployments.json new file mode 100644 index 0000000000..3101baf7e4 --- /dev/null +++ b/scripts/addresses/mainnet-3.4.0/1-tmp-deployments.json @@ -0,0 +1,38 @@ +{ + "prerequisites": { + "RSR": "0x320623b8E4fF03373931769A31Fc52A4E78B5d70", + "RSR_FEED": "0x759bBC1be8F90eE6457C44abc7d443842a976d02", + "GNOSIS_EASY_AUCTION": "0x0b7fFc1f4AD541A4Ed16b40D8c37f0929158D101" + }, + "tradingLib": "0xa54544C6C36C0d776cc4F04EBB847e0BB3A11ea2", + "facade": "0x2C7ca56342177343A2954C250702Fd464f4d0613", + "facets": { + "actFacet": "0xCAB3D3d0d5544145A6BCB47e58F61368BCcAe2dB", + "readFacet": "0x823110a13eB26cB09c4Bb118DBfE4ff5f96D5526", + "maxIssuableFacet": "0x5771d976696AA180Fed276FB6571fE2f41D0b849" + }, + "facadeWriteLib": "0xDf73Cd789422040182b0C24a8b2C97bbCbba3263", + "basketLib": "0xf383dC60D29A5B9ba461F40A0606870d80d1EA88", + "facadeWrite": "0x1D94290F82D0B417B088d9F5dB316B11C9cf220C", + "deployer": "0x2204EC97D31E2C9eE62eaD9e6E2d5F7712D3f1bF", + "rsrAsset": "0x591529f039Ba48C3bEAc5090e30ceDDcb41D0EaA", + "implementations": { + "main": "0x24a4B37F9c40fB0E80ec436Df2e9989FBAFa8bB7", + "trading": { + "gnosisTrade": "0x030c9B66Ac089cB01aA2058FC8f7d9baddC9ae75", + "dutchTrade": "0x971c890ACb9EeB084f292996Be667bB9A2889AE9" + }, + "components": { + "assetRegistry": "0xbF1C0206de440b2cF76Ea4405e1DbF2fC227a463", + "backingManager": "0x20C801869e578E71F2298649870765Aa81f7DC69", + "basketHandler": "0xeE7FC703f84AE2CE30475333c57E56d3A7D3AdBC", + "broker": "0x62BD44b05542bfF1E59A01Bf7151F533e1c9C12c", + "distributor": "0x44a42A0F14128E81a21c5fc4322a9f91fF83b4Ee", + "furnace": "0x845B8b0a1c6DB8318414d708Da25fA28d4a0dc81", + "rsrTrader": "0xc60a7Cd6fce24d0c3637A1dCBC8B0f9A9BFF6a7c", + "rTokenTrader": "0xc60a7Cd6fce24d0c3637A1dCBC8B0f9A9BFF6a7c", + "rToken": "0x784955641292b0014BC9eF82321300f0b6C7E36d", + "stRSR": "0xE433673648c94FEC0706E5AC95d4f4097f58B5fb" + } + } +} diff --git a/scripts/deploy.ts b/scripts/deploy.ts index c7ef59ead8..6c8ee02fb5 100644 --- a/scripts/deploy.ts +++ b/scripts/deploy.ts @@ -31,7 +31,7 @@ async function main() { 'phase1-core/1_deploy_libraries.ts', 'phase1-core/2_deploy_implementations.ts', 'phase1-core/3_deploy_rsrAsset.ts', - 'phase1-core/4_deploy_facade.ts', // comment this out before deployment to keep old Facade + 'phase1-core/4_deploy_facade.ts', 'phase1-core/5_deploy_deployer.ts', 'phase1-core/6_deploy_facadeWrite.ts', ] @@ -62,9 +62,11 @@ async function main() { 'phase2-assets/collaterals/deploy_convex_3pool_collateral.ts', 'phase2-assets/collaterals/deploy_convex_paypool_collateral.ts', 'phase2-assets/collaterals/deploy_convex_crvusd_usdc_collateral.ts', + 'phase2-assets/collaterals/deploy_convex_crvusd_usdt_collateral.ts', 'phase2-assets/collaterals/deploy_convex_rToken_metapool_plugin.ts', 'phase2-assets/collaterals/deploy_convex_stable_metapool_plugin.ts', 'phase2-assets/collaterals/deploy_convex_ethplus_eth.ts', + 'phase2-assets/collaterals/deploy_stakedao_usdc_usdcplus.ts', 'phase2-assets/collaterals/deploy_curve_stable_plugin.ts', 'phase2-assets/collaterals/deploy_curve_rToken_metapool_plugin.ts', 'phase2-assets/collaterals/deploy_curve_stable_metapool_plugin.ts', @@ -80,7 +82,9 @@ async function main() { 'phase2-assets/collaterals/deploy_steakusdc.ts', 'phase2-assets/collaterals/deploy_steakpyusd.ts', 'phase2-assets/collaterals/deploy_bbusdt.ts', - 'phase2-assets/collaterals/deploy_re7weth.ts' + 'phase2-assets/collaterals/deploy_re7weth.ts', + 'phase2-assets/assets/deploy_crv.ts', + 'phase2-assets/assets/deploy_cvx.ts' ) } else if (chainId == '8453' || chainId == '84531') { // Base L2 chains @@ -89,9 +93,10 @@ async function main() { 'phase2-assets/1_deploy_assets.ts', 'phase2-assets/2_deploy_collateral.ts', 'phase2-assets/collaterals/deploy_cbeth_collateral.ts', - 'phase2-assets/collaterals/deploy_ctokenv3_usdbc_collateral.ts', + 'phase2-assets/collaterals/deploy_ctokenv3_usdc_collateral.ts', 'phase2-assets/collaterals/deploy_aave_v3_usdc.ts', - 'phase2-assets/collaterals/deploy_stargate_usdc_collateral.ts', + 'phase2-assets/collaterals/deploy_lido_wsteth_collateral.ts', + 'phase2-assets/collaterals/deploy_cbeth_collateral.ts', 'phase2-assets/assets/deploy_stg.ts' ) } else if (chainId == '42161' || chainId == '421614') { diff --git a/scripts/deployment/common.ts b/scripts/deployment/common.ts index b87565bbd1..66f03c7c97 100644 --- a/scripts/deployment/common.ts +++ b/scripts/deployment/common.ts @@ -23,7 +23,6 @@ export interface IDeployments { facade: string facets: IFacets facadeWriteLib: string - cvxMiningLib: string facadeWrite: string deployer: string rsrAsset: string diff --git a/scripts/deployment/phase1-core/0_setup_deployments.ts b/scripts/deployment/phase1-core/0_setup_deployments.ts index 9cddc68e88..f2c4666e54 100644 --- a/scripts/deployment/phase1-core/0_setup_deployments.ts +++ b/scripts/deployment/phase1-core/0_setup_deployments.ts @@ -54,11 +54,11 @@ async function main() { GNOSIS_EASY_AUCTION: gnosisAddr, }, tradingLib: '', - cvxMiningLib: '', facade: '', facets: { actFacet: '', readFacet: '', + maxIssuableFacet: '', }, facadeWriteLib: '', basketLib: '', diff --git a/scripts/deployment/phase1-core/1_deploy_libraries.ts b/scripts/deployment/phase1-core/1_deploy_libraries.ts index 78a4efa683..5b4080d2b0 100644 --- a/scripts/deployment/phase1-core/1_deploy_libraries.ts +++ b/scripts/deployment/phase1-core/1_deploy_libraries.ts @@ -1,10 +1,10 @@ import fs from 'fs' import hre, { ethers } from 'hardhat' import { getChainId } from '../../../common/blockchain-utils' -import { baseL2Chains, networkConfig } from '../../../common/configuration' +import { networkConfig } from '../../../common/configuration' import { getDeploymentFile, getDeploymentFilename, IDeployments } from '../common' import { validatePrerequisites } from '../utils' -import { BasketLibP1, CvxMining, RecollateralizationLibP1 } from '../../../typechain' +import { BasketLibP1, RecollateralizationLibP1 } from '../../../typechain' let tradingLib: RecollateralizationLibP1 let basketLib: BasketLibP1 diff --git a/scripts/deployment/phase1-facade/2_deploy_actFacet.ts b/scripts/deployment/phase1-facade/2_deploy_actFacet.ts index 97ee29342a..38b48c8e4c 100644 --- a/scripts/deployment/phase1-facade/2_deploy_actFacet.ts +++ b/scripts/deployment/phase1-facade/2_deploy_actFacet.ts @@ -13,7 +13,7 @@ async function main() { const [burner] = await hre.ethers.getSigners() const chainId = await getChainId(hre) - console.log(`Deploying Facade to network ${hre.network.name} (${chainId}) + console.log(`Deploying ActFacet to network ${hre.network.name} (${chainId}) with burner account: ${burner.address}`) if (!networkConfig[chainId]) { diff --git a/scripts/deployment/phase2-assets/assets/deploy_stg.ts b/scripts/deployment/phase2-assets/assets/deploy_stg.ts index 98c81e2be1..2cac620c9a 100644 --- a/scripts/deployment/phase2-assets/assets/deploy_stg.ts +++ b/scripts/deployment/phase2-assets/assets/deploy_stg.ts @@ -10,7 +10,7 @@ import { IAssetCollDeployments, fileExists, } from '../../../deployment/common' -import { priceTimeout, oracleTimeout } from '../../../deployment/utils' +import { priceTimeout } from '../../../deployment/utils' import { Asset } from '../../../../typechain' async function main() { @@ -43,7 +43,7 @@ async function main() { oracleError: fp('0.02').toString(), // 2% tokenAddress: networkConfig[chainId].tokens.STG, maxTradeVolume: fp('1e6').toString(), // $1m, - oracleTimeout: oracleTimeout(chainId, '86400').toString(), // 24 hr + oracleTimeout: '86400', // 24 hr }) await (await ethers.getContractAt('Asset', stgAsset)).refresh() diff --git a/scripts/deployment/phase2-assets/collaterals/deploy_convex_ethplus_eth.ts b/scripts/deployment/phase2-assets/collaterals/deploy_convex_ethplus_eth.ts index 87f2a33d2b..7b55998602 100644 --- a/scripts/deployment/phase2-assets/collaterals/deploy_convex_ethplus_eth.ts +++ b/scripts/deployment/phase2-assets/collaterals/deploy_convex_ethplus_eth.ts @@ -4,7 +4,7 @@ import { getChainId } from '../../../../common/blockchain-utils' import { networkConfig } from '../../../../common/configuration' import { expect } from 'chai' import { ONE_ADDRESS, CollateralStatus } from '../../../../common/constants' -import { bn } from '../../../../common/numbers' +import { bn, fp } from '../../../../common/numbers' import { getDeploymentFile, getAssetCollDeploymentFilename, @@ -13,7 +13,6 @@ import { fileExists, } from '../../common' import { CurveAppreciatingRTokenSelfReferentialCollateral } from '../../../../typechain' -import { revenueHiding } from '../../utils' import { CurvePoolType, DEFAULT_THRESHOLD, @@ -83,7 +82,7 @@ async function main() { defaultThreshold: DEFAULT_THRESHOLD.add(WETH_ORACLE_ERROR), delayUntilDefault: DELAY_UNTIL_DEFAULT, // 72h }, - revenueHiding.toString(), + fp('1e-3').toString(), { nTokens: 2, curvePool: ETHPLUS_BP_POOL, diff --git a/scripts/deployment/phase2-assets/collaterals/deploy_convex_rToken_metapool_plugin.ts b/scripts/deployment/phase2-assets/collaterals/deploy_convex_rToken_metapool_plugin.ts index b382962e58..2356c4dfea 100644 --- a/scripts/deployment/phase2-assets/collaterals/deploy_convex_rToken_metapool_plugin.ts +++ b/scripts/deployment/phase2-assets/collaterals/deploy_convex_rToken_metapool_plugin.ts @@ -9,7 +9,6 @@ import { getDeploymentFile, getAssetCollDeploymentFilename, IAssetCollDeployments, - IDeployments, getDeploymentFilename, fileExists, } from '../../common' @@ -53,7 +52,6 @@ async function main() { if (!fileExists(phase1File)) { throw new Error(`${phase1File} doesn't exist yet. Run phase 1`) } - const deployments = getDeploymentFile(phase1File) // Check previous step completed const assetCollDeploymentFilename = getAssetCollDeploymentFilename(chainId) diff --git a/scripts/deployment/phase2-assets/collaterals/deploy_convex_stable_metapool_plugin.ts b/scripts/deployment/phase2-assets/collaterals/deploy_convex_stable_metapool_plugin.ts index 6727ff25d7..de99d2885b 100644 --- a/scripts/deployment/phase2-assets/collaterals/deploy_convex_stable_metapool_plugin.ts +++ b/scripts/deployment/phase2-assets/collaterals/deploy_convex_stable_metapool_plugin.ts @@ -8,7 +8,6 @@ import { getDeploymentFile, getAssetCollDeploymentFilename, IAssetCollDeployments, - IDeployments, getDeploymentFilename, fileExists, } from '../../common' @@ -59,7 +58,6 @@ async function main() { if (!fileExists(phase1File)) { throw new Error(`${phase1File} doesn't exist yet. Run phase 1`) } - const deployments = getDeploymentFile(phase1File) // Check previous step completed const assetCollDeploymentFilename = getAssetCollDeploymentFilename(chainId) diff --git a/scripts/deployment/phase2-assets/collaterals/deploy_curve_stable_plugin.ts b/scripts/deployment/phase2-assets/collaterals/deploy_curve_stable_plugin.ts index 6b9f415d01..15b55e069a 100644 --- a/scripts/deployment/phase2-assets/collaterals/deploy_curve_stable_plugin.ts +++ b/scripts/deployment/phase2-assets/collaterals/deploy_curve_stable_plugin.ts @@ -114,7 +114,7 @@ async function main() { await (await collateral.refresh()).wait() expect(await collateral.status()).to.equal(CollateralStatus.SOUND) - assetCollDeployments.collateral.cvx3Pool = collateral.address + assetCollDeployments.collateral.crv3Pool = collateral.address assetCollDeployments.erc20s.crv3Pool = w3Pool.address deployedCollateral.push(collateral.address.toString()) diff --git a/scripts/deployment/phase2-assets/collaterals/deploy_stakedao_usdc_usdcplus.ts b/scripts/deployment/phase2-assets/collaterals/deploy_stakedao_usdc_usdcplus.ts new file mode 100644 index 0000000000..5ad2551f6d --- /dev/null +++ b/scripts/deployment/phase2-assets/collaterals/deploy_stakedao_usdc_usdcplus.ts @@ -0,0 +1,105 @@ +import fs from 'fs' +import hre from 'hardhat' +import { getChainId } from '../../../../common/blockchain-utils' +import { networkConfig } from '../../../../common/configuration' +import { expect } from 'chai' +import { ONE_ADDRESS, CollateralStatus } from '../../../../common/constants' +import { bn, fp } from '../../../../common/numbers' +import { + getDeploymentFile, + getAssetCollDeploymentFilename, + IAssetCollDeployments, + getDeploymentFilename, + fileExists, +} from '../../common' +import { StakeDAORecursiveCollateral } from '../../../../typechain' +import { + CurvePoolType, + DEFAULT_THRESHOLD, + DELAY_UNTIL_DEFAULT, + USDC_USDCPLUS_GAUGE, + USDC_USDCPLUS_POOL, + USDC_USDCPLUS_LP_TOKEN, + USDC_USD_FEED, + USDC_ORACLE_TIMEOUT, + USDC_ORACLE_ERROR, + MAX_TRADE_VOL, + PRICE_TIMEOUT, +} from '../../../../test/plugins/individual-collateral/curve/constants' + +// This file specifically deploys StakeDAORecursiveCollateral Plugin for USDC/USDC+ + +async function main() { + // ==== Read Configuration ==== + const [deployer] = await hre.ethers.getSigners() + + const chainId = await getChainId(hre) + + console.log(`Deploying StakeDAORecursiveCollateral to network ${hre.network.name} (${chainId}) + with burner account: ${deployer.address}`) + + if (!networkConfig[chainId]) { + throw new Error(`Missing network configuration for ${hre.network.name}`) + } + + // Get phase1 deployment + const phase1File = getDeploymentFilename(chainId) + if (!fileExists(phase1File)) { + throw new Error(`${phase1File} doesn't exist yet. Run phase 1`) + } + + // Check previous step completed + const assetCollDeploymentFilename = getAssetCollDeploymentFilename(chainId) + const assetCollDeployments = getDeploymentFile(assetCollDeploymentFilename) + + const deployedCollateral: string[] = [] + + /******** Deploy StakeDAO Recursive RToken Collateral for USDC/USDC+ **************************/ + + const CollateralFactory = await hre.ethers.getContractFactory('StakeDAORecursiveCollateral') + + const collateral = await CollateralFactory.connect(deployer).deploy( + { + erc20: USDC_USDCPLUS_GAUGE, + targetName: hre.ethers.utils.formatBytes32String('USD'), + priceTimeout: PRICE_TIMEOUT, + chainlinkFeed: ONE_ADDRESS, + oracleError: bn('1'), + oracleTimeout: bn('1'), + maxTradeVolume: MAX_TRADE_VOL, + defaultThreshold: DEFAULT_THRESHOLD.add(USDC_ORACLE_ERROR), + delayUntilDefault: DELAY_UNTIL_DEFAULT, // 72h + }, + fp('1e-4'), // backtest to confirm: 0.01% since pool virtual price will probably decrease + { + nTokens: 2, + curvePool: USDC_USDCPLUS_POOL, + poolType: CurvePoolType.Plain, + feeds: [[USDC_USD_FEED], [ONE_ADDRESS]], + oracleTimeouts: [[USDC_ORACLE_TIMEOUT], [bn('1')]], + oracleErrors: [[USDC_ORACLE_ERROR], [bn('1')]], + lpToken: USDC_USDCPLUS_LP_TOKEN, + } + ) + await collateral.deployed() + await (await collateral.refresh()).wait() + expect(await collateral.status()).to.equal(CollateralStatus.SOUND) + + console.log( + `Deployed StakeDAO Recursive Collateral to ${hre.network.name} (${chainId}): ${collateral.address}` + ) + + assetCollDeployments.collateral.sdUSDCUSDCPlus = collateral.address + deployedCollateral.push(collateral.address.toString()) + + fs.writeFileSync(assetCollDeploymentFilename, JSON.stringify(assetCollDeployments, null, 2)) + + console.log(`Deployed collateral to ${hre.network.name} (${chainId}) + New deployments: ${deployedCollateral} + Deployment file: ${assetCollDeploymentFilename}`) +} + +main().catch((error) => { + console.error(error) + process.exitCode = 1 +}) diff --git a/scripts/deployment/phase2-assets/collaterals/deploy_stargate_usdc_collateral.ts b/scripts/deployment/phase2-assets/collaterals/deploy_stargate_usdc_collateral.ts index dfd837767f..301e15b2ab 100644 --- a/scripts/deployment/phase2-assets/collaterals/deploy_stargate_usdc_collateral.ts +++ b/scripts/deployment/phase2-assets/collaterals/deploy_stargate_usdc_collateral.ts @@ -57,6 +57,7 @@ async function main() { let oracleError = fp('0.0025') if (chainIdKey == '8453') { + throw new Error('deprecated; no pure USDC market available') USDC_NAME = 'USDbC' name = 'Wrapped Stargate USDbC' symbol = 'wsgUSDbC' diff --git a/scripts/deployment/utils.ts b/scripts/deployment/utils.ts index e2d68af55c..5abd9ecb5f 100644 --- a/scripts/deployment/utils.ts +++ b/scripts/deployment/utils.ts @@ -115,21 +115,20 @@ export async function verifyContract( if (baseL2Chains.includes(hre.network.name)) { const BASESCAN_API_KEY = useEnv('BASESCAN_API_KEY') // Base L2 - url = `${getCustomVerificationURL( + url = `${getVerificationURL( chainId - )}/?module=contract&action=getsourcecode&address=${address}&apikey=${BASESCAN_API_KEY}` + )}?module=contract&action=getsourcecode&address=${address}&apikey=${BASESCAN_API_KEY}` } else if (arbitrumL2Chains.includes(hre.network.name)) { const ARBISCAN_API_KEY = useEnv('ARBISCAN_API_KEY') // Arbitrum L2 - url = `${getCustomVerificationURL( + url = `${getVerificationURL( chainId - )}/?module=contract&action=getsourcecode&address=${address}&apikey=${ARBISCAN_API_KEY}` + )}?module=contract&action=getsourcecode&address=${address}&apikey=${ARBISCAN_API_KEY}` } else { // Ethereum - url = `${getEtherscanBaseURL( - chainId, - true - )}/api/?module=contract&action=getsourcecode&address=${address}&apikey=${ETHERSCAN_API_KEY}` + url = `${getVerificationURL( + chainId + )}/api?module=contract&action=getsourcecode&address=${address}&apikey=${ETHERSCAN_API_KEY}` } // Check to see if already verified @@ -154,7 +153,7 @@ export async function verifyContract( } catch (e) { console.log( `IMPORTANT: failed to verify ${contract}. - ${getEtherscanBaseURL(chainId)}/address/${address}#code`, + ${getVerificationURL(chainId)}/address/${address}#code`, e ) } @@ -163,14 +162,9 @@ export async function verifyContract( } } -export const getEtherscanBaseURL = (chainId: number, api = false) => { - let prefix: string - if (api) prefix = chainId == 1 ? 'api.' : `api-${hre.network.name}.` - else prefix = chainId == 1 ? '' : `${hre.network.name}.` - return `https://${prefix}etherscan.io` -} +export const getVerificationURL = (chainId: number) => { + if (chainId == 1) return 'https://api.etherscan.io' -export const getCustomVerificationURL = (chainId: number) => { // For Base, get URL from HH config const chainConfig = hre.config.etherscan.customChains.find((chain) => chain.chainId == chainId) if (!chainConfig || !chainConfig.urls) { @@ -188,10 +182,9 @@ export const getEmptyDeployment = (): IDeployments => { }, tradingLib: '', basketLib: '', - facets: { actFacet: '', readFacet: '' }, + facets: { actFacet: '', readFacet: '', maxIssuableFacet: '' }, facade: '', facadeWriteLib: '', - cvxMiningLib: '', facadeWrite: '', deployer: '', rsrAsset: '', diff --git a/scripts/refresh-whales.ts b/scripts/refresh-whales.ts new file mode 100644 index 0000000000..5f170ae066 --- /dev/null +++ b/scripts/refresh-whales.ts @@ -0,0 +1,158 @@ +import hre from 'hardhat' +import { getChainId } from '../common/blockchain-utils' +import { ITokens, ITokensKeys, networkConfig } from '#/common/configuration' +import { whileImpersonating } from '#/utils/impersonation' +import axios from "axios"; +import * as cheerio from "cheerio"; +import { NetworkWhales, RTOKENS, getWhalesFile, getWhalesFileName } from './whalesConfig'; +import fs from 'fs' +import { useEnv } from '#/utils/env'; + +// set to true to force a refresh of all whales +const FORCE_REFRESH = useEnv('FORCE_WHALE_REFRESH'); +const BASESCAN_API_KEY = useEnv('BASESCAN_API_KEY') +const FORK_NETWORK = useEnv('FORK_NETWORK') + +const SCANNER_URLS: {[key: string]: string} = { + 'mainnet': 'etherscan.io', + 'base': 'basescan.org' +} + +const getstRSRs = async (rTokens: string[]) => { + const strsrs: string[] = [] + for (let i = 0; i < rTokens.length; i++) { + const rToken = rTokens[i] + const rTokenContract = await hre.ethers.getContractAt('RTokenP1', rToken) + // lazy way to skip rtokens that are bridged + try { + const mainAddress = await rTokenContract.main() + const main = await hre.ethers.getContractAt('IMain', mainAddress) + strsrs.push(await main.stRSR()) + } catch {} + } + return strsrs +} + +async function main() { + const chainId = await getChainId(hre) + + // ********** Read config ********** + if (!networkConfig[chainId]) { + throw new Error(`Missing network configuration for ${hre.network.name}`) + } + console.log('Refreshing whales for network', chainId, hre.network.name, FORK_NETWORK) + + const rTokens = RTOKENS[chainId] + const stRSRs = await getstRSRs(rTokens) + + const whalesFile = getWhalesFileName(chainId) + const whales: NetworkWhales = getWhalesFile(chainId) + + const isGoodWhale = (whale: string) => { + return !stRSRs.includes(whale) + } + + const getBigWhale = async (token: string) => { + const ethUrl = `https://${SCANNER_URLS[FORK_NETWORK]}/token/generic-tokenholders2?m=light&a=${token}&p=1` + // const response = await axios.get(ethUrl); + + if (FORK_NETWORK === 'mainnet') { + const response = await axios.get(ethUrl); + const selector = cheerio.load(response.data); + let found = false; + let i = 0; + let whale = ""; + while (!found) { + whale = selector(selector("tbody > tr")[i]).find("td > div > .link-secondary")[0].attribs['data-clipboard-text']; + if (isGoodWhale(whale)) { + found = true; + break; + } + i++; + } + return whale + } else if (FORK_NETWORK === 'base') { + const response = await fetch(ethUrl, { + "headers": { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", + "accept-language": "en-US,en;q=0.9", + "cache-control": "max-age=0", + "priority": "u=0, i", + "sec-ch-ua": "\"Chromium\";v=\"124\", \"Google Chrome\";v=\"124\", \"Not-A.Brand\";v=\"99\"", + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": "\"macOS\"", + "sec-fetch-dest": "document", + "sec-fetch-mode": "navigate", + "sec-fetch-site": "none", + "sec-fetch-user": "?1", + "upgrade-insecure-requests": "1" + }, + "referrerPolicy": "strict-origin-when-cross-origin", + "body": null, + "method": "GET", + "mode": "cors", + "credentials": "include" + }); + const selector = cheerio.load(await response.text()); + let found = false; + let i = 0; + let whale = ""; + while (!found) { + whale = selector(selector("tbody > tr")[i]).find("td > span > a")[0].attribs['href'].split('?a=')[1]; + if (isGoodWhale(whale)) { + found = true; + break; + } + i++; + } + return whale; + } else { + throw new Error('Invalid network') + } + // TODO: make sure that the selector is ok to use + // example: if the token is RSR, we don't want an stRSR to be the whale + } + + const refreshWhale = async (tokenAddress: string) => { + let tokenWhale = whales.tokens[tokenAddress] + let lastUpdated = whales.lastUpdated[tokenAddress] + // only get a big whale if the whale is not already set or if it was last updated more than 1 day ago + if (!FORCE_REFRESH && tokenWhale && lastUpdated && new Date().getTime() - new Date(lastUpdated).getTime() < 86400000) { + console.log('Whale already set for', tokenAddress, 'skipping...') + return + } + console.log('Getting whale for', tokenAddress) + try { + const bigWhale = await getBigWhale(tokenAddress) + // FIX THIS + whales.tokens[tokenAddress] = bigWhale + whales.lastUpdated[tokenAddress] = new Date().toISOString() + fs.writeFileSync(whalesFile, JSON.stringify(whales, null, 2)) + console.log(`Whale ${bigWhale} updated for`, tokenAddress) + } catch (error) { + console.error('Error getting whale for', tokenAddress, error) + } + } + + // ERC20 Collaterals + const tokens: ITokensKeys = Object.keys(networkConfig[chainId].tokens) as ITokensKeys + for (let i = 0; i < tokens.length; i++) { + let tokenAddress = networkConfig[chainId].tokens[tokens[i]]!.toLowerCase() + await refreshWhale(tokenAddress) + } + + // RTokens + for (let i = 0; i < rTokens.length; i++) { + let tokenAddress = rTokens[i] + await refreshWhale(tokenAddress) + } + + console.log('All whales updated for network', chainId) +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) \ No newline at end of file diff --git a/scripts/verification/6_verify_collateral.ts b/scripts/verification/6_verify_collateral.ts index a750f337bd..4a2f582ce9 100644 --- a/scripts/verification/6_verify_collateral.ts +++ b/scripts/verification/6_verify_collateral.ts @@ -69,13 +69,13 @@ async function main() { if (baseL2Chains.includes(hre.network.name)) { await verifyContract( chainId, - deployments.collateral.USDbC, + deployments.collateral.USDC, [ { priceTimeout: priceTimeout.toString(), chainlinkFeed: networkConfig[chainId].chainlinkFeeds.USDC, oracleError: usdcOracleError.toString(), - erc20: networkConfig[chainId].tokens.USDbC, + erc20: networkConfig[chainId].tokens.USDC, maxTradeVolume: fp('1e6').toString(), // $1m, oracleTimeout: usdcOracleTimeout, targetName: hre.ethers.utils.formatBytes32String('USD'), @@ -87,7 +87,7 @@ async function main() { ) } - if (!arbitrumL2Chains.includes(hre.network.name)) { + if (!arbitrumL2Chains.includes(hre.network.name) && !baseL2Chains.includes(hre.network.name)) { /******** Verify StaticATokenLM - aDAI **************************/ // Get AToken to retrieve name and symbol const aToken: ATokenMock = ( @@ -106,7 +106,7 @@ async function main() { 'Static ' + (await aToken.name()), 's' + (await aToken.symbol()), ], - 'contracts/plugins/assets/aave/vendor/StaticATokenLM.sol:StaticATokenLM' + 'contracts/plugins/assets/aave/StaticATokenLM.sol:StaticATokenLM' ) /******** Verify ATokenFiatCollateral - aDAI **************************/ await verifyContract( @@ -240,28 +240,6 @@ async function main() { ], 'contracts/plugins/assets/SelfReferentialCollateral.sol:SelfReferentialCollateral' ) - - /********************** Verify EURFiatCollateral - EURT ****************************************/ - await verifyContract( - chainId, - deployments.collateral.EURT, - [ - { - priceTimeout: priceTimeout.toString(), - chainlinkFeed: networkConfig[chainId].chainlinkFeeds.EURT, - oracleError: fp('0.02').toString(), // 2% - erc20: networkConfig[chainId].tokens.EURT, - maxTradeVolume: fp('1e6').toString(), // $1m, - oracleTimeout: '86400', // 24hr - targetName: ethers.utils.formatBytes32String('EUR'), - defaultThreshold: fp('0.03').toString(), // 3% - delayUntilDefault: bn('86400').toString(), // 24h - }, - networkConfig[chainId].chainlinkFeeds.EUR, - '86400', - ], - 'contracts/plugins/assets/EURFiatCollateral.sol:EURFiatCollateral' - ) } } diff --git a/scripts/verification/collateral-plugins/verify_convex_ethplus_eth.ts b/scripts/verification/collateral-plugins/verify_convex_ethplus_eth.ts index 596b1f03c4..93ce97fd68 100644 --- a/scripts/verification/collateral-plugins/verify_convex_ethplus_eth.ts +++ b/scripts/verification/collateral-plugins/verify_convex_ethplus_eth.ts @@ -2,14 +2,13 @@ import hre, { ethers } from 'hardhat' import { getChainId } from '../../../common/blockchain-utils' import { developmentChains, networkConfig } from '../../../common/configuration' import { ONE_ADDRESS } from '../../../common/constants' -import { bn } from '../../../common/numbers' +import { bn, fp } from '../../../common/numbers' import { getDeploymentFile, getAssetCollDeploymentFilename, IAssetCollDeployments, } from '../../deployment/common' import { verifyContract } from '../../deployment/utils' -import { revenueHiding } from '../../deployment/utils' import { CurvePoolType, DEFAULT_THRESHOLD, @@ -69,7 +68,7 @@ async function main() { defaultThreshold: DEFAULT_THRESHOLD.add(WETH_ORACLE_ERROR), // 2% + delayUntilDefault: DELAY_UNTIL_DEFAULT, // 72h }, - revenueHiding.toString(), + fp('1e-3').toString(), { nTokens: 2, curvePool: ETHPLUS_BP_POOL, diff --git a/scripts/verification/collateral-plugins/verify_morpho.ts b/scripts/verification/collateral-plugins/verify_morpho.ts index 4f9e6d832b..7119245c6e 100644 --- a/scripts/verification/collateral-plugins/verify_morpho.ts +++ b/scripts/verification/collateral-plugins/verify_morpho.ts @@ -86,16 +86,16 @@ async function main() { priceTimeout: priceTimeout.toString(), oracleError: combinedBTCWBTCError.toString(), // 0.25% maxTradeVolume: fp('1e6'), // $1m, - oracleTimeout: '3600', // 1 hr + oracleTimeout: '86400', // 24 hr targetName: ethers.utils.formatBytes32String('BTC'), defaultThreshold: fp('0.01').add(combinedBTCWBTCError), // ~3.5% delayUntilDefault: bn('86400'), // 24h - chainlinkFeed: networkConfig[chainId].chainlinkFeeds.BTC!, + chainlinkFeed: networkConfig[chainId].chainlinkFeeds.WBTC!, erc20: await maWBTC.erc20(), }, revenueHiding, - networkConfig[chainId].chainlinkFeeds.WBTC!, - '86400', // 1 hr + networkConfig[chainId].chainlinkFeeds.BTC!, + '3600', // 1 hr ], 'contracts/plugins/assets/morpho-aave/MorphoNonFiatCollateral.sol:MorphoNonFiatCollateral' ) diff --git a/scripts/verification/collateral-plugins/verify_sdai.ts b/scripts/verification/collateral-plugins/verify_sdai.ts index 393c6264b3..f34f279849 100644 --- a/scripts/verification/collateral-plugins/verify_sdai.ts +++ b/scripts/verification/collateral-plugins/verify_sdai.ts @@ -7,7 +7,7 @@ import { getAssetCollDeploymentFilename, IAssetCollDeployments, } from '../../deployment/common' -import { priceTimeout, oracleTimeout, verifyContract } from '../../deployment/utils' +import { priceTimeout, verifyContract } from '../../deployment/utils' import { POT } from '../../../test/plugins/individual-collateral/dsr/constants' let deployments: IAssetCollDeployments @@ -37,7 +37,7 @@ async function main() { oracleError: fp('0.0025').toString(), // 0.25% erc20: networkConfig[chainId].tokens.sDAI, maxTradeVolume: fp('1e6').toString(), // $1m, - oracleTimeout: oracleTimeout(chainId, '3600').toString(), // 1 hr + oracleTimeout: '3600', // 1 hr targetName: hre.ethers.utils.formatBytes32String('USD'), defaultThreshold: fp('0.0125').toString(), // 1.25% delayUntilDefault: bn('86400').toString(), // 24h diff --git a/scripts/verification/collateral-plugins/verify_sfrax.ts b/scripts/verification/collateral-plugins/verify_sfrax.ts index 5e4be4fc45..f6fe3a1d6d 100644 --- a/scripts/verification/collateral-plugins/verify_sfrax.ts +++ b/scripts/verification/collateral-plugins/verify_sfrax.ts @@ -7,7 +7,7 @@ import { getAssetCollDeploymentFilename, IAssetCollDeployments, } from '../../deployment/common' -import { priceTimeout, oracleTimeout, verifyContract } from '../../deployment/utils' +import { priceTimeout, verifyContract } from '../../deployment/utils' let deployments: IAssetCollDeployments @@ -36,7 +36,7 @@ async function main() { oracleError: fp('0.01').toString(), // 1% erc20: networkConfig[chainId].tokens.sFRAX, maxTradeVolume: fp('1e6').toString(), // $1m, - oracleTimeout: oracleTimeout(chainId, '3600').toString(), // 1 hr + oracleTimeout: '3600', // 1 hr targetName: hre.ethers.utils.formatBytes32String('USD'), defaultThreshold: fp('0.02').toString(), // 2% delayUntilDefault: bn('86400').toString(), // 24h diff --git a/scripts/verification/collateral-plugins/verify_stakedao_usdc_usdcplus.ts b/scripts/verification/collateral-plugins/verify_stakedao_usdc_usdcplus.ts new file mode 100644 index 0000000000..084df746a2 --- /dev/null +++ b/scripts/verification/collateral-plugins/verify_stakedao_usdc_usdcplus.ts @@ -0,0 +1,80 @@ +import hre, { ethers } from 'hardhat' +import { getChainId } from '../../../common/blockchain-utils' +import { developmentChains, networkConfig } from '../../../common/configuration' +import { ONE_ADDRESS } from '../../../common/constants' +import { bn, fp } from '../../../common/numbers' +import { + getDeploymentFile, + getAssetCollDeploymentFilename, + IAssetCollDeployments, +} from '../../deployment/common' +import { verifyContract } from '../../deployment/utils' +import { + CurvePoolType, + DEFAULT_THRESHOLD, + DELAY_UNTIL_DEFAULT, + USDC_USDCPLUS_POOL, + USDC_USDCPLUS_LP_TOKEN, + USDC_ORACLE_ERROR, + USDC_ORACLE_TIMEOUT, + USDC_USD_FEED, + MAX_TRADE_VOL, + PRICE_TIMEOUT, +} from '../../../test/plugins/individual-collateral/curve/constants' + +let deployments: IAssetCollDeployments + +async function main() { + // ********** Read config ********** + const chainId = await getChainId(hre) + if (!networkConfig[chainId]) { + throw new Error(`Missing network configuration for ${hre.network.name}`) + } + + if (developmentChains.includes(hre.network.name)) { + throw new Error(`Cannot verify contracts for development chain ${hre.network.name}`) + } + + const assetCollDeploymentFilename = getAssetCollDeploymentFilename(chainId) + deployments = getDeploymentFile(assetCollDeploymentFilename) + + const collateral = await ethers.getContractAt( + 'StakeDAORecursiveCollateral', + deployments.collateral.sdUSDCUSDCPlus! + ) + + /******** Verify USDC/USDC+ plugin **************************/ + await verifyContract( + chainId, + deployments.collateral.sdUSDCUSDCPlus, + [ + { + erc20: await collateral.erc20(), + targetName: ethers.utils.formatBytes32String('USD'), + priceTimeout: PRICE_TIMEOUT, + chainlinkFeed: ONE_ADDRESS, + oracleError: bn('1'), + oracleTimeout: bn('1'), + maxTradeVolume: MAX_TRADE_VOL, + defaultThreshold: DEFAULT_THRESHOLD.add(USDC_ORACLE_ERROR), // 2% + + delayUntilDefault: DELAY_UNTIL_DEFAULT, // 72h + }, + fp('1e-4'), // backtest to confirm: 0.01% since pool virtual price will probably decrease + { + nTokens: 2, + curvePool: USDC_USDCPLUS_POOL, + poolType: CurvePoolType.Plain, + feeds: [[USDC_USD_FEED], [ONE_ADDRESS]], + oracleTimeouts: [[USDC_ORACLE_TIMEOUT], [bn('1')]], + oracleErrors: [[USDC_ORACLE_ERROR], [bn('1')]], + lpToken: USDC_USDCPLUS_LP_TOKEN, + }, + ], + 'contracts/plugins/assets/curve/stakedao/StakeDAORecursiveCollateral.sol:StakeDAORecursiveCollateral' + ) +} + +main().catch((error) => { + console.error(error) + process.exitCode = 1 +}) diff --git a/scripts/verification/collateral-plugins/verify_yearn_v2_curve_usdc.ts b/scripts/verification/collateral-plugins/verify_yearn_v2_curve_usdc.ts index 7505cfdb85..b0f8794085 100644 --- a/scripts/verification/collateral-plugins/verify_yearn_v2_curve_usdc.ts +++ b/scripts/verification/collateral-plugins/verify_yearn_v2_curve_usdc.ts @@ -7,7 +7,7 @@ import { getAssetCollDeploymentFilename, IAssetCollDeployments, } from '../../deployment/common' -import { priceTimeout, oracleTimeout, verifyContract } from '../../deployment/utils' +import { priceTimeout, verifyContract } from '../../deployment/utils' import { PRICE_PER_SHARE_HELPER, YVUSDC_LP_TOKEN, @@ -40,7 +40,7 @@ async function main() { oracleError: fp('0.0025').toString(), // not used but can't be empty erc20: networkConfig[chainId].tokens.yvCurveUSDCcrvUSD, maxTradeVolume: fp('1e6').toString(), // $1m, - oracleTimeout: oracleTimeout(chainId, '86400').toString(), // 24hr -- max of all oracleTimeouts + oracleTimeout: '86400', // 24hr -- max of all oracleTimeouts targetName: hre.ethers.utils.formatBytes32String('USD'), defaultThreshold: fp('0.015').toString(), // 1.5% = max oracleError + 1% delayUntilDefault: bn('86400').toString(), // 24h @@ -51,14 +51,11 @@ async function main() { curvePool: YVUSDC_LP_TOKEN, poolType: '0', feeds: [ - networkConfig[chainId].chainlinkFeeds.USDC, - networkConfig[chainId].chainlinkFeeds.crvUSD, + [networkConfig[chainId].chainlinkFeeds.USDC], + [networkConfig[chainId].chainlinkFeeds.crvUSD], ], - oracleTimeouts: [ - oracleTimeout(chainId, '86400').toString(), - oracleTimeout(chainId, '86400').toString(), - ], - oracleErrors: [fp('0.0025').toString(), fp('0.005').toString()], + oracleTimeouts: [['86400'], ['86400']], + oracleErrors: [[fp('0.0025').toString()], [fp('0.005').toString()]], lpToken: YVUSDC_LP_TOKEN, }, PRICE_PER_SHARE_HELPER, diff --git a/scripts/verify_etherscan.ts b/scripts/verify_etherscan.ts index 550498eaff..d3fed82f61 100644 --- a/scripts/verify_etherscan.ts +++ b/scripts/verify_etherscan.ts @@ -63,6 +63,7 @@ async function main() { 'collateral-plugins/verify_curve_stable.ts', 'collateral-plugins/verify_curve_stable_metapool.ts', 'collateral-plugins/verify_curve_stable_rtoken_metapool.ts', + 'collateral-plugins/verify_stakedao_usdc_usdcplus.ts', 'collateral-plugins/verify_cusdcv3.ts', 'collateral-plugins/verify_reth.ts', 'collateral-plugins/verify_wsteth.ts', @@ -71,7 +72,6 @@ async function main() { 'collateral-plugins/verify_morpho.ts', 'collateral-plugins/verify_aave_v3_usdc.ts', 'collateral-plugins/verify_yearn_v2_curve_usdc.ts', - 'collateral-plugins/verify_yearn_v2_curve_usdp.ts', 'collateral-plugins/verify_sfrax.ts', 'collateral-plugins/verify_sfrax_eth.ts', 'collateral-plugins/verify_steakusdc.ts', @@ -80,10 +80,10 @@ async function main() { } else if (chainId == '8453' || chainId == '84531') { // Base L2 chains scripts.push( - 'collateral-plugins/verify_cbeth.ts', - 'collateral-plugins/verify_cusdbcv3.ts', + 'collateral-plugins/verify_cusdcv3.ts', 'collateral-plugins/verify_aave_v3_usdc.ts', - 'collateral-plugins/verify_stargate_usdc', + 'collateral-plugins/verify_wsteth.ts', + 'collateral-plugins/verify_cbeth.ts', 'assets/verify_stg.ts' ) } else if (chainId == '42161' || chainId == '421614') { diff --git a/scripts/whalesConfig.ts b/scripts/whalesConfig.ts new file mode 100644 index 0000000000..1adf923ba4 --- /dev/null +++ b/scripts/whalesConfig.ts @@ -0,0 +1,65 @@ +import { ITokens } from "#/common/configuration" +import fs from "fs" + +export interface Whales { + [key: string]: string +} +export interface Updated { + [key: string]: string +} + +export interface NetworkWhales { + tokens: Whales + lastUpdated: Updated +} + +export interface RTokens { + [key: string]: string[] +} + +export const RTOKENS: RTokens = { + // mainnet + '1': [ + '0xA0d69E286B938e21CBf7E51D71F6A4c8918f482F'.toLowerCase(), // eUSD + '0xE72B141DF173b999AE7c1aDcbF60Cc9833Ce56a8'.toLowerCase(), // ETH+ + '0xaCdf0DBA4B9839b96221a8487e9ca660a48212be'.toLowerCase(), // hyUSD + '0xFc0B1EEf20e4c68B3DCF36c4537Cfa7Ce46CA70b'.toLowerCase(), // USDC+ + '0x0d86883FAf4FfD7aEb116390af37746F45b6f378'.toLowerCase(), // USD3 + '0x78da5799CF427Fee11e9996982F4150eCe7a99A7'.toLowerCase(), // rgUSD + ], + // hardhat + '31337': [ + '0xA0d69E286B938e21CBf7E51D71F6A4c8918f482F'.toLowerCase(), // eUSD + '0xE72B141DF173b999AE7c1aDcbF60Cc9833Ce56a8'.toLowerCase(), // ETH+ + '0xaCdf0DBA4B9839b96221a8487e9ca660a48212be'.toLowerCase(), // hyUSD + '0xFc0B1EEf20e4c68B3DCF36c4537Cfa7Ce46CA70b'.toLowerCase(), // USDC+ + '0x0d86883FAf4FfD7aEb116390af37746F45b6f378'.toLowerCase(), // USD3 + '0x78da5799CF427Fee11e9996982F4150eCe7a99A7'.toLowerCase(), // rgUSD + ], + // base + '8453': [ + '0xCfA3Ef56d303AE4fAabA0592388F19d7C3399FB4'.toLowerCase(), // eUSD + '0xEFb97aaF77993922aC4be4Da8Fbc9A2425322677'.toLowerCase(), // USDC3 + '0x8E5E9DF4F0EA39aE5270e79bbABFCc34203A3470'.toLowerCase(), // rgUSD + '0xCc7FF230365bD730eE4B352cC2492CEdAC49383e'.toLowerCase(), // hyUSD + '0xCb327b99fF831bF8223cCEd12B1338FF3aA322Ff'.toLowerCase(), // bsdETH + '0xfE0D6D83033e313691E96909d2188C150b834285'.toLowerCase(), // iUSDC + '0xC9a3e2B3064c1c0546D3D0edc0A748E9f93Cf18d'.toLowerCase(), // VAYA + ], + // arbitrum + '42161': [ + '0x12275DCB9048680c4Be40942eA4D92c74C63b844'.toLowerCase(), // eUSD + '0x18c14c2d707b2212e17d1579789fc06010cfca23'.toLowerCase(), // ETH+ + '0x96a993f06951b01430523d0d5590192d650ebf3e'.toLowerCase(), // rgUSD + ] +} + +export function getWhalesFileName(chainId: string | number): string { + return `./tasks/validation/whales/whales_${chainId}.json` +} + +export function getWhalesFile(chainId: string | number): NetworkWhales { + const whalesFile = getWhalesFileName(chainId) + const whales: NetworkWhales = JSON.parse(fs.readFileSync(whalesFile, 'utf8')) + return whales +} \ No newline at end of file diff --git a/tasks/deployment/create-deployer-registry.ts b/tasks/deployment/create-deployer-registry.ts index 125510b071..bdaaf019c0 100644 --- a/tasks/deployment/create-deployer-registry.ts +++ b/tasks/deployment/create-deployer-registry.ts @@ -1,6 +1,6 @@ import { getChainId } from '../../common/blockchain-utils' import { task, types } from 'hardhat/config' -import { DeployerRegistry, IDeployer } from '../../typechain' +import { DeployerRegistry } from '../../typechain' export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' diff --git a/tasks/deployment/deploy-governor-anastasius.ts b/tasks/deployment/deploy-governor-anastasius.ts new file mode 100644 index 0000000000..626e12ed9d --- /dev/null +++ b/tasks/deployment/deploy-governor-anastasius.ts @@ -0,0 +1,43 @@ +import { getChainId } from '../../common/blockchain-utils' +import { task } from 'hardhat/config' +import { bn } from '../../common/numbers' + +task( + 'deploy-governor-anastasius', + 'Deploy an instance of governor anastasius from an existing deployment of Governor Alexios' +) + .addParam('governor', 'The previous governor, must be of type Alexios') + .setAction(async (params, hre) => { + const chainId = await getChainId(hre) + + const oldGovernor = await hre.ethers.getContractAt('Governance', params.governor) + const timelock = await hre.ethers.getContractAt( + 'TimelockController', + await oldGovernor.timelock() + ) + const stRSR = await hre.ethers.getContractAt('StRSRP1Votes', await oldGovernor.token()) + if ((await oldGovernor.name()) != 'Governor Alexios') throw new Error('Alexios only') + + let blocktime = 1 // arbitrum + if (chainId == 1 || chainId == 3 || chainId == 5) blocktime = 12 // mainnet + if (chainId == 8453 || chainId == 84531) blocktime = 2 // base + + const votingDelay = await oldGovernor.votingDelay() + const votingPeriod = await oldGovernor.votingPeriod() + const proposalThresholdVotes = await oldGovernor.proposalThreshold() + const stRSRSupply = await stRSR.totalSupply() + const quorumNumerator = await oldGovernor['quorumNumerator()']() + if (!(await oldGovernor.quorumDenominator()).eq(100)) throw new Error('quorumDenominator wrong') + + const GovernorAnastasiusFactory = await hre.ethers.getContractFactory('Governance') + const governorAnastasius = await GovernorAnastasiusFactory.deploy( + stRSR.address, + timelock.address, + votingDelay.mul(blocktime), + votingPeriod.mul(blocktime), + proposalThresholdVotes.mul(bn('1e8')).div(stRSRSupply), + quorumNumerator + ) + + console.log('Deployed a new Governor Anastasius to: ', governorAnastasius.address) + }) diff --git a/tasks/index.ts b/tasks/index.ts index 91737c1821..b595bfbebc 100644 --- a/tasks/index.ts +++ b/tasks/index.ts @@ -21,9 +21,8 @@ import './deployment/empty-wallet' import './deployment/cancel-tx' import './deployment/sign-msg' import './deployment/get-addresses' +import './deployment/deploy-governor-anastasius' import './upgrades/force-import' import './upgrades/validate-upgrade' -import './testing/mint-tokens' -import './testing/print-invariants' -import './testing/upgrade-checker' -import './testing/tenderly' +import './validation/mint-tokens' +import './validation/proposal-validator' diff --git a/tasks/testing/tenderly.ts b/tasks/testing/tenderly.ts deleted file mode 100644 index 0622a6f68b..0000000000 --- a/tasks/testing/tenderly.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { task } from 'hardhat/config' -import { networkConfig } from '../../common/configuration' -import { getChainId } from '../../common/blockchain-utils' -import { fp } from '#/common/numbers' -import { whileImpersonating } from '#/utils/impersonation' - -task('give-eth', 'Mints ETH to an address on a tenderly fork') - .addParam('address', 'Ethereum address to receive the tokens') - .addParam('rpc', 'The Tenderly RPC endpoint') - .setAction(async (params, hre) => { - const chainId = await getChainId(hre) - - // ********** Read config ********** - if (!networkConfig[chainId]) { - throw new Error(`Missing network configuration for ${hre.network.name}`) - } - - const forkProvider = new hre.ethers.providers.JsonRpcProvider(params.rpc) - - await forkProvider.send('tenderly_setBalance', [ - [params.address], - hre.ethers.utils.hexValue(hre.ethers.utils.parseUnits('10', 'ether').toHexString()), - ]) - - console.log(`10 ETH sent to ${params.address}`) - }) - -task('give-rsr-tenderly', 'Mints RSR to an address on a tenderly fork') - .addParam('address', 'Ethereum address to receive the tokens') - .addParam('rpc', 'The Tenderly RPC endpoint') - .setAction(async (params, hre) => { - const chainId = await getChainId(hre) - - // ********** Read config ********** - if (!networkConfig[chainId]) { - throw new Error(`Missing network configuration for ${hre.network.name}`) - } - - const rsr = await hre.ethers.getContractAt('ERC20Mock', networkConfig[chainId].tokens.RSR!) - - const unsignedTx = await rsr.populateTransaction['transfer'](params.address, fp('100e6')) - const rsrWhale = '0x6bab6EB87Aa5a1e4A8310C73bDAAA8A5dAAd81C1' - const transactionParameters = [ - { - to: rsr.address, - from: rsrWhale, - data: unsignedTx.data, - gas: hre.ethers.utils.hexValue(300000), - gasPrice: hre.ethers.utils.hexValue(1), - value: hre.ethers.utils.hexValue(0), - }, - ] - - const forkProvider = new hre.ethers.providers.JsonRpcProvider(params.rpc) - - await forkProvider.send('tenderly_setBalance', [ - [rsrWhale], - hre.ethers.utils.hexValue(hre.ethers.utils.parseUnits('1', 'ether').toHexString()), - ]) - - const txHash = await forkProvider.send('eth_sendTransaction', transactionParameters) - - console.log(`100m RSR sent to ${params.address}`) - }) diff --git a/tasks/testing/upgrade-checker-utils/upgrades/2_1_0.ts b/tasks/testing/upgrade-checker-utils/upgrades/2_1_0.ts deleted file mode 100644 index c5398e5744..0000000000 --- a/tasks/testing/upgrade-checker-utils/upgrades/2_1_0.ts +++ /dev/null @@ -1,233 +0,0 @@ -import { whileImpersonating } from '#/utils/impersonation' -import { HardhatRuntimeEnvironment } from 'hardhat/types' -import { ProposalBuilder, buildProposal } from '../governance' -import { Proposal } from '#/utils/subgraph' -import { overrideOracle, pushOracleForward } from '../oracles' -import { networkConfig } from '#/common/configuration' -import { recollateralize } from '../rtokens' -import { TradeKind } from '#/common/constants' -import { bn, fp } from '#/common/numbers' -import { advanceBlocks, advanceTime, getLatestBlockTimestamp } from '#/utils/time' -import { LogDescription, Interface } from 'ethers/lib/utils' -import { logToken } from '../logs' -import { QUEUE_START } from '#/common/constants' -import { getTrade } from '#/utils/trades' -import { whales } from '../constants' -import { BigNumber } from 'ethers' - -export default async ( - hre: HardhatRuntimeEnvironment, - rTokenAddress: string, - governorAddress: string -) => { - console.log('\n* * * * * Run checks for release 2.1.0...') - const rToken = await hre.ethers.getContractAt('RTokenP1', rTokenAddress) - const main = await hre.ethers.getContractAt('IMain', await rToken.main()) - const governor = await hre.ethers.getContractAt('Governance', governorAddress) - const timelock = await hre.ethers.getContractAt('TimelockController', await governor.timelock()) - const stRSR = await hre.ethers.getContractAt('StRSRP1Votes', await main.stRSR()) - const basketHandler = await hre.ethers.getContractAt( - 'BasketHandlerP1', - await main.basketHandler() - ) - - // check Broker updates - const broker = await hre.ethers.getContractAt('BrokerP1', await main.broker()) - const preGnosis = await broker.gnosis() - const preTrade = await broker.batchTradeImplementation() - - const gnosisFactory = await hre.ethers.getContractFactory('EasyAuction') - const newGnosis = await gnosisFactory.deploy() - const tradeFactory = await hre.ethers.getContractFactory('GnosisTrade') - const newTrade = await tradeFactory.deploy() - - await whileImpersonating(hre, timelock.address, async (govSigner) => { - await broker.connect(govSigner).setGnosis(newGnosis.address) - await broker.connect(govSigner).setBatchTradeImplementation(newTrade.address) - }) - - const postGnosis = await broker.gnosis() - const postTrade = await broker.batchTradeImplementation() - - if (postGnosis != newGnosis.address) { - throw new Error(`setGnosis() failure: received: ${postGnosis} / expected: ${newGnosis.address}`) - } - - if (postTrade != newTrade.address) { - throw new Error( - `setBatchTradeImplementation() failure: received: ${postTrade} / expected: ${newTrade.address}` - ) - } - - await whileImpersonating(hre, timelock.address, async (govSigner) => { - await broker.connect(govSigner).setGnosis(preGnosis) - await broker.connect(govSigner).setBatchTradeImplementation(preTrade) - }) - - // check stRSR updates - // if these calls succeed, then the functions exist - await stRSR.getDraftRSR() - await stRSR.getStakeRSR() - await stRSR.getTotalDrafts() - - /* - Verify broker disable bug is gone - */ - await whileImpersonating(hre, timelock.address, async (govSigner) => { - await basketHandler - .connect(govSigner) - .setBackupConfig(hre.ethers.utils.formatBytes32String('USD'), bn(1), [ - networkConfig['1'].tokens.USDT!, - ]) - }) - - const ar = await hre.ethers.getContractAt('AssetRegistryP1', await main.assetRegistry()) - const backingManager = await hre.ethers.getContractAt( - 'BackingManagerP1', - await main.backingManager() - ) - const usdcCollat = await ar.toColl(networkConfig['1'].tokens.USDC!) - const usdc = await hre.ethers.getContractAt('FiatCollateral', usdcCollat) - const oracle = await overrideOracle(hre, await usdc.chainlinkFeed()) - const lastPrice = await oracle.latestAnswer() - await oracle.updateAnswer(lastPrice.mul(90).div(100)) - await ar.refresh() - - // default - await advanceTime(hre, 60 * 60 * 25) - await advanceBlocks(hre, 5 * 60 * 25) - - // push other oracles forward - console.log(`\nPushing some oracles forward for RToken ${rTokenAddress}...`) - const registry = await ar.getRegistry() - for (const asset of registry.assets) { - const assetContract = await hre.ethers.getContractAt('TestIAsset', asset) - const erc20 = await assetContract.erc20() - if (!logToken(erc20).includes('USDC')) { - await pushOracleForward(hre, asset) - } - } - - await ar.refresh() - await basketHandler.refreshBasket() - - const tradingDelay = await backingManager.tradingDelay() - await advanceBlocks(hre, tradingDelay / 12 + 1) - await advanceTime(hre, tradingDelay + 1) - - const iface: Interface = backingManager.interface - - // do first trade as a bad trade - // buy half of the auction for the absolute minimum price - - console.log('\n* * * * * Try to break broker...') - const r = await backingManager.rebalance(TradeKind.BATCH_AUCTION) - const resp = await r.wait() - for (const event of resp.events!) { - let parsedLog: LogDescription | undefined - try { - parsedLog = iface.parseLog(event) - } catch {} - if (parsedLog && parsedLog.name == 'TradeStarted') { - console.log( - `\n====== Trade Started: sell ${logToken(parsedLog.args.sell)} / buy ${logToken( - parsedLog.args.buy - )} ======\n\tmbuyAmount: ${parsedLog.args.minBuyAmount}\n\tsellAmount: ${ - parsedLog.args.sellAmount - }` - ) - // - // run trade - const tradeToken = parsedLog.args.sell - const trade = await getTrade(hre, backingManager, tradeToken) - const buyTokenAddress = await trade.buy() - console.log(`Running trade: sell ${logToken(tradeToken)} for ${logToken(buyTokenAddress)}...`) - const endTime = await trade.endTime() - const worstPrice = await trade.worstCasePrice() // trade.buy() per trade.sell() - const auctionId = await trade.auctionId() - - /* - we're only placing a half bid - */ - const sellAmount = (await trade.initBal()).div(2) - - const sellToken = await hre.ethers.getContractAt('ERC20Mock', await trade.sell()) - const sellDecimals = await sellToken.decimals() - const buytoken = await hre.ethers.getContractAt('ERC20Mock', await buyTokenAddress) - const buyDecimals = await buytoken.decimals() - let buyAmount = sellAmount.mul(worstPrice).div(fp('1')) - if (buyDecimals > sellDecimals) { - buyAmount = buyAmount.mul(bn(10 ** (buyDecimals - sellDecimals))) - } else if (sellDecimals > buyDecimals) { - buyAmount = buyAmount.div(bn(10 ** (sellDecimals - buyDecimals))) - } - - buyAmount = buyAmount.add(1) // need 1 wei to be at min price - - const gnosis = await hre.ethers.getContractAt('EasyAuction', await trade.gnosis()) - await whileImpersonating(hre, whales[buyTokenAddress.toLowerCase()], async (whale) => { - const sellToken = await hre.ethers.getContractAt('ERC20Mock', buyTokenAddress) - let repeat = true - while (repeat) { - try { - await sellToken.connect(whale).approve(gnosis.address, 0) - await sellToken.connect(whale).approve(gnosis.address, buyAmount) - await gnosis - .connect(whale) - .placeSellOrders( - auctionId, - [sellAmount], - [buyAmount], - [QUEUE_START], - hre.ethers.constants.HashZero - ) - repeat = false - } catch (e) { - console.log(e) - buyAmount = buyAmount.add(1) - console.log('Trying again...') - } - } - }) - - const lastTimestamp = await getLatestBlockTimestamp(hre) - await advanceTime(hre, BigNumber.from(endTime).sub(lastTimestamp).toString()) - await backingManager.settleTrade(tradeToken) - console.log(`Settled trade for ${logToken(buyTokenAddress)}.`) - } - } - - console.log('\n* * * * * Broker did not break!') - - await recollateralize(hre, rTokenAddress) - - console.log('\n2.1.0 check succeeded!') -} - -export const proposal_2_1_0: ProposalBuilder = async ( - hre: HardhatRuntimeEnvironment, - rTokenAddress: string -): Promise => { - const rToken = await hre.ethers.getContractAt('RTokenP1', rTokenAddress) - const main = await hre.ethers.getContractAt('IMain', await rToken.main()) - const broker = await hre.ethers.getContractAt('BrokerP1', await main.broker()) - const stRSR = await hre.ethers.getContractAt('StRSRP1Votes', await main.stRSR()) - const basketHandler = await hre.ethers.getContractAt( - 'BasketHandlerP1', - await main.basketHandler() - ) - - const txs = [ - await broker.populateTransaction.upgradeTo('0x89209a52d085D975b14555F3e828F43fb7EaF3B7'), - await stRSR.populateTransaction.upgradeTo('0xfDa8C62d86E426D5fB653B6c44a455Bb657b693f'), - await basketHandler.populateTransaction.upgradeTo('0x5c13b3b6f40aD4bF7aa4793F844BA24E85482030'), - await rToken.populateTransaction.upgradeTo('0x5643D5AC6b79ae8467Cf2F416da6D465d8e7D9C1'), - await broker.populateTransaction.setBatchTradeImplementation( - '0xAd4B0B11B041BB1342fEA16fc9c12Ef2a6443439' - ), - ] - - const description = 'Upgrade Broker implementation and set new trade plugin' - - return buildProposal(txs, description) -} diff --git a/tasks/testing/upgrade-checker-utils/upgrades/3_0_0.ts b/tasks/testing/upgrade-checker-utils/upgrades/3_0_0.ts deleted file mode 100644 index 82e7892e64..0000000000 --- a/tasks/testing/upgrade-checker-utils/upgrades/3_0_0.ts +++ /dev/null @@ -1,464 +0,0 @@ -import { HardhatRuntimeEnvironment } from 'hardhat/types' -import { expect } from 'chai' -import { ProposalBuilder, buildProposal } from '../governance' -import { Proposal } from '#/utils/subgraph' -import { networkConfig } from '#/common/configuration' -import { bn, fp, toBNDecimals } from '#/common/numbers' -import { CollateralStatus, TradeKind, ZERO_ADDRESS } from '#/common/constants' -import { pushOraclesForward, setOraclePrice } from '../oracles' -import { whileImpersonating } from '#/utils/impersonation' -import { whales } from '../constants' -import { getTokens, runDutchTrade } from '../trades' -import { EURFiatCollateral, MockV3Aggregator } from '../../../../typechain' -import { - advanceTime, - advanceToTimestamp, - getLatestBlockTimestamp, - setNextBlockTimestamp, -} from '#/utils/time' - -export default async ( - hre: HardhatRuntimeEnvironment, - rTokenAddress: string, - governorAddress: string -) => { - console.log('\n* * * * * Run checks for release 3.0.0...') - const [tester] = await hre.ethers.getSigners() - const rToken = await hre.ethers.getContractAt('RTokenP1', rTokenAddress) - const main = await hre.ethers.getContractAt('IMain', await rToken.main()) - const governor = await hre.ethers.getContractAt('Governance', governorAddress) - const timelockAddress = await governor.timelock() - const timelock = await hre.ethers.getContractAt('TimelockController', timelockAddress) - - const assetRegistry = await hre.ethers.getContractAt( - 'AssetRegistryP1', - await main.assetRegistry() - ) - const basketHandler = await hre.ethers.getContractAt( - 'BasketHandlerP1', - await main.basketHandler() - ) - const backingManager = await hre.ethers.getContractAt( - 'BackingManagerP1', - await main.backingManager() - ) - const broker = await hre.ethers.getContractAt('BrokerP1', await main.broker()) - const furnace = await hre.ethers.getContractAt('FurnaceP1', await main.furnace()) - const rsrTrader = await hre.ethers.getContractAt('RevenueTraderP1', await main.rsrTrader()) - const stRSR = await hre.ethers.getContractAt('StRSRP1Votes', await main.stRSR()) - const rsr = await hre.ethers.getContractAt('StRSRP1Votes', await main.rsr()) - - // we pushed the chain forward, so we need to keep the rToken SOUND - await pushOraclesForward(hre, rTokenAddress) - - /* - Asset Registry - new getters - */ - const nextTimestamp = (await getLatestBlockTimestamp(hre)) + 10 - await setNextBlockTimestamp(hre, nextTimestamp) - await assetRegistry.refresh() - expect(await assetRegistry.lastRefresh()).to.equal(nextTimestamp) - expect(await assetRegistry.size()).to.equal(16) - console.log(`successfully tested new AssetRegistry getters`) - - /* - New Basket validations - units and weights - */ - const usdcCollat = await assetRegistry.toColl(networkConfig['1'].tokens.USDC!) - const usdcFiatColl = await hre.ethers.getContractAt('FiatCollateral', usdcCollat) - const usdc = await hre.ethers.getContractAt('USDCMock', await usdcFiatColl.erc20()) - - // Attempt to change target weights in basket - await whileImpersonating(hre, timelockAddress, async (tl) => { - await expect( - basketHandler.connect(tl).setPrimeBasket([usdc.address], [fp('20')]) - ).to.be.revertedWith('new target weights') - }) - - // Attempt to change target unit in basket - const eurt = await hre.ethers.getContractAt('ERC20Mock', networkConfig['1'].tokens.EURT!) - const EURFiatCollateralFactory = await hre.ethers.getContractFactory('EURFiatCollateral') - const feedMock = ( - await (await hre.ethers.getContractFactory('MockV3Aggregator')).deploy(8, bn('1e8')) - ) - const eurFiatCollateral = await EURFiatCollateralFactory.deploy( - { - priceTimeout: bn('604800'), - chainlinkFeed: feedMock.address, - oracleError: fp('0.01'), - erc20: eurt.address, - maxTradeVolume: fp('1000'), - oracleTimeout: await usdcFiatColl.oracleTimeout(), - targetName: hre.ethers.utils.formatBytes32String('EUR'), - defaultThreshold: fp('0.01'), - delayUntilDefault: bn('86400'), - }, - feedMock.address, - await usdcFiatColl.oracleTimeout() - ) - await eurFiatCollateral.refresh() - - // Attempt to set basket with an EUR token - await whileImpersonating(hre, timelockAddress, async (tl) => { - await assetRegistry.connect(tl).register(eurFiatCollateral.address) - await expect( - basketHandler.connect(tl).setPrimeBasket([eurt.address], [fp('1')]) - ).to.be.revertedWith('new target weights') - await assetRegistry.connect(tl).unregister(eurFiatCollateral.address) - }) - - console.log(`successfully tested validations of weights and units on basket switch`) - - /* - Main - Pausing issuance and trading - */ - // Can pause/unpause issuance and trading separately - await whileImpersonating(hre, timelockAddress, async (tl) => { - await main.connect(tl).pauseIssuance() - - await expect(rToken.connect(tester).issue(fp('100'))).to.be.revertedWith( - 'frozen or issuance paused' - ) - - await main.connect(tl).unpauseIssuance() - - await expect(rToken.connect(tester).issue(fp('100'))).to.emit(rToken, 'Issuance') - - await main.connect(tl).pauseTrading() - - await expect(backingManager.connect(tester).forwardRevenue([])).to.be.revertedWith( - 'frozen or trading paused' - ) - - await main.connect(tl).unpauseTrading() - - await expect(backingManager.connect(tester).forwardRevenue([])).to.not.be.reverted - }) - - console.log(`successfully tested issuance and trading pause`) - - /* - New getters/setters for auctions - */ - // Auction getters/setters - await whileImpersonating(hre, timelockAddress, async (tl) => { - await broker.connect(tl).enableBatchTrade() - await broker.connect(tl).enableDutchTrade(rsr.address) - }) - expect(await broker.batchTradeDisabled()).to.equal(false) - expect(await broker.dutchTradeDisabled(rsr.address)).to.equal(false) - - console.log(`successfully tested new auction getters/setters`) - - /* - Dust Auctions - */ - console.log(`testing dust auctions...`) - - const minTrade = bn('1e18') - const minTradePrev = await rsrTrader.minTradeVolume() - await whileImpersonating(hre, timelockAddress, async (tl) => { - await broker.connect(tl).setDutchAuctionLength(1800) - await rsrTrader.connect(tl).setMinTradeVolume(minTrade) - }) - await usdcFiatColl.refresh() - - const dustAmount = bn('1e17') - await getTokens(hre, usdc.address, toBNDecimals(dustAmount, 6), tester.address) - await usdc.connect(tester).transfer(rsrTrader.address, toBNDecimals(dustAmount, 6)) - - await expect(rsrTrader.manageTokens([usdc.address], [TradeKind.DUTCH_AUCTION])).to.emit( - rsrTrader, - 'TradeStarted' - ) - - await runDutchTrade(hre, rsrTrader, usdc.address) - - // Restore values - await whileImpersonating(hre, timelockAddress, async (tl) => { - await rsrTrader.connect(tl).setMinTradeVolume(minTradePrev) - await broker.connect(tl).setDutchAuctionLength(0) - }) - - console.log(`succesfully tested dust auctions`) - - /* - Warmup period - */ - - console.log(`testing warmup period...`) - - const usdcChainlinkFeed = await hre.ethers.getContractAt( - 'AggregatorV3Interface', - await usdcFiatColl.chainlinkFeed() - ) - - const roundData = await usdcChainlinkFeed.latestRoundData() - await setOraclePrice(hre, usdcFiatColl.address, bn('0.8e8')) - await assetRegistry.refresh() - expect(await usdcFiatColl.status()).to.equal(CollateralStatus.IFFY) - expect(await basketHandler.status()).to.equal(CollateralStatus.IFFY) - expect(await basketHandler.isReady()).to.equal(false) - - // Restore SOUND - await setOraclePrice(hre, usdcFiatColl.address, roundData.answer) - await assetRegistry.refresh() - - // Still cannot issue - expect(await usdcFiatColl.status()).to.equal(CollateralStatus.SOUND) - expect(await basketHandler.status()).to.equal(CollateralStatus.SOUND) - - // If warmup period defined - if ((await basketHandler.warmupPeriod()) > 0) { - expect(await basketHandler.isReady()).to.equal(false) - await expect(rToken.connect(tester).issue(fp('1'))).to.be.revertedWith('basket not ready') - - // Move post warmup period - await advanceTime(hre, Number(await basketHandler.warmupPeriod()) + 1) - } - - // Can issue now - expect(await usdcFiatColl.status()).to.equal(CollateralStatus.SOUND) - expect(await basketHandler.status()).to.equal(CollateralStatus.SOUND) - expect(await basketHandler.isReady()).to.equal(true) - await expect(rToken.connect(tester).issue(fp('1'))).to.emit(rToken, 'Issuance') - console.log(`succesfully tested warmup period`) - - // we pushed the chain forward, so we need to keep the rToken SOUND - await pushOraclesForward(hre, rTokenAddress) - - /* - Melting occurs when paused - */ - - await whileImpersonating(hre, timelockAddress, async (tl) => { - await main.connect(tl).pauseIssuance() - await main.connect(tl).pauseTrading() - - await furnace.melt() - - await main.connect(tl).unpauseIssuance() - await main.connect(tl).unpauseTrading() - }) - console.log(`successfully tested melting during paused state`) - - /* - Stake and delegate - */ - - console.log(`testing stakeAndDelegate...`) - const stakeAmount = fp('4e6') - await whileImpersonating(hre, whales[networkConfig['1'].tokens.RSR!], async (rsrSigner) => { - expect(await stRSR.delegates(rsrSigner.address)).to.equal(ZERO_ADDRESS) - expect(await stRSR.balanceOf(rsrSigner.address)).to.equal(0) - - await rsr.connect(rsrSigner).approve(stRSR.address, stakeAmount) - await stRSR.connect(rsrSigner).stakeAndDelegate(stakeAmount, rsrSigner.address) - - expect(await stRSR.delegates(rsrSigner.address)).to.equal(rsrSigner.address) - expect(await stRSR.balanceOf(rsrSigner.address)).to.be.gt(0) - }) - console.log(`successfully tested stakeAndDelegate`) - - /* - Withdrawal leak - */ - - console.log(`testing withrawalLeak...`) - - // Decrease withdrawal leak to be able to test with previous stake - const withdrawalLeakPrev = await stRSR.withdrawalLeak() - const withdrawalLeak = withdrawalLeakPrev.eq(bn(0)) ? bn(0) : bn('1e5') - const unstakingDelay = await stRSR.unstakingDelay() - - await whileImpersonating(hre, timelockAddress, async (tl) => { - await stRSR.connect(tl).setWithdrawalLeak(withdrawalLeak) - }) - - await whileImpersonating(hre, whales[networkConfig['1'].tokens.RSR!], async (rsrSigner) => { - const withdrawal = stakeAmount - await stRSR.connect(rsrSigner).unstake(1) - await stRSR.connect(rsrSigner).unstake(withdrawal) - await stRSR.connect(rsrSigner).unstake(1) - - // Move forward past stakingWithdrawalDelay - await advanceToTimestamp(hre, Number(await getLatestBlockTimestamp(hre)) + unstakingDelay) - - // we pushed the chain forward, so we need to keep the rToken SOUND - await pushOraclesForward(hre, rTokenAddress) - - let lastRefresh = await assetRegistry.lastRefresh() - - // Should not refresh if withdrawal leak is applied - await stRSR.connect(rsrSigner).withdraw(rsrSigner.address, 1) - if (withdrawalLeak.gt(bn(0))) { - expect(await assetRegistry.lastRefresh()).to.eq(lastRefresh) - } - - // Should refresh - await stRSR.connect(rsrSigner).withdraw(rsrSigner.address, 2) - expect(await assetRegistry.lastRefresh()).to.be.gt(lastRefresh) - lastRefresh = await assetRegistry.lastRefresh() - - // Should not refresh - await stRSR.connect(rsrSigner).withdraw(rsrSigner.address, 3) - if (withdrawalLeak.gt(bn(0))) { - expect(await assetRegistry.lastRefresh()).to.eq(lastRefresh) - } - }) - - // Restore values - await whileImpersonating(hre, timelockAddress, async (tl) => { - await stRSR.connect(tl).setWithdrawalLeak(withdrawalLeakPrev) - }) - console.log(`successfully tested withrawalLeak`) - - /* - Governance changes - */ - console.log(`testing governance...`) - - const EXECUTOR_ROLE = await timelock.EXECUTOR_ROLE() - expect(await timelock.hasRole(EXECUTOR_ROLE, governor.address)).to.equal(true) - expect(await timelock.hasRole(EXECUTOR_ROLE, ZERO_ADDRESS)).to.equal(false) - - console.log(`successfully tested governance`) - - // we pushed the chain forward, so we need to keep the rToken SOUND - await pushOraclesForward(hre, rTokenAddress) - - console.log('\n3.0.0 check succeeded!') -} - -export const proposal_3_0_0: ProposalBuilder = async ( - hre: HardhatRuntimeEnvironment, - rTokenAddress: string, - governorAddress: string -): Promise => { - const rToken = await hre.ethers.getContractAt('RTokenP1', rTokenAddress) - const main = await hre.ethers.getContractAt('MainP1', await rToken.main()) - const assetRegistry = await hre.ethers.getContractAt( - 'AssetRegistryP1', - await main.assetRegistry() - ) - const backingManager = await hre.ethers.getContractAt( - 'BackingManagerP1', - await main.backingManager() - ) - const basketHandler = await hre.ethers.getContractAt( - 'BasketHandlerP1', - await main.basketHandler() - ) - const broker = await hre.ethers.getContractAt('BrokerP1', await main.broker()) - const distributor = await hre.ethers.getContractAt('DistributorP1', await main.distributor()) - const furnace = await hre.ethers.getContractAt('FurnaceP1', await main.furnace()) - const rsrTrader = await hre.ethers.getContractAt('RevenueTraderP1', await main.rsrTrader()) - const rTokenTrader = await hre.ethers.getContractAt('RevenueTraderP1', await main.rTokenTrader()) - const stRSR = await hre.ethers.getContractAt('StRSRP1Votes', await main.stRSR()) - - const governor = await hre.ethers.getContractAt('Governance', governorAddress) - const timelock = await hre.ethers.getContractAt('TimelockController', await governor.timelock()) - - const mainImplAddr = '0xF5366f67FF66A3CefcB18809a762D5b5931FebF8' - const batchTradeImplAddr = '0xe416Db92A1B27c4e28D5560C1EEC03f7c582F630' - const dutchTradeImplAddr = '0x2387C22727ACb91519b80A15AEf393ad40dFdb2F' - const assetRegImplAddr = '0x773cf50adCF1730964D4A9b664BaEd4b9FFC2450' - const bckMgrImplAddr = '0x0A388FC05AA017b31fb084e43e7aEaFdBc043080' - const bsktHdlImplAddr = '0x5ccca36CbB66a4E4033B08b4F6D7bAc96bA55cDc' - const brokerImplAddr = '0x9A5F8A9bB91a868b7501139eEdB20dC129D28F04' - const distImplAddr = '0x0e8439a17bA5cBb2D9823c03a02566B9dd5d96Ac' - const furnaceImplAddr = '0x99580Fc649c02347eBc7750524CAAe5cAcf9d34c' - const rsrTraderImplAddr = '0x1cCa3FBB11C4b734183f997679d52DeFA74b613A' - const rTokenTraderImplAddr = '0x1cCa3FBB11C4b734183f997679d52DeFA74b613A' - const rTokenImplAddr = '0xb6f01Aa21defA4a4DE33Bed16BcC06cfd23b6A6F' - const stRSRImplAddr = '0xC98eaFc9F249D90e3E35E729e3679DD75A899c10' - - const cUSDCVaultAddr = '0xf579F9885f1AEa0d3F8bE0F18AfED28c92a43022' - const cUSDCVaultCollateralAddr = '0x50a9d529EA175CdE72525Eaa809f5C3c47dAA1bB' - const cUSDTVaultAddr = '0x4Be33630F92661afD646081BC29079A38b879aA0' - const cUSDTVaultCollateralAddr = '0x5757fF814da66a2B4f9D11d48570d742e246CfD9' - const saUSDCAddr = '0x60C384e226b120d93f3e0F4C502957b2B9C32B15' - const aUSDCCollateralAddr = '0x7CD9CA6401f743b38B3B16eA314BbaB8e9c1aC51' - const saUSDTAddr = '0x21fe646D1Ed0733336F2D4d9b2FE67790a6099D9' - const aUSDTCollateralAddr = '0xE39188Ddd4eb27d1D25f5f58cC6A5fD9228EEdeF' - - const RSRAssetAddr = '0x7edD40933DfdA0ecEe1ad3E61a5044962284e1A6' - const TUSDCollateralAddr = '0x7F9999B2C9D310a5f48dfD070eb5129e1e8565E2' - const USDPCollateralAddr = '0x2f98bA77a8ca1c630255c4517b1b3878f6e60C89' - const DAICollateralAddr = '0xf7d1C6eE4C0D84C6B530D53A897daa1E9eB56833' - const USDTCollateralAddr = '0x58D7bF13D3572b08dE5d96373b8097d94B1325ad' - const USDCCollateralAddr = '0xBE9D23040fe22E8Bd8A88BF5101061557355cA04' - const COMPAssetAddr = '0xCFA67f42A0fDe4F0Fb612ea5e66170B0465B84c1' - const stkAAVEAssetAddr = '0x6647c880Eb8F57948AF50aB45fca8FE86C154D24' - const RTokenAssetAddr = '0x70C34352a73b76322cEc6bB965B9fd1a95C77A61' - - // Step 1 - Update implementations - const txs = [ - await assetRegistry.populateTransaction.upgradeTo(assetRegImplAddr), - await backingManager.populateTransaction.upgradeTo(bckMgrImplAddr), - await basketHandler.populateTransaction.upgradeTo(bsktHdlImplAddr), - await broker.populateTransaction.upgradeTo(brokerImplAddr), - await distributor.populateTransaction.upgradeTo(distImplAddr), - await furnace.populateTransaction.upgradeTo(furnaceImplAddr), - await main.populateTransaction.upgradeTo(mainImplAddr), - await rsrTrader.populateTransaction.upgradeTo(rsrTraderImplAddr), - await rTokenTrader.populateTransaction.upgradeTo(rTokenTraderImplAddr), - await rToken.populateTransaction.upgradeTo(rTokenImplAddr), - await stRSR.populateTransaction.upgradeTo(stRSRImplAddr), - ] - - // Step 2 - Cache components - txs.push( - await backingManager.populateTransaction.cacheComponents(), - await distributor.populateTransaction.cacheComponents(), - await rsrTrader.populateTransaction.cacheComponents(), - await rTokenTrader.populateTransaction.cacheComponents() - ) - - // Step 3 - Register and swap assets - txs.push( - await assetRegistry.populateTransaction.register(cUSDCVaultCollateralAddr), - await assetRegistry.populateTransaction.register(cUSDTVaultCollateralAddr), - await assetRegistry.populateTransaction.swapRegistered(aUSDCCollateralAddr), - await assetRegistry.populateTransaction.swapRegistered(aUSDTCollateralAddr), - await assetRegistry.populateTransaction.swapRegistered(RSRAssetAddr), - await assetRegistry.populateTransaction.swapRegistered(TUSDCollateralAddr), - await assetRegistry.populateTransaction.swapRegistered(USDPCollateralAddr), - await assetRegistry.populateTransaction.swapRegistered(DAICollateralAddr), - await assetRegistry.populateTransaction.swapRegistered(USDTCollateralAddr), - await assetRegistry.populateTransaction.swapRegistered(USDCCollateralAddr), - await assetRegistry.populateTransaction.swapRegistered(COMPAssetAddr), - await assetRegistry.populateTransaction.swapRegistered(stkAAVEAssetAddr), - await assetRegistry.populateTransaction.swapRegistered(RTokenAssetAddr) - ) - - // Step 4 - Basket change - txs.push( - await basketHandler.populateTransaction.setPrimeBasket( - [cUSDCVaultAddr, cUSDTVaultAddr, saUSDCAddr, saUSDTAddr], - [fp('0.25'), fp('0.25'), fp('0.25'), fp('0.25')] - ), - await basketHandler.populateTransaction.refreshBasket() - ) - - // Step 5 - Governance - const EXECUTOR_ROLE = await timelock.EXECUTOR_ROLE() - txs.push( - await timelock.populateTransaction.grantRole(EXECUTOR_ROLE, governor.address), - await timelock.populateTransaction.revokeRole(EXECUTOR_ROLE, ZERO_ADDRESS) - ) - - // Step 6 - Initializations - txs.push( - await basketHandler.populateTransaction.setWarmupPeriod(900), - await stRSR.populateTransaction.setWithdrawalLeak(bn('5e16')), - await broker.populateTransaction.setBatchTradeImplementation(batchTradeImplAddr), - await broker.populateTransaction.setDutchTradeImplementation(dutchTradeImplAddr), - await broker.populateTransaction.setDutchAuctionLength(1800) - ) - - const description = - 'Upgrade implementations, assets, set trade plugins, config values, and update basket' - - return buildProposal(txs, description) -} diff --git a/tasks/upgrades/validate-upgrade.ts b/tasks/upgrades/validate-upgrade.ts index 21c199e4fb..beceec0786 100644 --- a/tasks/upgrades/validate-upgrade.ts +++ b/tasks/upgrades/validate-upgrade.ts @@ -52,7 +52,15 @@ task('validate-upgrade', 'Validates if upgrade to new version is safe') await validateUpgrade(hre, deployments.implementations.main, 'MainP1') await validateUpgrade(hre, deployments.implementations.components.rToken, 'RTokenP1') - await validateUpgrade(hre, deployments.implementations.components.stRSR, 'StRSRP1Votes') + await validateUpgrade( + hre, + deployments.implementations.components.stRSR, + 'StRSRP1Votes', + undefined, + undefined, + undefined, + true + ) await validateUpgrade( hre, deployments.implementations.components.assetRegistry, @@ -102,7 +110,8 @@ const validateUpgrade = async ( factoryName: string, tradingLibAddress?: string, basketLibAddress?: string, - unsafeAllow?: any[] + unsafeAllow?: any[], + unsafeAllowRenames?: boolean ) => { // Get Contract Factory let contractFactory: ContractFactory @@ -129,6 +138,7 @@ const validateUpgrade = async ( await hre.upgrades.validateUpgrade(prevImplAddress, contractFactory, { kind: 'uups', unsafeAllow, + unsafeAllowRenames, }) console.log( diff --git a/tasks/testing/mint-tokens.ts b/tasks/validation/mint-tokens.ts similarity index 100% rename from tasks/testing/mint-tokens.ts rename to tasks/validation/mint-tokens.ts diff --git a/tasks/testing/print-invariants.ts b/tasks/validation/print-invariants.ts similarity index 100% rename from tasks/testing/print-invariants.ts rename to tasks/validation/print-invariants.ts diff --git a/tasks/validation/proposal-validator.ts b/tasks/validation/proposal-validator.ts new file mode 100644 index 0000000000..72bd613e42 --- /dev/null +++ b/tasks/validation/proposal-validator.ts @@ -0,0 +1,316 @@ +import { task } from 'hardhat/config' +import { networkConfig } from '../../common/configuration' +import { getChainId } from '../../common/blockchain-utils' +import { whileImpersonating } from '#/utils/impersonation' +import { useEnv } from '#/utils/env' +import { expect } from 'chai' +import { fp } from '#/common/numbers' +import { MAX_UINT256, TradeKind } from '#/common/constants' +import { formatEther, formatUnits } from 'ethers/lib/utils' +import { recollateralize, redeemRTokens } from './utils/rtokens' +import { claimRsrRewards } from './utils/rewards' +import { pushOraclesForward } from './utils/oracles' +import { + passProposal, + executeProposal, + proposeUpgrade, + stakeAndDelegateRsr, + moveProposalToActive, + voteProposal, +} from './utils/governance' +import { advanceTime, getLatestBlockNumber } from '#/utils/time' +import { test_proposal } from './test-proposal' +import { HardhatRuntimeEnvironment } from 'hardhat/types' +import { resetFork } from '#/utils/chain' +import fs from 'fs' +import { BigNumber } from 'ethers' +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +import { BasketHandlerP1 } from '@typechain/BasketHandlerP1' +import { RTokenP1 } from '@typechain/RTokenP1' +import { StRSRP1Votes } from '@typechain/StRSRP1Votes' +import { MainP1 } from '@typechain/MainP1' +import { IMain } from '@typechain/IMain' +import { Whales, getWhalesFile } from '#/scripts/whalesConfig' + +interface Params { + proposalid?: string +} + +task('proposal-validator', 'Runs a proposal and confirms can fully rebalance + redeem + mint') + .addParam('proposalid', 'the ID of the governance proposal', undefined) + .setAction(async (params: Params, hre) => { + await resetFork(hre, Number(process.env.FORK_BLOCK)) + + const chainId = await getChainId(hre) + + // make sure config exists + if (!networkConfig[chainId]) { + throw new Error(`Missing network configuration for ${hre.network.name}`) + } + + // only run locally + if (hre.network.name != 'localhost' && hre.network.name != 'hardhat') { + throw new Error('Only run this on a local fork') + } + + // make sure subgraph is configured + if (params.proposalid && !useEnv('SUBGRAPH_URL')) { + throw new Error('SUBGRAPH_URL required for subgraph queries') + } + + console.log(`Network Block: ${await getLatestBlockNumber(hre)}`) + + await hre.run('propose', { + pid: params.proposalid, + }) + + const proposalData = JSON.parse(fs.readFileSync(`./tasks/validation/proposals/proposal-${params.proposalid}.json`, 'utf-8')) + await hre.run('recollateralize', { + rtoken: proposalData.rtoken, + governor: proposalData.governor, + }) + + await hre.run('run-validations', { + rtoken: proposalData.rtoken, + governor: proposalData.governor, + }) + + const rToken = await hre.ethers.getContractAt('IRToken', proposalData.rtoken) + const main = await hre.ethers.getContractAt('IMain', await rToken.main()) + const assetRegistry = await hre.ethers.getContractAt( + 'IAssetRegistry', + await main.assetRegistry() + ) + const basketHandler = await hre.ethers.getContractAt( + 'IBasketHandler', + await main.basketHandler() + ) + await assetRegistry.refresh() + if (!((await basketHandler.status()) == 0)) throw new Error('Basket is not SOUND') + if (!(await basketHandler.fullyCollateralized())) { + throw new Error('Basket is not fully collateralized') + } + console.log('Basket is SOUND and fully collateralized!') + }) + +interface ProposeParams { + pid: string +} + +task('propose', 'propose a gov action') + .addParam('pid', 'the ID of the governance proposal') + .setAction(async (params: ProposeParams, hre) => { + const proposalData = JSON.parse(fs.readFileSync(`./tasks/validation/proposals/proposal-${params.pid}.json`, 'utf-8')) + + const proposal = await proposeUpgrade(hre, proposalData.rtoken, proposalData.governor, proposalData) + + if (proposal.proposalId != params.pid) { + throw new Error(`Proposed Proposal ID does not match expected ID: ${params.pid}`) + } + + await moveProposalToActive(hre, proposalData.rtoken, proposalData.governor, proposal.proposalId) + await voteProposal(hre, proposalData.rtoken, proposalData.governor, proposal.proposalId) + await passProposal(hre, proposalData.governor, proposal.proposalId) + await executeProposal(hre, proposalData.rtoken, proposalData.governor, proposal.proposalId, proposal) + }) + +task('recollateralize') + .addParam('rtoken', 'the address of the RToken being upgraded') + .addParam('governor', 'the address of the OWNER of the RToken being upgraded') + .setAction(async (params, hre) => { + const [tester] = await hre.ethers.getSigners() + const rToken = await hre.ethers.getContractAt('RTokenP1', params.rtoken) + + // 2. Bring back to fully collateralized + const main = await hre.ethers.getContractAt('IMain', await rToken.main()) + const basketHandler = await hre.ethers.getContractAt( + 'BasketHandlerP1', + await main.basketHandler() + ) + const backingManager = await hre.ethers.getContractAt( + 'BackingManagerP1', + await main.backingManager() + ) + // const broker = await hre.ethers.getContractAt('BrokerP1', await main.broker()) + const stRSR = await hre.ethers.getContractAt('StRSRP1Votes', await main.stRSR()) + + /* + recollateralize + */ + await advanceTime(hre, (await backingManager.tradingDelay()) + 1) + await pushOraclesForward(hre, params.rtoken, []) + await recollateralize(hre, rToken.address, TradeKind.DUTCH_AUCTION).catch((e: Error) => { + if (e.message.includes('already collateralized')) { + console.log('Already Collateralized!') + return + } + throw e + }) + if (!(await basketHandler.fullyCollateralized())) throw new Error('Failed to recollateralize') + }) + +task('run-validations', 'Runs all validations') + .addParam('rtoken', 'the address of the RToken being upgraded') + .addParam('governor', 'the address of the OWNER of the RToken being upgraded') + .setAction(async (params, hre) => { + const [tester] = await hre.ethers.getSigners() + const rToken = await hre.ethers.getContractAt('RTokenP1', params.rtoken) + + // 2. Bring back to fully collateralized + const main = await hre.ethers.getContractAt('IMain', await rToken.main()) + const basketHandler = await hre.ethers.getContractAt( + 'BasketHandlerP1', + await main.basketHandler() + ) + const backingManager = await hre.ethers.getContractAt( + 'BackingManagerP1', + await main.backingManager() + ) + const stRSR = await hre.ethers.getContractAt('StRSRP1Votes', await main.stRSR()) + + const chainId = await getChainId(hre) + const whales: Whales = getWhalesFile(chainId).tokens + + /* + redeem + */ + // Give `tester` RTokens from a whale + const redeemAmt = fp('1e4') + await whileImpersonating(hre, whales[params.rtoken.toLowerCase()], async (whaleSigner) => { + await rToken.connect(whaleSigner).transfer(tester.address, redeemAmt) + }) + if (!(await rToken.balanceOf(tester.address)).gte(redeemAmt)) throw new Error('missing R') + + await runCheck_redeem(hre, tester, rToken.address, redeemAmt) + + /* + mint + */ + await runCheck_mint(hre, fp('1e3'), tester, basketHandler, rToken) + + /* + claim rewards + */ + await claimRsrRewards(hre, params.rtoken) + + await pushOraclesForward(hre, params.rtoken, []) + + /* + staking/unstaking + */ + await runCheck_stakeUnstake(hre, tester, rToken, stRSR, main) + }) + +const runCheck_stakeUnstake = async ( + hre: HardhatRuntimeEnvironment, + tester: SignerWithAddress, + rToken: RTokenP1, + stRSR: StRSRP1Votes, + main: IMain +) => { + const chainId = await getChainId(hre) + const whales = getWhalesFile(chainId).tokens + + // get RSR + const stakeAmount = fp('4e6') + const rsr = await hre.ethers.getContractAt('StRSRP1Votes', await main.rsr()) + await whileImpersonating( + hre, + whales[networkConfig['1'].tokens.RSR!.toLowerCase()], + async (rsrSigner) => { + await rsr.connect(rsrSigner).transfer(tester.address, stakeAmount) + } + ) + + const balPrevRSR = await rsr.balanceOf(stRSR.address) + const balPrevStRSR = await stRSR.balanceOf(tester.address) + const testerBal = await rsr.balanceOf(tester.address) + + await stakeAndDelegateRsr(hre, rToken.address, tester.address) + + expect(await rsr.balanceOf(stRSR.address)).to.equal(balPrevRSR.add(testerBal)) + expect(await stRSR.balanceOf(tester.address)).to.be.gt(balPrevStRSR) +} + +const runCheck_redeem = async ( + hre: HardhatRuntimeEnvironment, + signer: SignerWithAddress, + rToken: string, + redeemAmt: BigNumber +) => { + await redeemRTokens(hre, signer, rToken, redeemAmt) +} + +const runCheck_mint = async ( + hre: HardhatRuntimeEnvironment, + issueAmt: BigNumber, + signer: SignerWithAddress, + basketHandler: BasketHandlerP1, + rToken: RTokenP1 +) => { + console.log(`\nIssuing ${formatEther(issueAmt)} RTokens...`) + const [erc20s] = await basketHandler.quote(fp('1'), 0) + for (const e of erc20s) { + const erc20 = await hre.ethers.getContractAt( + '@openzeppelin/contracts/token/ERC20/IERC20.sol:IERC20', + e + ) + await erc20.connect(signer).approve(rToken.address, MAX_UINT256) // max approval + } + const preBal = await rToken.balanceOf(signer.address) + await rToken.connect(signer).issue(issueAmt) + + const postIssueBal = await rToken.balanceOf(signer.address) + if (!postIssueBal.eq(preBal.add(issueAmt))) { + throw new Error( + `Did not issue the correct amount of RTokens. wanted: ${formatUnits( + preBal.add(issueAmt), + 'mwei' + )} balance: ${formatUnits(postIssueBal, 'mwei')}` + ) + } + + console.log('Successfully minted RTokens') +} + +import { proposal_3_4_0_step_1 } from './proposals/3_4_0' + +task('print-proposal') + .addParam('rtoken', 'the address of the RToken being upgraded') + .addParam('gov', 'the address of the OWNER of the RToken being upgraded') + .addParam('time', 'the address of the timelock') + .setAction(async (params, hre) => { + const proposal = await proposal_3_4_0_step_1(hre, params.rtoken, params.gov, params.time) + + console.log(`\nGenerating and proposing proposal...`) + const [tester] = await hre.ethers.getSigners() + + await hre.run('give-rsr', { address: tester.address }) + await stakeAndDelegateRsr(hre, params.rtoken, tester.address) + + const governor = await hre.ethers.getContractAt('Governance', params.gov) + + const call = await governor.populateTransaction.propose( + proposal.targets, + proposal.values, + proposal.calldatas, + proposal.description + ) + + console.log(`Proposal Transaction:\n`, call.data) + + const r = await governor.propose( + proposal.targets, + proposal.values, + proposal.calldatas, + proposal.description + ) + const resp = await r.wait() + + console.log('\nSuccessfully proposed!') + console.log(`Proposal ID: ${resp.events![0].args!.proposalId}`) + + proposal.proposalId = resp.events![0].args!.proposalId.toString() + + fs.writeFileSync(`./tasks/validation/proposals/proposal-${proposal.proposalId}.json`, JSON.stringify(proposal, null, 2)) + }) \ No newline at end of file diff --git a/tasks/validation/proposals/3_4_0.ts b/tasks/validation/proposals/3_4_0.ts new file mode 100644 index 0000000000..b28a3838dc --- /dev/null +++ b/tasks/validation/proposals/3_4_0.ts @@ -0,0 +1,169 @@ +import { HardhatRuntimeEnvironment } from 'hardhat/types' +import { ProposalBuilder, buildProposal } from '../utils/governance' +import { Proposal } from '#/utils/subgraph' +import { getDeploymentFile, getDeploymentFilename, IDeployments } from '#/scripts/deployment/common' +import { bn } from '#/common/numbers' + +const EXECUTOR_ROLE = '0xd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63' +const PROPOSER_ROLE = '0xb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1' + +// RToken address => Governor Anastasius address +export const GOVERNOR_ANASTASIUSES: { [key: string]: string } = { + '0xCc7FF230365bD730eE4B352cC2492CEdAC49383e': '0x5ef74a083ac932b5f050bf41cde1f67c659b4b88', + '0xCb327b99fF831bF8223cCEd12B1338FF3aA322Ff': '0x8A11D590B32186E1236B5E75F2d8D72c280dc880', + '0xfE0D6D83033e313691E96909d2188C150b834285': '0xaeCa35F0cB9d12D68adC4d734D4383593F109654', + '0xC9a3e2B3064c1c0546D3D0edc0A748E9f93Cf18d': '0xC8f487B34251Eb76761168B70Dc10fA38B0Bd90b', + '0xA0d69E286B938e21CBf7E51D71F6A4c8918f482F': '0xfa4Cc3c65c5CCe085Fc78dD262d00500cf7546CD', + '0xE72B141DF173b999AE7c1aDcbF60Cc9833Ce56a8': '0x991c13ff5e8bd3FFc59244A8cF13E0253C78d2bD', + '0xaCdf0DBA4B9839b96221a8487e9ca660a48212be': '0xb79434b4778E5C1930672053f4bE88D11BbD1f97', + '0xFc0B1EEf20e4c68B3DCF36c4537Cfa7Ce46CA70b': '0x6814F3489cbE3EB32b27508a75821073C85C12b7', + '0x0d86883FAf4FfD7aEb116390af37746F45b6f378': '0x16a0F420426FD102a85A7CcA4BA25f6be1E98cFc', + '0x78da5799CF427Fee11e9996982F4150eCe7a99A7': '0xE5D337258a1e8046fa87Ca687e3455Eb8b626e1F', +} + +// some RTokens are on 1 week and some 2 week +const ONE_WEEK_REWARD_RATIO = '1146076687500' +const TWO_WEEK_REWARD_RATIO = '573038343750' + +export const proposal_3_4_0_step_1: ProposalBuilder = async ( + hre: HardhatRuntimeEnvironment, + rTokenAddress: string, + governorAddress: string, + timelockAddress?: string +): Promise => { + const deploymentFilename = getDeploymentFilename(1) // mainnet only + const deployments = getDeploymentFile(deploymentFilename) + console.log(deployments.implementations.components) + + // Confirm old governor is Alexios + const alexios = await hre.ethers.getContractAt('Governance', governorAddress) + if ((await alexios.name()) != 'Governor Alexios') throw new Error('Governor Alexios only') + + // Confirm a Governor Anastasius exists + const anastasius = await hre.ethers.getContractAt( + 'Governance', + GOVERNOR_ANASTASIUSES[rTokenAddress] + ) + if ((await anastasius.name()) != 'Governor Anastasius') throw new Error('configuration error') + + // Validate timelock is controlled by governance + if (!timelockAddress) throw new Error('missing timelockAddress') + const timelock = await hre.ethers.getContractAt('TimelockController', timelockAddress) + if (!(await timelock.hasRole(EXECUTOR_ROLE, governorAddress))) + throw new Error('missing EXECUTOR_ROLE') + if (!(await timelock.hasRole(PROPOSER_ROLE, governorAddress))) + throw new Error('missing PROPOSER_ROLE') + + const rToken = await hre.ethers.getContractAt('RTokenP1', rTokenAddress) + const main = await hre.ethers.getContractAt('MainP1', await rToken.main()) + const assetRegistry = await hre.ethers.getContractAt( + 'AssetRegistryP1', + await main.assetRegistry() + ) + const backingManager = await hre.ethers.getContractAt( + 'BackingManagerP1', + await main.backingManager() + ) + const basketHandler = await hre.ethers.getContractAt( + 'BasketHandlerP1', + await main.basketHandler() + ) + const broker = await hre.ethers.getContractAt('BrokerP1', await main.broker()) + const distributor = await hre.ethers.getContractAt('DistributorP1', await main.distributor()) + const stRSR = await hre.ethers.getContractAt('StRSRP1Votes', await main.stRSR()) + const furnace = await hre.ethers.getContractAt('FurnaceP1', await main.furnace()) + const rsrTrader = await hre.ethers.getContractAt('RevenueTraderP1', await main.rsrTrader()) + const rTokenTrader = await hre.ethers.getContractAt('RevenueTraderP1', await main.rTokenTrader()) + + // Build proposal + const txs = [ + await main.populateTransaction.upgradeTo(deployments.implementations.main), + await assetRegistry.populateTransaction.upgradeTo( + deployments.implementations.components.assetRegistry + ), + await backingManager.populateTransaction.upgradeTo( + deployments.implementations.components.backingManager + ), + await basketHandler.populateTransaction.upgradeTo( + deployments.implementations.components.basketHandler + ), + await broker.populateTransaction.upgradeTo(deployments.implementations.components.broker), + await distributor.populateTransaction.upgradeTo( + deployments.implementations.components.distributor + ), + await furnace.populateTransaction.upgradeTo(deployments.implementations.components.furnace), + await rsrTrader.populateTransaction.upgradeTo(deployments.implementations.components.rsrTrader), + await rTokenTrader.populateTransaction.upgradeTo( + deployments.implementations.components.rTokenTrader + ), + await stRSR.populateTransaction.upgradeTo(deployments.implementations.components.stRSR), + await rToken.populateTransaction.upgradeTo(deployments.implementations.components.rToken), + await broker.populateTransaction.cacheComponents(), + await backingManager.populateTransaction.cacheComponents(), + await distributor.populateTransaction.cacheComponents(), + await rTokenTrader.populateTransaction.cacheComponents(), + await rsrTrader.populateTransaction.cacheComponents(), + await broker.populateTransaction.setDutchTradeImplementation( + deployments.implementations.trading.dutchTrade + ), + await broker.populateTransaction.setBatchTradeImplementation( + deployments.implementations.trading.gnosisTrade + ), + await furnace.populateTransaction.setRatio(TWO_WEEK_REWARD_RATIO), + await stRSR.populateTransaction.setRewardRatio(TWO_WEEK_REWARD_RATIO), + // TODO + // plugin rotation + + await timelock.populateTransaction.grantRole(EXECUTOR_ROLE, anastasius.address), + await timelock.populateTransaction.grantRole(PROPOSER_ROLE, anastasius.address), + await timelock.populateTransaction.revokeRole(EXECUTOR_ROLE, alexios.address), + await timelock.populateTransaction.grantRole(PROPOSER_ROLE, alexios.address), + ] + + const description = '3.4.0 Upgrade (1/2) - Core Contracts + Plugins' + + return buildProposal(txs, description) +} + +export const proposal_3_4_0_step_2: ProposalBuilder = async ( + hre: HardhatRuntimeEnvironment, + rTokenAddress: string, + governorAddress: string, + timelockAddress?: string +): Promise => { + // Confirm governor is now Anastasius + const anastasius = await hre.ethers.getContractAt('Governance', governorAddress) + if ((await anastasius.name()) != 'Governor Anastasius') throw new Error('step one incomplete') + + // Validate timelock is controlled by governance + if (!timelockAddress) throw new Error('missing timelockAddress') + const timelock = await hre.ethers.getContractAt('TimelockController', timelockAddress) + if (!(await timelock.hasRole(EXECUTOR_ROLE, governorAddress))) + throw new Error('missing EXECUTOR_ROLE') + if (!(await timelock.hasRole(PROPOSER_ROLE, governorAddress))) + throw new Error('missing PROPOSER_ROLE') + + const rToken = await hre.ethers.getContractAt('RTokenP1', rTokenAddress) + const main = await hre.ethers.getContractAt('MainP1', await rToken.main()) + const backingManager = await hre.ethers.getContractAt( + 'BackingManagerP1', + await main.backingManager() + ) + const stRSR = await hre.ethers.getContractAt('StRSRP1Votes', await main.stRSR()) + const furnace = await hre.ethers.getContractAt('FurnaceP1', await main.furnace()) + + // Build proposal + const txs = [ + await backingManager.populateTransaction.setTradingDelay(0), + await furnace.populateTransaction.setRatio(ONE_WEEK_REWARD_RATIO), + await stRSR.populateTransaction.setRewardRatio(ONE_WEEK_REWARD_RATIO), + await rToken.populateTransaction.setIssuanceThrottleParams({ + amtRate: bn('2e24'), + pctRate: bn('1e17'), + }), + ] + + const description = '3.4.0 Upgrade (2/2) - Parameters' + + return buildProposal(txs, description) +} \ No newline at end of file diff --git a/tasks/validation/proposals/proposal-19635069547141631801899721667815895344178432860995231621586111571059800714939.json b/tasks/validation/proposals/proposal-19635069547141631801899721667815895344178432860995231621586111571059800714939.json new file mode 100644 index 0000000000..6743faf97e --- /dev/null +++ b/tasks/validation/proposals/proposal-19635069547141631801899721667815895344178432860995231621586111571059800714939.json @@ -0,0 +1,14 @@ +{ + "rtoken": "0xA0d69E286B938e21CBf7E51D71F6A4c8918f482F", + "governor": "0x7e880d8bD9c9612D6A9759F96aCD23df4A4650E6", + "targets": [ + "0x6d309297ddDFeA104A6E89a132e2f05ce3828e07", + "0x6d309297ddDFeA104A6E89a132e2f05ce3828e07" + ], + "values": [0, 0], + "calldatas": [ + "0xef2b9337000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000004000000000000000000000000093cb4f405924a0c468b43209d5e466f1dd0ac7d000000000000000000000000fbd1a538f5707c0d67a16ca4e3fc711b80bd931a000000000000000000000000f650c3d88d12db855b8bf7d11be6c55a4e07dcc90000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000003782dace9d9000000000000000000000000000000000000000000000000000003782dace9d9000000000000000000000000000000000000000000000000000003782dace9d9000000000000000000000000000000000000000000000000000003782dace9d90000", + "0x8a55015b" + ], + "description": "Test proposal (swap dai into the basket)" +} \ No newline at end of file diff --git a/tasks/validation/proposals/proposal-57514285674680658177308923843884653494858997429824418248202790423910218544052.json b/tasks/validation/proposals/proposal-57514285674680658177308923843884653494858997429824418248202790423910218544052.json new file mode 100644 index 0000000000..bedb8078e1 --- /dev/null +++ b/tasks/validation/proposals/proposal-57514285674680658177308923843884653494858997429824418248202790423910218544052.json @@ -0,0 +1,85 @@ +{ + "rtoken": "0xA0d69E286B938e21CBf7E51D71F6A4c8918f482F", + "governor": "0x7e880d8bD9c9612D6A9759F96aCD23df4A4650E6", + "timelock": "0xc8Ee187A5e5c9dC9b42414Ddf861FFc615446a2c", + "targets": [ + "0x7697aE4dEf3C3Cd52493Ba3a6F57fc6d8c59108a", + "0x9B85aC04A09c8C813c37de9B3d563C2D3F936162", + "0xF014FEF41cCB703975827C8569a3f0940cFD80A4", + "0x6d309297ddDFeA104A6E89a132e2f05ce3828e07", + "0x90EB22A31b69C29C34162E0E9278cc0617aA2B50", + "0x8a77980f82A1d537600891D782BCd8bd41B85472", + "0x57084b3a6317bea01bA8f7c582eD033d9345c2B2", + "0xE04C26F68E0657d402FA95377aa7a2838D6cBA6f", + "0x3d5EbB5399243412c7e895a7AA468c7cD4b1014A", + "0x18ba6e33ceb80f077DEb9260c9111e62f21aE7B8", + "0xA0d69E286B938e21CBf7E51D71F6A4c8918f482F", + "0x90EB22A31b69C29C34162E0E9278cc0617aA2B50", + "0xF014FEF41cCB703975827C8569a3f0940cFD80A4", + "0x8a77980f82A1d537600891D782BCd8bd41B85472", + "0x3d5EbB5399243412c7e895a7AA468c7cD4b1014A", + "0xE04C26F68E0657d402FA95377aa7a2838D6cBA6f", + "0x90EB22A31b69C29C34162E0E9278cc0617aA2B50", + "0x90EB22A31b69C29C34162E0E9278cc0617aA2B50", + "0x57084b3a6317bea01bA8f7c582eD033d9345c2B2", + "0x18ba6e33ceb80f077DEb9260c9111e62f21aE7B8", + "0xc8Ee187A5e5c9dC9b42414Ddf861FFc615446a2c", + "0xc8Ee187A5e5c9dC9b42414Ddf861FFc615446a2c", + "0xc8Ee187A5e5c9dC9b42414Ddf861FFc615446a2c", + "0xc8Ee187A5e5c9dC9b42414Ddf861FFc615446a2c" + ], + "values": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "calldatas": [ + "0x3659cfe600000000000000000000000024a4b37f9c40fb0e80ec436df2e9989fbafa8bb7", + "0x3659cfe6000000000000000000000000bf1c0206de440b2cf76ea4405e1dbf2fc227a463", + "0x3659cfe600000000000000000000000020c801869e578e71f2298649870765aa81f7dc69", + "0x3659cfe6000000000000000000000000ee7fc703f84ae2ce30475333c57e56d3a7d3adbc", + "0x3659cfe600000000000000000000000062bd44b05542bff1e59a01bf7151f533e1c9c12c", + "0x3659cfe600000000000000000000000044a42a0f14128e81a21c5fc4322a9f91ff83b4ee", + "0x3659cfe6000000000000000000000000845b8b0a1c6db8318414d708da25fa28d4a0dc81", + "0x3659cfe6000000000000000000000000c60a7cd6fce24d0c3637a1dcbc8b0f9a9bff6a7c", + "0x3659cfe6000000000000000000000000c60a7cd6fce24d0c3637a1dcbc8b0f9a9bff6a7c", + "0x3659cfe6000000000000000000000000e433673648c94fec0706e5ac95d4f4097f58b5fb", + "0x3659cfe6000000000000000000000000784955641292b0014bc9ef82321300f0b6c7e36d", + "0x7162c797", + "0x7162c797", + "0x7162c797", + "0x7162c797", + "0x7162c797", + "0x2a6b85da000000000000000000000000971c890acb9eeb084f292996be667bb9a2889ae9", + "0x6e300590000000000000000000000000030c9b66ac089cb01aa2058fc8f7d9baddc9ae75", + "0x4f533b23000000000000000000000000000000000000000000000000000000856bbf3646", + "0xd7ccc275000000000000000000000000000000000000000000000000000000856bbf3646", + "0x2f2ff15dd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63000000000000000000000000fa4cc3c65c5cce085fc78dd262d00500cf7546cd", + "0x2f2ff15db09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1000000000000000000000000fa4cc3c65c5cce085fc78dd262d00500cf7546cd", + "0xd547741fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e630000000000000000000000007e880d8bd9c9612d6a9759f96acd23df4a4650e6", + "0x2f2ff15db09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc10000000000000000000000007e880d8bd9c9612d6a9759f96acd23df4a4650e6" + ], + "description": "3.4.0 Upgrade (1/2) - Core Contracts + Plugins", + "proposalId": "57514285674680658177308923843884653494858997429824418248202790423910218544052" +} \ No newline at end of file diff --git a/tasks/validation/test-proposal.ts b/tasks/validation/test-proposal.ts new file mode 100644 index 0000000000..c431515c1c --- /dev/null +++ b/tasks/validation/test-proposal.ts @@ -0,0 +1,85 @@ +import { HardhatRuntimeEnvironment } from 'hardhat/types' +import { ProposalBuilder, buildProposal } from './utils/governance' +import { Proposal } from '#/utils/subgraph' +import { fp } from '#/common/numbers' + +export default async ( + hre: HardhatRuntimeEnvironment, + rTokenAddress: string, + governorAddress: string +) => { + console.log('\n* * * * * Run checks for release 3.3.0...') + const [tester] = await hre.ethers.getSigners() + const rToken = await hre.ethers.getContractAt('RTokenP1', rTokenAddress) + const main = await hre.ethers.getContractAt('IMain', await rToken.main()) + const governor = await hre.ethers.getContractAt('Governance', governorAddress) + const timelockAddress = await governor.timelock() + const timelock = await hre.ethers.getContractAt('TimelockController', timelockAddress) + + const assetRegistry = await hre.ethers.getContractAt( + 'AssetRegistryP1', + await main.assetRegistry() + ) + const basketHandler = await hre.ethers.getContractAt( + 'BasketHandlerP1', + await main.basketHandler() + ) + const backingManager = await hre.ethers.getContractAt( + 'BackingManagerP1', + await main.backingManager() + ) + const broker = await hre.ethers.getContractAt('BrokerP1', await main.broker()) + const furnace = await hre.ethers.getContractAt('FurnaceP1', await main.furnace()) + const rsrTrader = await hre.ethers.getContractAt('RevenueTraderP1', await main.rsrTrader()) + const stRSR = await hre.ethers.getContractAt('StRSRP1Votes', await main.stRSR()) + const rsr = await hre.ethers.getContractAt('StRSRP1Votes', await main.rsr()) + + console.log('\n3.3.0 check succeeded!') +} + +export const saUSDTCollateralAddr = '0x8AD3055286f4E59B399616Bd6BEfE24F64573928' +export const saUSDCCollateralAddr = '0x6E14943224d6E4F7607943512ba17DbBA9524B8e' +export const saEthUSDCCollateralAddr = '0x05beee046A5C28844804E679aD5587046dBffbc0' +export const wcUSDCv3CollateralAddr = '0xf0Fb23485057Fd88C80B9CEc8b433FdA47e0a07A' +export const cUSDTCollateralAddr = '0x1269BFa56EcaE9D6d5003810D4a35bf8479376b8' +export const saEthPyUSDCollateralAddr = '0xe176A5ebFB873D5b3cf1909d0EdaE4FE095F5bc7' +export const TUSDCollateralAddr = '0x7F9999B2C9D310a5f48dfD070eb5129e1e8565E2' +export const cUSDCVaultCollateralAddr = '0x50a9d529ea175cde72525eaa809f5c3c47daa1bb' +export const cUSDTVaultCollateralAddr = '0x5757fF814da66a2B4f9D11d48570d742e246CfD9' +export const daiCollateralAddr = '0xf7d1C6eE4C0D84C6B530D53A897daa1E9eB56833' + +export const saEthUSDCERC20Addr = '0x093cB4f405924a0C468b43209d5E466F1dd0aC7d' +export const wcUSDCv3ERC20Addr = '0xfBD1a538f5707C0D67a16ca4e3Fc711B80BD931A' +export const cUSDTVaultERC20Addr = '0x4Be33630F92661afD646081BC29079A38b879aA0' +export const saUSDTERC20Addr = '0x21fe646D1Ed0733336F2D4d9b2FE67790a6099D9' +export const cUSDTERC20Addr = '0xf650C3d88D12dB855b8bf7D11Be6C55A4e07dCC9' +export const saEthPyUSDERC20Addr = '0x8d6E0402A3E3aD1b43575b05905F9468447013cF' +export const daiAddr = '0x6B175474E89094C44Da98b954EedeAC495271d0F' + +const batchTradeImplAddr = '0x803a52c5DAB69B78419bb160051071eF2F9Fd227' +const dutchTradeImplAddr = '0x4eDEb80Ce684A890Dd58Ae0d9762C38731b11b99' + +export const test_proposal: ProposalBuilder = async ( + hre: HardhatRuntimeEnvironment, + rTokenAddress: string +): Promise => { + const rToken = await hre.ethers.getContractAt('RTokenP1', rTokenAddress) + const main = await hre.ethers.getContractAt('MainP1', await rToken.main()) + const basketHandler = await hre.ethers.getContractAt( + 'BasketHandlerP1', + await main.basketHandler() + ) + + // Build proposal + const txs = [ + await basketHandler.populateTransaction.setPrimeBasket( + [saEthUSDCERC20Addr, wcUSDCv3ERC20Addr, cUSDTERC20Addr, daiAddr], + [fp('0.25'), fp('0.25'), fp('0.25'), fp('0.25')] + ), + await basketHandler.populateTransaction.refreshBasket(), + ] + + const description = 'Test proposal (swap dai into the basket)' + + return buildProposal(txs, description) +} diff --git a/tasks/testing/upgrade-checker-utils/constants.ts b/tasks/validation/utils/constants.ts similarity index 100% rename from tasks/testing/upgrade-checker-utils/constants.ts rename to tasks/validation/utils/constants.ts diff --git a/tasks/validation/utils/governance.ts b/tasks/validation/utils/governance.ts new file mode 100644 index 0000000000..10b2057004 --- /dev/null +++ b/tasks/validation/utils/governance.ts @@ -0,0 +1,262 @@ +import { ProposalState } from '#/common/constants' +import { bn } from '#/common/numbers' +import { whileImpersonating } from '#/utils/impersonation' +import { Delegate, Proposal, getDelegates, getProposalDetails } from '#/utils/subgraph' +import { advanceBlocks, advanceTime } from '#/utils/time' +import { BigNumber, PopulatedTransaction } from 'ethers' +import { HardhatRuntimeEnvironment } from 'hardhat/types' +import { pushOraclesForward } from './oracles' + +const validatePropState = async (propState: ProposalState, expectedState: ProposalState) => { + if (propState !== expectedState) { + throw new Error( + `Proposal should be ${ProposalState[expectedState]} but was ${ProposalState[propState]}` + ) + } +} + +export const moveProposalToActive = async ( + hre: HardhatRuntimeEnvironment, + rtokenAddress: string, + governorAddress: string, + proposalId: string +) => { + console.log('Activating Proposal:', proposalId) + + const governor = await hre.ethers.getContractAt('Governance', governorAddress) + const propState = await governor.state(proposalId) + + if (propState == ProposalState.Pending) { + console.log(`Proposal is PENDING, moving to ACTIVE...`) + + // Advance time to start voting + const votingDelay = await governor.votingDelay() + const rToken = await hre.ethers.getContractAt('RTokenP1', rtokenAddress) + const version = await rToken.version() + if (version == '3.0.0' || version == '3.0.1') await advanceBlocks(hre, votingDelay.add(2)) + else await advanceTime(hre, votingDelay.add(2).toNumber()) + } else { + if (propState == ProposalState.Active) { + console.log(`Proposal is already ${ProposalState[ProposalState.Active]}... skipping step.`) + } else { + throw Error(`Proposal should be ${ProposalState[ProposalState.Pending]} at this step.`) + } + } + + await validatePropState(await governor.state(proposalId), ProposalState.Active) +} + +export const voteProposal = async ( + hre: HardhatRuntimeEnvironment, + rtokenAddress: string, + governorAddress: string, + proposalId: string, + proposal?: Proposal +) => { + console.log('Voting Proposal:', proposalId) + + const governor = await hre.ethers.getContractAt('Governance', governorAddress) + const propState = await governor.state(proposalId) + + if (propState == ProposalState.Active) { + console.log(`Proposal is ACTIVE, moving to SUCCEEDED...`) + + if (!proposal) { + // gather enough whale voters + let whales: Array = await getDelegates(rtokenAddress.toLowerCase()) + const startBlock = await governor.proposalSnapshot(proposalId) + const quorum = await governor.quorum(startBlock) + + let quorumNotReached = true + let currentVoteAmount = BigNumber.from(0) + let i = 0 + while (quorumNotReached) { + const whale = whales[i] + currentVoteAmount = currentVoteAmount.add(BigNumber.from(whale.delegatedVotesRaw)) + i += 1 + if (currentVoteAmount.gt(quorum)) { + quorumNotReached = false + } + } + + whales = whales.slice(0, i) + + // cast enough votes to pass the proposal + for (const whale of whales) { + await whileImpersonating(hre, whale.address, async (signer) => { + await governor.connect(signer).castVote(proposalId, 1) + }) + } + } else { + // Vote from testing account, on the assumption it is staked/delegated + const [tester] = await hre.ethers.getSigners() + await governor.connect(tester).castVote(proposalId, 1) + } + } + + await validatePropState(await governor.state(proposalId), ProposalState.Active) +} + +export const passProposal = async ( + hre: HardhatRuntimeEnvironment, + governorAddress: string, + proposalId: string +) => { + console.log('Passing Proposal:', proposalId) + + const governor = await hre.ethers.getContractAt('Governance', governorAddress) + const propState = await governor.state(proposalId) + + if (propState == ProposalState.Active) { + // Advance time till voting is complete + const votingPeriod = await governor.votingPeriod() + await advanceBlocks(hre, votingPeriod.add(1)) + } + + await validatePropState(await governor.state(proposalId), ProposalState.Succeeded) +} + +export const executeProposal = async ( + hre: HardhatRuntimeEnvironment, + rtokenAddress: string, + governorAddress: string, + proposalId: string, + proposal?: Proposal +) => { + console.log('Executing Proposal:', proposalId) + const governor = await hre.ethers.getContractAt('Governance', governorAddress) + + // Check proposal state + let propState = await governor.state(proposalId) + + let descriptionHash: string + + if (propState == ProposalState.Succeeded) { + console.log(`Proposal is SUCCEEDED, moving to QUEUED...`) + + if (!proposal) { + proposal = await getProposalDetails(proposalId) + } + + descriptionHash = hre.ethers.utils.keccak256(hre.ethers.utils.toUtf8Bytes(proposal.description)) + // Queue proposal + await governor.queue(proposal.targets, proposal.values, proposal.calldatas, descriptionHash) + + // Check proposal state + propState = await governor.state(proposalId) + await validatePropState(propState, ProposalState.Queued) + } + + if (propState == ProposalState.Queued) { + console.log(`Proposal is QUEUED, moving to EXECUTED...`) + + if (!proposal) { + proposal = await getProposalDetails(`${governorAddress.toLowerCase()}-${proposalId}`) + } + + descriptionHash = hre.ethers.utils.keccak256(hre.ethers.utils.toUtf8Bytes(proposal.description)) + + const timelock = await hre.ethers.getContractAt('TimelockController', await governor.timelock()) + const minDelay = await timelock.getMinDelay() + + console.log('Preparing execution...') + // Advance time required by timelock + await advanceTime(hre, minDelay.add(1).toString()) + await advanceBlocks(hre, 1) + + /* + ** Executing proposals requires that the oracles aren't stale. + ** Make sure to specify any extra assets that may have been registered. + */ + await pushOraclesForward(hre, rtokenAddress, []) + + console.log('Executing now...') + + // Execute + await governor.execute(proposal.targets, proposal.values, proposal.calldatas, descriptionHash) + + propState = await governor.state(proposalId) + await validatePropState(propState, ProposalState.Executed) + } else { + throw new Error('Proposal should be queued') + } + + console.log(`Proposal is EXECUTED.`) +} + +export const stakeAndDelegateRsr = async ( + hre: HardhatRuntimeEnvironment, + rtokenAddress: string, + user: string +) => { + const rToken = await hre.ethers.getContractAt('RTokenP1', rtokenAddress) + const main = await hre.ethers.getContractAt('IMain', await rToken.main()) + const stRSR = await hre.ethers.getContractAt('StRSRP1Votes', await main.stRSR()) + const rsr = await hre.ethers.getContractAt('StRSRP1Votes', await main.rsr()) + + await whileImpersonating(hre, user, async (signer) => { + const bal = await rsr.balanceOf(signer.address) + await rsr.approve(stRSR.address, bal) + await stRSR.stake(bal) + await stRSR.delegate(signer.address) + }) +} + +export const buildProposal = (txs: Array, description: string): Proposal => { + const targets = txs.map((tx: PopulatedTransaction) => tx.to!) + const values = txs.map(() => bn(0)) + const calldatas = txs.map((tx: PopulatedTransaction) => tx.data!) + return { + targets, + values, + calldatas, + description, + } +} + +export type ProposalBuilder = ( + hre: HardhatRuntimeEnvironment, + rTokenAddress: string, + governorAddress: string, + timelockAddress: string +) => Promise + +export const proposeUpgrade = async ( + hre: HardhatRuntimeEnvironment, + rTokenAddress: string, + governorAddress: string, + proposal: Proposal +) => { + console.log(`\nGenerating and proposing proposal...`) + const [tester] = await hre.ethers.getSigners() + + await hre.run('give-rsr', { address: tester.address }) + await stakeAndDelegateRsr(hre, rTokenAddress, tester.address) + + const governor = await hre.ethers.getContractAt('Governance', governorAddress) + + const call = await governor.populateTransaction.propose( + proposal.targets, + proposal.values, + proposal.calldatas, + proposal.description + ) + + console.log(`Proposal Transaction:\n`, call.data) + + const r = await governor.propose( + proposal.targets, + proposal.values, + proposal.calldatas, + proposal.description + ) + const resp = await r.wait() + + console.log('\nSuccessfully proposed!') + console.log(`Proposal ID: ${resp.events![0].args!.proposalId}`) + + return { + ...proposal, + proposalId: resp.events![0].args!.proposalId as string, + } +} diff --git a/tasks/testing/upgrade-checker-utils/logs.ts b/tasks/validation/utils/logs.ts similarity index 100% rename from tasks/testing/upgrade-checker-utils/logs.ts rename to tasks/validation/utils/logs.ts diff --git a/tasks/validation/utils/oracles.ts b/tasks/validation/utils/oracles.ts new file mode 100644 index 0000000000..e4bb0874b8 --- /dev/null +++ b/tasks/validation/utils/oracles.ts @@ -0,0 +1,145 @@ +/* eslint-disable no-empty */ +import { networkConfig } from '../../../common/configuration' +import { EACAggregatorProxyMock } from '@typechain/EACAggregatorProxyMock' +import { HardhatRuntimeEnvironment } from 'hardhat/types' +import { BigNumber } from 'ethers' +import { AggregatorV3Interface } from '@typechain/index' +import { ONE_ADDRESS } from '../../../common/constants' + +export const overrideOracle = async ( + hre: HardhatRuntimeEnvironment, + oracleAddress: string +): Promise => { + const oracle = await hre.ethers.getContractAt( + 'contracts/plugins/mocks/EACAggregatorProxyMock.sol:EACAggregatorProxy', + oracleAddress + ) + const aggregator = await oracle.aggregator() + const accessController = await oracle.accessController() + const initPrice = await oracle.latestRoundData() + const mockOracleFactory = await hre.ethers.getContractFactory('EACAggregatorProxyMock') + const mockOracle = await mockOracleFactory.deploy(aggregator, accessController, initPrice.answer) + const bytecode = await hre.network.provider.send('eth_getCode', [mockOracle.address, 'latest']) + await hre.network.provider.request({ + method: 'hardhat_setCode', + params: [oracleAddress, bytecode], + }) + return hre.ethers.getContractAt('EACAggregatorProxyMock', oracleAddress) +} + +export const pushOraclesForward = async ( + hre: HardhatRuntimeEnvironment, + rTokenAddress: string, + extraAssets: string[] = [] +) => { + console.log(`🔃 Pushing Oracles forward for RToken: ${rTokenAddress}`) + const rToken = await hre.ethers.getContractAt('RTokenP1', rTokenAddress) + const main = await hre.ethers.getContractAt('IMain', await rToken.main()) + const assetRegistry = await hre.ethers.getContractAt( + 'AssetRegistryP1', + await main.assetRegistry() + ) + const registry = await assetRegistry.getRegistry() + + for (const asset of registry.assets) { + await pushOracleForward(hre, asset) + } + + for (const asset of extraAssets) { + await pushOracleForward(hre, asset) + } +} + +export const pushOracleForward = async (hre: HardhatRuntimeEnvironment, asset: string) => { + // Need to handle all oracle cases, ie targetUnitChainlinkFeed, PoolTokens, etc + const updateAnswer = async (chainlinkFeed: AggregatorV3Interface) => { + const initPrice = await chainlinkFeed.latestRoundData() + const oracle = await overrideOracle(hre, chainlinkFeed.address) + await oracle.updateAnswer(initPrice.answer) + + console.log('✅ Feed Updated:', chainlinkFeed.address) + } + + // chainlinkFeed + try { + const assetContract = await hre.ethers.getContractAt('TestIAsset', asset) + const feed = await hre.ethers.getContractAt( + 'AggregatorV3Interface', + await assetContract.chainlinkFeed() + ) + if (feed.address != ONE_ADDRESS) await updateAnswer(feed) + } catch { + // console.error('❌ chainlinkFeed not found for:', asset, 'skipping...') + } + + // targetUnitChainlinkFeed + try { + const assetContractNonFiat = await hre.ethers.getContractAt('NonFiatCollateral', asset) + const feed = await hre.ethers.getContractAt( + 'AggregatorV3Interface', + await assetContractNonFiat.targetUnitChainlinkFeed() + ) + await updateAnswer(feed) + } catch { + // console.error('❌ targetUnitChainlinkFeed not found for:', asset, 'skipping...') + } + + // targetPerRefChainlinkFeed, uoaPerTargetChainlinkFeed, refPerTokenChainlinkFeed + try { + const assetContractLido = await hre.ethers.getContractAt('L2LidoStakedEthCollateral', asset) + let feed = await hre.ethers.getContractAt( + 'AggregatorV3Interface', + await assetContractLido.targetPerRefChainlinkFeed() + ) + await updateAnswer(feed) + feed = await hre.ethers.getContractAt( + 'AggregatorV3Interface', + await assetContractLido.uoaPerTargetChainlinkFeed() + ) + await updateAnswer(feed) + feed = await hre.ethers.getContractAt( + 'AggregatorV3Interface', + await assetContractLido.refPerTokenChainlinkFeed() + ) + await updateAnswer(feed) + } catch { + // console.error('❌ targetPerRefChainlinkFeed, uoaPerTargetChainlinkFeed, or refPerTokenChainlinkFeed not found for:', asset, 'skipping...') + } + + // targetPerTokChainlinkFeed + try { + const assetContractReth = await hre.ethers.getContractAt('RethCollateral', asset) + const feed = await hre.ethers.getContractAt( + 'AggregatorV3Interface', + await assetContractReth.targetPerTokChainlinkFeed() + ) + await updateAnswer(feed) + } catch { + // console.error('❌ targetPerTokChainlinkFeed not found for:', asset, 'skipping...') + } + + // TODO do better + // Problem: The feeds on PoolTokens are internal immutable. Not in storage nor are there getters. + // Workaround solution: hard-code oracles for FRAX for eUSDFRAXBP; USDC is registered as backup + if (asset == '0x890FAa00C16EAD6AA76F18A1A7fe9C40838F9122') { + const feed = await hre.ethers.getContractAt( + 'AggregatorV3Interface', + networkConfig['1'].chainlinkFeeds.FRAX! + ) + await updateAnswer(feed) + } +} + +export const setOraclePrice = async ( + hre: HardhatRuntimeEnvironment, + asset: string, + value: BigNumber +) => { + const assetContract = await hre.ethers.getContractAt('TestIAsset', asset) + const realChainlinkFeed = await hre.ethers.getContractAt( + 'AggregatorV3Interface', + await assetContract.chainlinkFeed() + ) + const oracle = await overrideOracle(hre, realChainlinkFeed.address) + await oracle.updateAnswer(value) +} diff --git a/tasks/testing/upgrade-checker-utils/rewards.ts b/tasks/validation/utils/rewards.ts similarity index 87% rename from tasks/testing/upgrade-checker-utils/rewards.ts rename to tasks/validation/utils/rewards.ts index 46e694e373..8213618a08 100644 --- a/tasks/testing/upgrade-checker-utils/rewards.ts +++ b/tasks/validation/utils/rewards.ts @@ -5,7 +5,7 @@ import { advanceBlocks, advanceTime } from '#/utils/time' import { IRewardable } from '@typechain/IRewardable' import { formatEther } from 'ethers/lib/utils' import { HardhatRuntimeEnvironment } from 'hardhat/types' -import { runBatchTrade } from '../upgrade-checker-utils/trades' +import { runBatchTrade } from './trades' const claimRewards = async (claimer: IRewardable) => { const resp = await claimer.claimRewards() @@ -23,6 +23,10 @@ export const claimRsrRewards = async (hre: HardhatRuntimeEnvironment, rtokenAddr console.log(`\n* * * * * Claiming RSR rewards...`) const rToken = await hre.ethers.getContractAt('RTokenP1', rtokenAddress) const main = await hre.ethers.getContractAt('IMain', await rToken.main()) + const assetRegistry = await hre.ethers.getContractAt( + 'AssetRegistryP1', + await main.assetRegistry() + ) const backingManager = await hre.ethers.getContractAt( 'BackingManagerP1', await main.backingManager() @@ -32,8 +36,11 @@ export const claimRsrRewards = async (hre: HardhatRuntimeEnvironment, rtokenAddr const strsr = await hre.ethers.getContractAt('StRSRP1', await main.stRSR()) const rsrRatePre = await strsr.exchangeRate() - const rewards = await claimRewards(backingManager) - console.log('rewards claimed', rewards) + // requires 3.4.0 plugins to be swapped in + // const rewards = await claimRewards(backingManager) + // console.log('rewards claimed', rewards) + const rewards = await assetRegistry.erc20s() + await backingManager.forwardRevenue(rewards) const comp = '0xc00e94Cb662C3520282E6f5717214004A7f26888' const compContract = await hre.ethers.getContractAt('ERC20Mock', comp) @@ -45,7 +52,6 @@ export const claimRsrRewards = async (hre: HardhatRuntimeEnvironment, rtokenAddr await rsrTrader.manageTokens([comp], [TradeKind.BATCH_AUCTION]) await runBatchTrade(hre, rsrTrader, comp, false) - await rsrTrader.manageTokens([rsr.address], [TradeKind.BATCH_AUCTION]) await strsr.payoutRewards() await advanceBlocks(hre, 100) await advanceTime(hre, 1200) diff --git a/tasks/testing/upgrade-checker-utils/rtokens.ts b/tasks/validation/utils/rtokens.ts similarity index 99% rename from tasks/testing/upgrade-checker-utils/rtokens.ts rename to tasks/validation/utils/rtokens.ts index 59db68913d..933eb46ade 100644 --- a/tasks/testing/upgrade-checker-utils/rtokens.ts +++ b/tasks/validation/utils/rtokens.ts @@ -10,7 +10,7 @@ import { callAndGetNextTrade, runBatchTrade, runDutchTrade } from './trades' import { CollateralStatus } from '#/common/constants' import { ActFacet } from '@typechain/ActFacet' import { ReadFacet } from '@typechain/ReadFacet' -import { pushOraclesForward } from '../upgrade-checker-utils/oracles' +import { pushOraclesForward } from './oracles' type Balances = { [key: string]: BigNumber } diff --git a/tasks/validation/utils/trades.ts b/tasks/validation/utils/trades.ts new file mode 100644 index 0000000000..af256b8543 --- /dev/null +++ b/tasks/validation/utils/trades.ts @@ -0,0 +1,400 @@ +import { MAX_UINT256, QUEUE_START, TradeKind, TradeStatus } from '#/common/constants' +import { bn, fp } from '#/common/numbers' +import { whileImpersonating } from '#/utils/impersonation' +import { networkConfig } from '../../../common/configuration' +import { + advanceToTimestamp, + advanceTime, + getLatestBlockNumber, + getLatestBlockTimestamp, +} from '#/utils/time' +import { DutchTrade } from '@typechain/DutchTrade' +import { GnosisTrade } from '@typechain/GnosisTrade' +import { TestITrading } from '@typechain/TestITrading' +import { BigNumber, ContractTransaction } from 'ethers' +import { LogDescription } from 'ethers/lib/utils' +import { HardhatRuntimeEnvironment } from 'hardhat/types' +import { logToken } from './logs' +import { getChainId } from '#/common/blockchain-utils' +import { Whales, getWhalesFile } from '#/scripts/whalesConfig' + +export const runBatchTrade = async ( + hre: HardhatRuntimeEnvironment, + trader: TestITrading, + tradeToken: string, + bidExact: boolean +) => { + // NOTE: + // buy & sell are from the perspective of the auction-starter + // placeSellOrders() flips it to be from the perspective of the trader + const chainId = await getChainId(hre) + const whales: Whales = getWhalesFile(chainId).tokens + + const tradeAddr = await trader.trades(tradeToken) + const trade = await hre.ethers.getContractAt('GnosisTrade', tradeAddr) + + // Only works for Batch trades + if ((await trade.KIND()) != TradeKind.BATCH_AUCTION) { + throw new Error(`Invalid Trade Type`) + } + + const buyTokenAddress = (await trade.buy()).toLowerCase() + console.log( + `Running batch trade: sell ${logToken(tradeToken)} for ${logToken(buyTokenAddress)}...` + ) + const endTime = await trade.endTime() + const worstPrice = await trade.worstCasePrice() // trade.buy() per trade.sell() + const auctionId = await trade.auctionId() + const sellAmount = await trade.initBal() + + const sellToken = await hre.ethers.getContractAt('ERC20Mock', await trade.sell()) + const sellDecimals = await sellToken.decimals() + const buytoken = await hre.ethers.getContractAt('ERC20Mock', await buyTokenAddress) + const buyDecimals = await buytoken.decimals() + let buyAmount = bidExact ? sellAmount : sellAmount.mul(worstPrice).div(fp('1')) + if (buyDecimals > sellDecimals) { + buyAmount = buyAmount.mul(bn(10 ** (buyDecimals - sellDecimals))) + } else if (sellDecimals > buyDecimals) { + buyAmount = buyAmount.div(bn(10 ** (sellDecimals - buyDecimals))) + } + buyAmount = buyAmount.add(fp('1').div(bn(10 ** (18 - buyDecimals)))) + + const gnosis = await hre.ethers.getContractAt('EasyAuction', await trade.gnosis()) + const whaleAddr = whales[buyTokenAddress.toLowerCase()] + + // For newly wrapped tokens we need to feed the whale + await getTokens(hre, buyTokenAddress, buyAmount, whaleAddr) + + await whileImpersonating(hre, whaleAddr, async (whale) => { + const sellToken = await hre.ethers.getContractAt('ERC20Mock', buyTokenAddress) + await sellToken.connect(whale).approve(gnosis.address, buyAmount) + + await gnosis + .connect(whale) + .placeSellOrders( + auctionId, + [sellAmount], + [buyAmount], + [QUEUE_START], + hre.ethers.constants.HashZero + ) + }) + + const lastTimestamp = await getLatestBlockTimestamp(hre) + await advanceTime(hre, BigNumber.from(endTime).sub(lastTimestamp).toString()) + await trader.settleTrade(tradeToken) + + console.log(`Settled trade for ${logToken(buyTokenAddress)}.`) +} + +export const runDutchTrade = async ( + hre: HardhatRuntimeEnvironment, + trader: TestITrading, + tradeToken: string +): Promise<[boolean, string]> => { + const router = await (await hre.ethers.getContractFactory('DutchTradeRouter')).deploy() + // NOTE: + // buy & sell are from the perspective of the auction-starter + // bid() flips it to be from the perspective of the trader + const chainId = await getChainId(hre) + const whales: Whales = getWhalesFile(chainId).tokens + + let tradesRemain = false + let newSellToken = '' + + const tradeAddr = await trader.trades(tradeToken) + const trade = await hre.ethers.getContractAt('DutchTrade', tradeAddr) + + // Only works for Dutch trades + if ((await trade.KIND()) != TradeKind.DUTCH_AUCTION) { + throw new Error(`Invalid Trade Type`) + } + + const buyTokenAddress = await trade.buy() + console.log('=========') + console.log( + `Running Dutch Trade: Selling ${logToken(tradeToken)} for ${logToken(buyTokenAddress)}...` + ) + + const endTime = await trade.endTime() + const whaleAddr = whales[buyTokenAddress.toLowerCase()] + + // Bid near 1:1 point, which occurs at the 70% mark + const latestTimestamp = await getLatestBlockTimestamp(hre) + const toAdvance = (endTime - latestTimestamp) * 7 / 10 + await advanceTime(hre, toAdvance) + const buyAmount = await trade.bidAmount(await getLatestBlockNumber(hre)) + + // Ensure funds available + await getTokens(hre, buyTokenAddress, buyAmount, whaleAddr) + + const buyToken = await hre.ethers.getContractAt('ERC20Mock', buyTokenAddress) + await buyToken.connect(whaleAddr).approve(router.address, MAX_UINT256) + + // Bid + ;[tradesRemain, newSellToken] = await callAndGetNextTrade( + router.bid(trade.address, await router.signer.getAddress()), + trader + ) + + console.log( + 'Trade State:', + TradeStatus[await trade.status()], + await trade.canSettle(), + await trade.bidder(), + whaleAddr + ) + + if ( + (await trade.canSettle()) || + (await trade.status()) != TradeStatus.CLOSED || + (await trade.bidder()) != router.address + ) { + throw new Error(`Error settling Dutch Trade`) + } + + console.log(`Settled trade for ${logToken(buyTokenAddress)} in amount ${buyAmount}.`) + + // Return new trade (if exists) + return [tradesRemain, newSellToken] +} + +export const callAndGetNextTrade = async ( + tx: Promise, + trader: TestITrading +): Promise<[boolean, string]> => { + let tradesRemain = false + let newSellToken = '' + + // Process transaction and get next trade + const r = await tx + const resp = await r.wait() + const iface = trader.interface + + for (const event of resp.events!) { + let parsedLog: LogDescription | undefined + try { + parsedLog = iface.parseLog(event) + // eslint-disable-next-line no-empty + } catch {} + + if (parsedLog && parsedLog.name == 'TradeStarted') { + // TODO: Improve this to include proper token details and parsing. + + console.log( + ` + ====== Trade Started: Selling ${logToken(parsedLog.args.sell)} / Buying ${logToken( + parsedLog.args.buy + )} ====== + minBuyAmount: ${parsedLog.args.minBuyAmount} + sellAmount: ${parsedLog.args.sellAmount} + `.trim() + ) + + tradesRemain = true + newSellToken = parsedLog.args.sell + } + } + + return [tradesRemain, newSellToken] +} + +// impersonate the whale to provide the required tokens to recipient +export const getTokens = async ( + hre: HardhatRuntimeEnvironment, + tokenAddress: string, + amount: BigNumber, + recipient: string +) => { + console.log('Acquiring tokens...', tokenAddress) + switch (tokenAddress.toLowerCase()) { + case '0x60C384e226b120d93f3e0F4C502957b2B9C32B15'.toLowerCase(): // saUSDC mainnet + case '0x21fe646D1Ed0733336F2D4d9b2FE67790a6099D9'.toLowerCase(): // saUSDT mainnet + case '0xC19f5d60e2Aca1174f3D5Fe189f0A69afaB76f50'.toLowerCase(): // saBasUSDC base + await getStaticAToken(hre, tokenAddress, amount, recipient) + break + case '0xf579F9885f1AEa0d3F8bE0F18AfED28c92a43022'.toLowerCase(): // cUSDCVault mainnet + case '0x4Be33630F92661afD646081BC29079A38b879aA0'.toLowerCase(): // cUSDTVault mainnet + await getCTokenVault(hre, tokenAddress, amount, recipient) + break + case '0x24CDc6b4Edd3E496b7283D94D93119983A61056a'.toLowerCase(): // cvx3Pool mainnet + case '0x511daB8150966aFfE15F0a5bFfBa7F4d2b62DEd4'.toLowerCase(): // cvxPayPool mainnet + case '0x81697e25DFf8564d9E0bC6D27edb40006b34ea2A'.toLowerCase(): // cvxeUSDFRAXBP mainnet + case '0x3e8f7EDc03E0133b95EcB4dD2f72B5027E695413'.toLowerCase(): // cvxMIM3Pool mainnet + case '0xDbC0cE2321B76D3956412B36e9c0FA9B0fD176E7'.toLowerCase(): // cvxETHPlusETH mainnet + case '0x6ad24C0B8fD4B594C6009A7F7F48450d9F56c6b8'.toLowerCase(): // cvxCrvUSDUSDC mainnet + case '0x5d1B749bA7f689ef9f260EDC54326C48919cA88b'.toLowerCase(): // cvxCrvUSDUSDT mainnet + await getCvxVault(hre, tokenAddress, amount, recipient) + default: + await getERC20Tokens(hre, tokenAddress, amount, recipient) + return + } +} + +const getCvxVault = async ( + hre: HardhatRuntimeEnvironment, + tokenAddress: string, + amount: BigNumber, + recipient: string +) => { + const chainId = await getChainId(hre) + const whales: Whales = getWhalesFile(chainId).tokens + + const cvxWrapper = await hre.ethers.getContractAt('ConvexStakingWrapper', tokenAddress) + const curveTokenAddy = await cvxWrapper.curveToken() + const curvePool = await hre.ethers.getContractAt( + '@openzeppelin/contracts/token/ERC20/IERC20.sol:IERC20', + curveTokenAddy + ) + + await whileImpersonating(hre, whales[curveTokenAddy.toLowerCase()], async (whaleSigner) => { + await curvePool.connect(whaleSigner).transfer(recipient, amount) + }) + + await whileImpersonating(hre, recipient, async (recipientSigner) => { + await curvePool.connect(recipientSigner).approve(cvxWrapper.address, amount) + await cvxWrapper.connect(recipientSigner).deposit(amount, recipient) + }) +} + +// get a specific amount of wrapped cTokens +const getCTokenVault = async ( + hre: HardhatRuntimeEnvironment, + tokenAddress: string, + amount: BigNumber, + recipient: string +) => { + const chainId = await getChainId(hre) + const whales: Whales = getWhalesFile(chainId).tokens + + const collateral = await hre.ethers.getContractAt('CTokenWrapper', tokenAddress) + const cToken = await hre.ethers.getContractAt('ICToken', await collateral.underlying()) + + await whileImpersonating(hre, whales[cToken.address.toLowerCase()], async (whaleSigner) => { + await cToken.connect(whaleSigner).transfer(recipient, amount) + }) + + await whileImpersonating(hre, recipient, async (recipientSigner) => { + await cToken.connect(recipientSigner).approve(collateral.address, amount) + await collateral.connect(recipientSigner).deposit(amount, recipient) + }) +} + +// get a specific amount of static aTokens +const getStaticAToken = async ( + hre: HardhatRuntimeEnvironment, + tokenAddress: string, + amount: BigNumber, + recipient: string +) => { + const chainId = await getChainId(hre) + const whales: Whales = getWhalesFile(chainId).tokens + + const collateral = await hre.ethers.getContractAt('StaticATokenLM', tokenAddress) + const aTokensNeeded = await collateral.staticToDynamicAmount(amount) + const aToken = await hre.ethers.getContractAt( + '@aave/protocol-v2/contracts/interfaces/IAToken.sol:IAToken', + await collateral.ATOKEN() + ) + + await whileImpersonating(hre, whales[aToken.address.toLowerCase()], async (whaleSigner) => { + await aToken.connect(whaleSigner).transfer(recipient, aTokensNeeded.mul(101).div(100)) // buffer to ensure enough balance + }) + + await whileImpersonating(hre, recipient, async (recipientSigner) => { + const bal = await aToken.balanceOf(recipientSigner.address) + await aToken.connect(recipientSigner).approve(collateral.address, bal) + await collateral.connect(recipientSigner).deposit(recipient, bal, 0, false) + }) +} + +// get a specific amount of erc20 plain token +const getERC20Tokens = async ( + hre: HardhatRuntimeEnvironment, + tokenAddress: string, + amount: BigNumber, + recipient: string +) => { + const chainId = await getChainId(hre) + const whales: Whales = getWhalesFile(chainId).tokens + + const token = await hre.ethers.getContractAt('ERC20Mock', tokenAddress) + + // special-cases for wrappers with 0 supply + const wcUSDCv3Address = networkConfig[chainId].tokens.wcUSDCv3!.toLowerCase() + const aUSDCv3Address = networkConfig[chainId].tokens.saEthUSDC!.toLowerCase() + const aPyUSDv3Address = networkConfig[chainId].tokens.saEthPyUSD!.toLowerCase() + const stkcvxeUSDFRAXBPAddress = '0x8e33D5aC344f9F2fc1f2670D45194C280d4fBcF1'.toLowerCase() + + if (tokenAddress.toLowerCase() == wcUSDCv3Address) { + const wcUSDCv3 = await hre.ethers.getContractAt( + 'CusdcV3Wrapper', + wcUSDCv3Address + ) + await whileImpersonating( + hre, + whales[networkConfig['1'].tokens.cUSDCv3!.toLowerCase()], + async (whaleSigner) => { + const cUSDCv3 = await hre.ethers.getContractAt( + 'ERC20Mock', + networkConfig['1'].tokens.cUSDCv3! + ) + await cUSDCv3.connect(whaleSigner).approve(wcUSDCv3.address, 0) + await cUSDCv3.connect(whaleSigner).approve(wcUSDCv3.address, MAX_UINT256) + await wcUSDCv3.connect(whaleSigner).deposit(amount.mul(2)) + const bal = await wcUSDCv3.balanceOf(whaleSigner.address) + await wcUSDCv3.connect(whaleSigner).transfer(recipient, bal) + } + ) + } else if (tokenAddress.toLowerCase() == aUSDCv3Address) { + const saEthUSDC = await hre.ethers.getContractAt( + 'IStaticATokenV3LM', + aUSDCv3Address + ) + await whileImpersonating( + hre, + whales[networkConfig['1'].tokens.USDC!.toLowerCase()], + async (whaleSigner) => { + const USDC = await hre.ethers.getContractAt('ERC20Mock', networkConfig['1'].tokens.USDC!) + await USDC.connect(whaleSigner).approve(saEthUSDC.address, amount.mul(2)) + await saEthUSDC.connect(whaleSigner).deposit(amount.mul(2), whaleSigner.address, 0, true) + await token.connect(whaleSigner).transfer(recipient, amount) // saEthUSDC transfer + } + ) + } else if (tokenAddress.toLowerCase() == aPyUSDv3Address) { + const saEthPyUSD = await hre.ethers.getContractAt( + 'IStaticATokenV3LM', + aPyUSDv3Address + ) + await whileImpersonating( + hre, + whales[networkConfig['1'].tokens.pyUSD!.toLowerCase()], + async (whaleSigner) => { + const pyUSD = await hre.ethers.getContractAt('ERC20Mock', networkConfig['1'].tokens.pyUSD!) + await pyUSD.connect(whaleSigner).approve(saEthPyUSD.address, amount.mul(2)) + await saEthPyUSD.connect(whaleSigner).deposit(amount.mul(2), whaleSigner.address, 0, true) + await token.connect(whaleSigner).transfer(recipient, amount) // saEthPyUSD transfer + } + ) + } else if (tokenAddress.toLowerCase() == stkcvxeUSDFRAXBPAddress) { + const stkcvxeUSDFRAXBP = await hre.ethers.getContractAt( + 'ConvexStakingWrapper', + stkcvxeUSDFRAXBPAddress + ) + + const lpTokenAddr = '0xaeda92e6a3b1028edc139a4ae56ec881f3064d4f'.toLowerCase() + + await whileImpersonating(hre, whales[lpTokenAddr], async (whaleSigner) => { + const lpToken = await hre.ethers.getContractAt('ERC20Mock', lpTokenAddr) + await lpToken.connect(whaleSigner).approve(stkcvxeUSDFRAXBP.address, amount.mul(2)) + await stkcvxeUSDFRAXBP.connect(whaleSigner).deposit(amount.mul(2), whaleSigner.address) + await token.connect(whaleSigner).transfer(recipient, amount) + }) + } else { + const addr = whales[token.address.toLowerCase()] + if (!addr) throw new Error('missing whale for ' + tokenAddress) + await whileImpersonating(hre, whales[token.address.toLowerCase()], async (whaleSigner) => { + await token.connect(whaleSigner).transfer(recipient, amount) + }) + } +} diff --git a/tasks/testing/upgrade-checker-utils/upgrades/3_3_0_plugins.ts b/tasks/validation/utils/upgrades/3_3_0_plugins.ts similarity index 100% rename from tasks/testing/upgrade-checker-utils/upgrades/3_3_0_plugins.ts rename to tasks/validation/utils/upgrades/3_3_0_plugins.ts diff --git a/tasks/validation/whales/whales_1.json b/tasks/validation/whales/whales_1.json new file mode 100644 index 0000000000..b8215cf6ee --- /dev/null +++ b/tasks/validation/whales/whales_1.json @@ -0,0 +1,158 @@ +{ + "tokens": { + "0xfbd1a538f5707c0d67a16ca4e3fc711b80bd931a": "0xF014FEF41cCB703975827C8569a3f0940cFD80A4", + "0x6b175474e89094c44da98b954eedeac495271d0f": "0x40ec5B33f54e0E8A33A975908C5BA1c14e5BbbDf", + "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": "0x4B16c5dE96EB2117bBE5fd171E4d203624B014aa", + "0xdac17f958d2ee523a2206206994597c13d831ec7": "0xF977814e90dA44bFA03b6295A0616a897441aceC", + "0x4fabb145d64652a948d72533023f6e7a623c7c53": "0x8Fe348f2F890046719aAceA910F01d772Dc20a65", + "0x8e870d67f660d95d5be530380d0ec0bd388289e1": "0x38699d04656fF537ef8671b6b595402ebDBdf6f4", + "0x0000000000085d4780b73119b644ae5ecd22b376": "0x9FCc67D7DB763787BB1c7f3bC7f34d3C548c19Fe", + "0x57ab1ec28d129707052df4df418d58a2d46d5f51": "0x99F4176EE457afedFfCB1839c7aB7A030a5e4A92", + "0x853d955acef822db058eb8505911ed77f175b99e": "0xcE6431D21E3fb1036CE9973a3312368ED96F5CE7", + "0x99d8a9c45b2eca8864373a26d1459e3dff1e17f3": "0x439a5f0f5E8d149DDA9a0Ca367D4a8e4D6f83C10", + "0xf939e0a03fb07f59a73314e73794be0e57ac1b4e": "0xA920De414eA4Ab66b97dA1bFE9e6EcA7d4219635", + "0xa0d69e286b938e21cbf7e51d71f6a4c8918f482f": "0x3154Cf16ccdb4C6d922629664174b904d80F2C35", + "0x028171bca77440897b824ca71d1c56cac55b68a3": "0x07edE94cF6316F4809f2B725f5d79AD303fB4Dc8", + "0xbcca60bb61934080951369a648fb03df4f96263c": "0xc9E6E51C7dA9FF1198fdC5b3369EfeDA9b19C34c", + "0x3ed3b47dd13ec9a98b44e6204a523e766b225811": "0x295E5eE985246cfD09B615f8706854600084c529", + "0xa361718326c15715591c299427c62086f69923d9": "0xc579a79376148c4B17821C5Eb9434965f3a15C80", + "0x2e8f4bdbe3d47d7d7de490437aea9915d930f1a3": "0x01820D92f8F86947CA0454789172AD60e05817fA", + "0x030ba81f1c18d280636f32af80b9aad02cf0854e": "0x777777c9898D384F785Ee44Acfe945efDFf5f3E0", + "0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c": "0xA91661efEe567b353D55948C0f051C1A16E503A5", + "0x093cb4f405924a0c468b43209d5e466f1dd0ac7d": "0xF014FEF41cCB703975827C8569a3f0940cFD80A4", + "0x5d3a536e4d6dbd6114cc1ead35777bab948e3643": "0x30030383d959675eC884E7EC88F05EE0f186cC06", + "0x39aa39c021dfbae8fac545936693ac917d5e7563": "0xC2F61a6eEEC48d686901D325CDE9233b81c793F3", + "0xf650c3d88d12db855b8bf7d11be6c55a4e07dcc9": "0xb99CC7e10Fe0Acc68C50C7829F473d81e23249cc", + "0x041171993284df560249b57358f931d9eb7b925d": "0x01820D92f8F86947CA0454789172AD60e05817fA", + "0x4ddc2d193948926d02f9b1fe9e1daa0718270ed5": "0x08CFd293D687B6CEe139219a607ACBBC10A6eb25", + "0xccf4429db6322d5c611ee964527d42e5d685dd6a": "0xceEf57F6C40A7CB2392eaAD101Ee0440aA43bA42", + "0x465a5a630482f3abd6d3b84b39b29b07214d19e5": "0x7Fbe0de6ffA86f4B9528AA27029595429B0c74A9", + "0x81994b9607e06ab3d5cf3afff9a67374f05f27d7": "0x7Fbe0de6ffA86f4B9528AA27029595429B0c74A9", + "0x1c9a2d6b33b4826757273d47ebee0e2dddcd978b": "0x11cC283d06FA762061df2B0D2f0787651ceef659", + "0xe2ba8693ce7474900a045757fe0efca900f6530b": "0x7Fbe0de6ffA86f4B9528AA27029595429B0c74A9", + "0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9": "0x4da27a545c0c5B758a6BA100e3a049001de870f5", + "0x4da27a545c0c5b758a6ba100e3a049001de870f5": "0xb56333581B852e61E1413A2A7A66BF679D8ACf81", + "0xc00e94cb662c3520282e6f5717214004a7f26888": "0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B", + "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2": "0xF04a5cC80B1E94C69B48f5ee68a08CD2F09A7c3E", + "0x9ff58f4ffb29fa2266ab25e75e2a8b3503311656": "0x777777c9898D384F785Ee44Acfe945efDFf5f3E0", + "0x8dae6cb04688c62d939ed9b68d32bc62e49970b1": "0xB5587A54fF7022AC218438720BDCD840a32f0481", + "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599": "0x5Ee5bf7ae06D1Be5997A1A72006FE6C607eC6DE8", + "0xc581b735a1688071a1746c968e0798d642ede491": "0x5754284f345afc66a98fbB0a0Afe71e0F007B949", + "0x320623b8e4ff03373931769a31fc52a4e78b5d70": "0x6bab6EB87Aa5a1e4A8310C73bDAAA8A5dAAd81C1", + "0xd533a949740bb3306d119cc777fa900ba034cd52": "0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2", + "0x4e3fbd56cd56c3e72c1403e103b45db9da5b9d2b": "0x72a19342e8F1838460eBFCCEf09F6585e32db86E", + "0xe95a203b1a91a908f9b9ce46459d101078c2c3cb": "0xF02e86D9E0eFd57aD034FaF52201B79917fE0713", + "0x5e8422345238f34275888049021821e8e08caa1f": "0xac3E018457B222d93114458476f3E3416Abbe38F", + "0xac3e018457b222d93114458476f3e3416abbe38f": "0x78bB3aEC3d855431bd9289fD98dA13F9ebB7ef15", + "0xae7ab96520de3a18e5e111b5eaab095312d7fe84": "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", + "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0": "0x0B925eD163218f6662a35e0f0371Ac234f9E9371", + "0xae78736cd615f374d3085123a210448e74fc6393": "0x1BeE69b7dFFfA4E2d53C2a2Df135C388AD25dCD2", + "0xc3d688b66703497daa19211eedff47f25384cdc3": "0x7f714b13249BeD8fdE2ef3FBDfB18Ed525544B03", + "0xfaba6f8e4a5e8ab82f62fe7c39859fa577269be3": "0x677FD4Ed8aE623f2f625DEB2D64F2070E46cA1A1", + "0xa663b02cf0a4b149d2ad41910cb81e23e1c41c32": "0x6A7efa964Cf6D9Ab3BC3c47eBdDB853A8853C502", + "0x83f20f44975d03b1b09e64809b757c47f942beea": "0xDdE0d6e90bfB74f1dC8ea070cFd0c0180C03Ad16", + "0xbe9895146f7af43049ca1c1ae358b0541ea49704": "0xED1F7bb04D2BA2b6EbE087026F03C96Ea2c357A8", + "0xaf5191b0de278c7286d6c7cc6ab6bb8a73ba2cd6": "0x65bb797c2B9830d891D87288F029ed8dACc19705", + "0xdf0770df86a8034b3efef0a1bb3c889b8332ff56": "0xB0D502E938ed5f4df2E681fE6E419ff29631d62b", + "0x38ea452219524bb87e18de1c24d3bb59510bd783": "0xB0D502E938ed5f4df2E681fE6E419ff29631d62b", + "0x101816545f6bd2b1076434b54383a1e633390a2e": "0xB0D502E938ed5f4df2E681fE6E419ff29631d62b", + "0x1982b2f5814301d4e9a8b0201555376e62f82428": "0x777777c9898D384F785Ee44Acfe945efDFf5f3E0", + "0x9994e35db50125e0df82e4c2dde62496ce330999": "0xcBa28b38103307Ec8dA98377ffF9816C164f9AFa", + "0xf56fb6cc29f0666bdd1662feaae2a3c935ee3469": "0x93A62dA5a14C80f265DAbC077fCEE437B1a0Efde", + "0x7ca00559b978cfde81297849be6151d3ccb408a9": "0xa931b486F661540c6D709aE6DfC8BcEF347ea437", + "0x6c3ea9036406852006290770bedfcaba0e23a0e8": "0xE25a329d385f77df5D4eD56265babe2b99A5436e", + "0x0c0d01abf3e6adfca0989ebba9d6e85dd58eab1e": "0x01820D92f8F86947CA0454789172AD60e05817fA", + "0xe72b141df173b999ae7c1adcbf60cc9833ce56a8": "0x7cc1bfAB73bE4E02BB53814d1059A98cF7e49644", + "0xacdf0dba4b9839b96221a8487e9ca660a48212be": "0x7cc1bfAB73bE4E02BB53814d1059A98cF7e49644", + "0xfc0b1eef20e4c68b3dcf36c4537cfa7ce46ca70b": "0xF2B25362a03f6EACCa8De8d5350A9f37944c1e59", + "0x0d86883faf4ffd7aeb116390af37746f45b6f378": "0x7cc1bfAB73bE4E02BB53814d1059A98cF7e49644", + "0x78da5799cf427fee11e9996982f4150ece7a99a7": "0x3154Cf16ccdb4C6d922629664174b904d80F2C35", + "0x73968b9a57c6e53d41345fd57a6e6ae27d6cdb2f": "0x0C30476f66034E11782938DF8e4384970B6c9e8a", + "0x48c3399719b582dd63eb5aadf12a40b4c3f52fa2": "0xF0d99D5d1D5E06CdAd4766503Cb82213B5E1d1bE", + "0xc55126051b22ebb829d00368f4b12bde432de5da": "0x742B70151cd3Bc7ab598aAFF1d54B90c3ebC6027", + "0x1576b2d7ef15a2ebe9c22c8765dd9c1efea8797b": "0x4B0b3d40b0623f3a9eac09d2E01F592710ee59F0", + "0xbeef01735c132ada46aa9aa4c54623caa92a64cb": "0xC977d218Fde6A39c7aCE71C8243545c276B48931", + "0xbeef02e5e13584ab96848af90261f0c8ee04722a": "0x7E4B4DC22111B84594d9b7707A8DCFFd793D477A", + "0x2c25f6c25770ffec5959d34b94bf898865e5d6b1": "0x3D3eb99C278C7A50d8cf5fE7eBF0AD69066Fb7d1", + "0x78fc2c2ed1a4cdb5402365934ae5648adad094d0": "0x733c33339684F38C8aADA0434751611e168255c4", + "0x9bbf31e99f30c38a5003952206c31eea77540bef": "0xC6625129C9df3314a4dd604845488f4bA62F9dB8" + }, + "lastUpdated": { + "0xfbd1a538f5707c0d67a16ca4e3fc711b80bd931a": "2024-05-02T02:11:46.313Z", + "0x6b175474e89094c44da98b954eedeac495271d0f": "2024-05-02T02:11:34.493Z", + "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": "2024-05-02T02:11:34.631Z", + "0xdac17f958d2ee523a2206206994597c13d831ec7": "2024-05-02T02:11:34.780Z", + "0x4fabb145d64652a948d72533023f6e7a623c7c53": "2024-05-02T02:11:35.369Z", + "0x8e870d67f660d95d5be530380d0ec0bd388289e1": "2024-05-02T02:11:36.021Z", + "0x0000000000085d4780b73119b644ae5ecd22b376": "2024-05-02T02:11:36.361Z", + "0x57ab1ec28d129707052df4df418d58a2d46d5f51": "2024-05-02T02:11:36.568Z", + "0x853d955acef822db058eb8505911ed77f175b99e": "2024-05-02T02:11:36.725Z", + "0x99d8a9c45b2eca8864373a26d1459e3dff1e17f3": "2024-05-02T02:11:37.105Z", + "0xf939e0a03fb07f59a73314e73794be0e57ac1b4e": "2024-05-02T02:11:37.529Z", + "0xa0d69e286b938e21cbf7e51d71f6a4c8918f482f": "2024-05-02T02:11:49.841Z", + "0x028171bca77440897b824ca71d1c56cac55b68a3": "2024-05-02T02:11:37.783Z", + "0xbcca60bb61934080951369a648fb03df4f96263c": "2024-05-02T02:11:37.936Z", + "0x3ed3b47dd13ec9a98b44e6204a523e766b225811": "2024-05-02T02:11:38.094Z", + "0xa361718326c15715591c299427c62086f69923d9": "2024-05-02T02:11:38.433Z", + "0x2e8f4bdbe3d47d7d7de490437aea9915d930f1a3": "2024-05-02T02:11:38.717Z", + "0x030ba81f1c18d280636f32af80b9aad02cf0854e": "2024-05-02T02:11:38.928Z", + "0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c": "2024-05-02T02:11:39.073Z", + "0x093cb4f405924a0c468b43209d5e466f1dd0ac7d": "2024-05-01T16:12:29.624Z", + "0x5d3a536e4d6dbd6114cc1ead35777bab948e3643": "2024-05-02T02:11:39.347Z", + "0x39aa39c021dfbae8fac545936693ac917d5e7563": "2024-05-02T02:11:39.804Z", + "0xf650c3d88d12db855b8bf7d11be6c55a4e07dcc9": "2024-05-02T02:11:40.098Z", + "0x041171993284df560249b57358f931d9eb7b925d": "2024-05-02T02:11:40.253Z", + "0x4ddc2d193948926d02f9b1fe9e1daa0718270ed5": "2024-05-02T02:11:40.801Z", + "0xccf4429db6322d5c611ee964527d42e5d685dd6a": "2024-05-02T02:11:40.942Z", + "0x465a5a630482f3abd6d3b84b39b29b07214d19e5": "2024-05-02T02:11:41.068Z", + "0x81994b9607e06ab3d5cf3afff9a67374f05f27d7": "2024-05-02T02:11:41.168Z", + "0x1c9a2d6b33b4826757273d47ebee0e2dddcd978b": "2024-05-02T02:11:41.262Z", + "0xe2ba8693ce7474900a045757fe0efca900f6530b": "2024-05-02T02:11:41.393Z", + "0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9": "2024-05-02T02:11:42.140Z", + "0x4da27a545c0c5b758a6ba100e3a049001de870f5": "2024-05-02T02:11:42.337Z", + "0xc00e94cb662c3520282e6f5717214004a7f26888": "2024-05-02T02:11:42.548Z", + "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2": "2024-05-02T02:11:43.099Z", + "0x9ff58f4ffb29fa2266ab25e75e2a8b3503311656": "2024-05-02T02:11:43.243Z", + "0x8dae6cb04688c62d939ed9b68d32bc62e49970b1": "2024-05-02T02:11:43.367Z", + "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599": "2024-05-02T02:11:43.821Z", + "0xc581b735a1688071a1746c968e0798d642ede491": "2024-05-02T02:11:43.940Z", + "0x320623b8e4ff03373931769a31fc52a4e78b5d70": "2024-05-02T02:11:44.121Z", + "0xd533a949740bb3306d119cc777fa900ba034cd52": "2024-05-02T02:11:44.562Z", + "0x4e3fbd56cd56c3e72c1403e103b45db9da5b9d2b": "2024-05-02T02:11:44.740Z", + "0xe95a203b1a91a908f9b9ce46459d101078c2c3cb": "2024-05-02T02:11:45.221Z", + "0x5e8422345238f34275888049021821e8e08caa1f": "2024-05-02T02:11:45.334Z", + "0xac3e018457b222d93114458476f3e3416abbe38f": "2024-05-02T02:11:45.476Z", + "0xae7ab96520de3a18e5e111b5eaab095312d7fe84": "2024-05-02T02:11:45.755Z", + "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0": "2024-05-02T02:11:45.929Z", + "0xae78736cd615f374d3085123a210448e74fc6393": "2024-05-02T02:11:46.130Z", + "0xc3d688b66703497daa19211eedff47f25384cdc3": "2024-05-02T02:11:46.235Z", + "0xfaba6f8e4a5e8ab82f62fe7c39859fa577269be3": "2024-05-02T02:11:46.579Z", + "0xa663b02cf0a4b149d2ad41910cb81e23e1c41c32": "2024-05-02T02:11:46.677Z", + "0x83f20f44975d03b1b09e64809b757c47f942beea": "2024-05-02T02:11:46.802Z", + "0xbe9895146f7af43049ca1c1ae358b0541ea49704": "2024-05-02T02:11:47.091Z", + "0xaf5191b0de278c7286d6c7cc6ab6bb8a73ba2cd6": "2024-05-02T02:11:47.333Z", + "0xdf0770df86a8034b3efef0a1bb3c889b8332ff56": "2024-05-02T02:11:47.488Z", + "0x38ea452219524bb87e18de1c24d3bb59510bd783": "2024-05-02T02:11:47.584Z", + "0x101816545f6bd2b1076434b54383a1e633390a2e": "2024-05-02T02:11:47.713Z", + "0x1982b2f5814301d4e9a8b0201555376e62f82428": "2024-05-02T02:11:47.935Z", + "0x9994e35db50125e0df82e4c2dde62496ce330999": "2024-05-02T02:11:48.057Z", + "0xf56fb6cc29f0666bdd1662feaae2a3c935ee3469": "2024-05-02T02:11:48.422Z", + "0x7ca00559b978cfde81297849be6151d3ccb408a9": "2024-05-02T02:11:48.810Z", + "0x6c3ea9036406852006290770bedfcaba0e23a0e8": "2024-05-02T02:11:48.960Z", + "0x0c0d01abf3e6adfca0989ebba9d6e85dd58eab1e": "2024-05-02T02:11:49.072Z", + "0xe72b141df173b999ae7c1adcbf60cc9833ce56a8": "2024-05-02T02:11:49.960Z", + "0xacdf0dba4b9839b96221a8487e9ca660a48212be": "2024-05-02T02:11:50.073Z", + "0xfc0b1eef20e4c68b3dcf36c4537cfa7ce46ca70b": "2024-05-02T02:11:50.194Z", + "0x0d86883faf4ffd7aeb116390af37746f45b6f378": "2024-05-02T02:11:50.289Z", + "0x78da5799cf427fee11e9996982f4150ece7a99a7": "2024-05-02T02:11:50.392Z", + "0x73968b9a57c6e53d41345fd57a6e6ae27d6cdb2f": "2024-05-02T02:11:44.902Z", + "0x48c3399719b582dd63eb5aadf12a40b4c3f52fa2": "2024-05-02T02:11:48.194Z", + "0xc55126051b22ebb829d00368f4b12bde432de5da": "2024-05-02T02:11:48.339Z", + "0x1576b2d7ef15a2ebe9c22c8765dd9c1efea8797b": "2024-05-02T02:11:49.159Z", + "0xbeef01735c132ada46aa9aa4c54623caa92a64cb": "2024-05-02T02:11:49.303Z", + "0xbeef02e5e13584ab96848af90261f0c8ee04722a": "2024-05-02T02:11:49.422Z", + "0x2c25f6c25770ffec5959d34b94bf898865e5d6b1": "2024-05-02T02:11:49.529Z", + "0x78fc2c2ed1a4cdb5402365934ae5648adad094d0": "2024-05-02T02:11:49.639Z", + "0x9bbf31e99f30c38a5003952206c31eea77540bef": "2024-05-02T02:11:49.748Z" + } +} \ No newline at end of file diff --git a/tasks/validation/whales/whales_31337.json b/tasks/validation/whales/whales_31337.json new file mode 100644 index 0000000000..808ba0a19b --- /dev/null +++ b/tasks/validation/whales/whales_31337.json @@ -0,0 +1,140 @@ +{ + "tokens": { + "0xfbd1a538f5707c0d67a16ca4e3fc711b80bd931a": "0xF014FEF41cCB703975827C8569a3f0940cFD80A4", + "0x6b175474e89094c44da98b954eedeac495271d0f": "0x40ec5B33f54e0E8A33A975908C5BA1c14e5BbbDf", + "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": "0x4B16c5dE96EB2117bBE5fd171E4d203624B014aa", + "0xdac17f958d2ee523a2206206994597c13d831ec7": "0xF977814e90dA44bFA03b6295A0616a897441aceC", + "0x4fabb145d64652a948d72533023f6e7a623c7c53": "0x8Fe348f2F890046719aAceA910F01d772Dc20a65", + "0x8e870d67f660d95d5be530380d0ec0bd388289e1": "0x38699d04656fF537ef8671b6b595402ebDBdf6f4", + "0x0000000000085d4780b73119b644ae5ecd22b376": "0x9FCc67D7DB763787BB1c7f3bC7f34d3C548c19Fe", + "0x57ab1ec28d129707052df4df418d58a2d46d5f51": "0x99F4176EE457afedFfCB1839c7aB7A030a5e4A92", + "0x853d955acef822db058eb8505911ed77f175b99e": "0xcE6431D21E3fb1036CE9973a3312368ED96F5CE7", + "0x99d8a9c45b2eca8864373a26d1459e3dff1e17f3": "0x439a5f0f5E8d149DDA9a0Ca367D4a8e4D6f83C10", + "0xf939e0a03fb07f59a73314e73794be0e57ac1b4e": "0xA920De414eA4Ab66b97dA1bFE9e6EcA7d4219635", + "0xa0d69e286b938e21cbf7e51d71f6a4c8918f482f": "0x3154Cf16ccdb4C6d922629664174b904d80F2C35", + "0x028171bca77440897b824ca71d1c56cac55b68a3": "0x07edE94cF6316F4809f2B725f5d79AD303fB4Dc8", + "0xbcca60bb61934080951369a648fb03df4f96263c": "0xc9E6E51C7dA9FF1198fdC5b3369EfeDA9b19C34c", + "0x3ed3b47dd13ec9a98b44e6204a523e766b225811": "0x295E5eE985246cfD09B615f8706854600084c529", + "0xa361718326c15715591c299427c62086f69923d9": "0xc579a79376148c4B17821C5Eb9434965f3a15C80", + "0x2e8f4bdbe3d47d7d7de490437aea9915d930f1a3": "0x01820D92f8F86947CA0454789172AD60e05817fA", + "0x030ba81f1c18d280636f32af80b9aad02cf0854e": "0x777777c9898D384F785Ee44Acfe945efDFf5f3E0", + "0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c": "0xA91661efEe567b353D55948C0f051C1A16E503A5", + "0x093cb4f405924a0c468b43209d5e466f1dd0ac7d": "0xF014FEF41cCB703975827C8569a3f0940cFD80A4", + "0x5d3a536e4d6dbd6114cc1ead35777bab948e3643": "0x30030383d959675eC884E7EC88F05EE0f186cC06", + "0x39aa39c021dfbae8fac545936693ac917d5e7563": "0xC2F61a6eEEC48d686901D325CDE9233b81c793F3", + "0xf650c3d88d12db855b8bf7d11be6c55a4e07dcc9": "0xb99CC7e10Fe0Acc68C50C7829F473d81e23249cc", + "0x041171993284df560249b57358f931d9eb7b925d": "0x01820D92f8F86947CA0454789172AD60e05817fA", + "0x4ddc2d193948926d02f9b1fe9e1daa0718270ed5": "0x08CFd293D687B6CEe139219a607ACBBC10A6eb25", + "0xccf4429db6322d5c611ee964527d42e5d685dd6a": "0xceEf57F6C40A7CB2392eaAD101Ee0440aA43bA42", + "0x465a5a630482f3abd6d3b84b39b29b07214d19e5": "0x7Fbe0de6ffA86f4B9528AA27029595429B0c74A9", + "0x81994b9607e06ab3d5cf3afff9a67374f05f27d7": "0x7Fbe0de6ffA86f4B9528AA27029595429B0c74A9", + "0x1c9a2d6b33b4826757273d47ebee0e2dddcd978b": "0x11cC283d06FA762061df2B0D2f0787651ceef659", + "0xe2ba8693ce7474900a045757fe0efca900f6530b": "0x7Fbe0de6ffA86f4B9528AA27029595429B0c74A9", + "0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9": "0x4da27a545c0c5B758a6BA100e3a049001de870f5", + "0x4da27a545c0c5b758a6ba100e3a049001de870f5": "0xb56333581B852e61E1413A2A7A66BF679D8ACf81", + "0xc00e94cb662c3520282e6f5717214004a7f26888": "0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B", + "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2": "0xF04a5cC80B1E94C69B48f5ee68a08CD2F09A7c3E", + "0x9ff58f4ffb29fa2266ab25e75e2a8b3503311656": "0x777777c9898D384F785Ee44Acfe945efDFf5f3E0", + "0x8dae6cb04688c62d939ed9b68d32bc62e49970b1": "0xB5587A54fF7022AC218438720BDCD840a32f0481", + "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599": "0x5Ee5bf7ae06D1Be5997A1A72006FE6C607eC6DE8", + "0xc581b735a1688071a1746c968e0798d642ede491": "0x5754284f345afc66a98fbB0a0Afe71e0F007B949", + "0x320623b8e4ff03373931769a31fc52a4e78b5d70": "0x6bab6EB87Aa5a1e4A8310C73bDAAA8A5dAAd81C1", + "0xd533a949740bb3306d119cc777fa900ba034cd52": "0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2", + "0x4e3fbd56cd56c3e72c1403e103b45db9da5b9d2b": "0x72a19342e8F1838460eBFCCEf09F6585e32db86E", + "0xe95a203b1a91a908f9b9ce46459d101078c2c3cb": "0xF02e86D9E0eFd57aD034FaF52201B79917fE0713", + "0x5e8422345238f34275888049021821e8e08caa1f": "0xac3E018457B222d93114458476f3E3416Abbe38F", + "0xac3e018457b222d93114458476f3e3416abbe38f": "0x78bB3aEC3d855431bd9289fD98dA13F9ebB7ef15", + "0xae7ab96520de3a18e5e111b5eaab095312d7fe84": "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", + "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0": "0x0B925eD163218f6662a35e0f0371Ac234f9E9371", + "0xae78736cd615f374d3085123a210448e74fc6393": "0x1BeE69b7dFFfA4E2d53C2a2Df135C388AD25dCD2", + "0xc3d688b66703497daa19211eedff47f25384cdc3": "0x7f714b13249BeD8fdE2ef3FBDfB18Ed525544B03", + "0xfaba6f8e4a5e8ab82f62fe7c39859fa577269be3": "0x677FD4Ed8aE623f2f625DEB2D64F2070E46cA1A1", + "0xa663b02cf0a4b149d2ad41910cb81e23e1c41c32": "0x6A7efa964Cf6D9Ab3BC3c47eBdDB853A8853C502", + "0x83f20f44975d03b1b09e64809b757c47f942beea": "0xDdE0d6e90bfB74f1dC8ea070cFd0c0180C03Ad16", + "0xbe9895146f7af43049ca1c1ae358b0541ea49704": "0xED1F7bb04D2BA2b6EbE087026F03C96Ea2c357A8", + "0xaf5191b0de278c7286d6c7cc6ab6bb8a73ba2cd6": "0x65bb797c2B9830d891D87288F029ed8dACc19705", + "0xdf0770df86a8034b3efef0a1bb3c889b8332ff56": "0xB0D502E938ed5f4df2E681fE6E419ff29631d62b", + "0x38ea452219524bb87e18de1c24d3bb59510bd783": "0xB0D502E938ed5f4df2E681fE6E419ff29631d62b", + "0x101816545f6bd2b1076434b54383a1e633390a2e": "0xB0D502E938ed5f4df2E681fE6E419ff29631d62b", + "0x1982b2f5814301d4e9a8b0201555376e62f82428": "0x777777c9898D384F785Ee44Acfe945efDFf5f3E0", + "0x9994e35db50125e0df82e4c2dde62496ce330999": "0xcBa28b38103307Ec8dA98377ffF9816C164f9AFa", + "0xf56fb6cc29f0666bdd1662feaae2a3c935ee3469": "0x93A62dA5a14C80f265DAbC077fCEE437B1a0Efde", + "0x7ca00559b978cfde81297849be6151d3ccb408a9": "0xa931b486F661540c6D709aE6DfC8BcEF347ea437", + "0x6c3ea9036406852006290770bedfcaba0e23a0e8": "0xE25a329d385f77df5D4eD56265babe2b99A5436e", + "0x0c0d01abf3e6adfca0989ebba9d6e85dd58eab1e": "0x01820D92f8F86947CA0454789172AD60e05817fA", + "0xe72b141df173b999ae7c1adcbf60cc9833ce56a8": "0x7cc1bfAB73bE4E02BB53814d1059A98cF7e49644", + "0xacdf0dba4b9839b96221a8487e9ca660a48212be": "0x7cc1bfAB73bE4E02BB53814d1059A98cF7e49644", + "0xfc0b1eef20e4c68b3dcf36c4537cfa7ce46ca70b": "0xF2B25362a03f6EACCa8De8d5350A9f37944c1e59", + "0x0d86883faf4ffd7aeb116390af37746f45b6f378": "0x7cc1bfAB73bE4E02BB53814d1059A98cF7e49644", + "0x78da5799cf427fee11e9996982f4150ece7a99a7": "0x3154Cf16ccdb4C6d922629664174b904d80F2C35" + }, + "lastUpdated": { + "0xfbd1a538f5707c0d67a16ca4e3fc711b80bd931a": "2024-05-01T16:12:37.530Z", + "0x6b175474e89094c44da98b954eedeac495271d0f": "2024-05-01T16:12:25.407Z", + "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": "2024-05-01T16:12:25.554Z", + "0xdac17f958d2ee523a2206206994597c13d831ec7": "2024-05-01T16:12:25.703Z", + "0x4fabb145d64652a948d72533023f6e7a623c7c53": "2024-05-01T16:12:26.453Z", + "0x8e870d67f660d95d5be530380d0ec0bd388289e1": "2024-05-01T16:12:27.130Z", + "0x0000000000085d4780b73119b644ae5ecd22b376": "2024-05-01T16:12:27.569Z", + "0x57ab1ec28d129707052df4df418d58a2d46d5f51": "2024-05-01T16:12:27.764Z", + "0x853d955acef822db058eb8505911ed77f175b99e": "2024-05-01T16:12:27.975Z", + "0x99d8a9c45b2eca8864373a26d1459e3dff1e17f3": "2024-05-01T16:12:28.088Z", + "0xf939e0a03fb07f59a73314e73794be0e57ac1b4e": "2024-05-01T16:12:28.205Z", + "0xa0d69e286b938e21cbf7e51d71f6a4c8918f482f": "2024-05-01T16:12:40.247Z", + "0x028171bca77440897b824ca71d1c56cac55b68a3": "2024-05-01T16:12:28.532Z", + "0xbcca60bb61934080951369a648fb03df4f96263c": "2024-05-01T16:12:28.694Z", + "0x3ed3b47dd13ec9a98b44e6204a523e766b225811": "2024-05-01T16:12:28.810Z", + "0xa361718326c15715591c299427c62086f69923d9": "2024-05-01T16:12:28.910Z", + "0x2e8f4bdbe3d47d7d7de490437aea9915d930f1a3": "2024-05-01T16:12:29.070Z", + "0x030ba81f1c18d280636f32af80b9aad02cf0854e": "2024-05-01T16:12:29.261Z", + "0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c": "2024-05-01T16:12:29.463Z", + "0x093cb4f405924a0c468b43209d5e466f1dd0ac7d": "2024-05-01T16:12:29.624Z", + "0x5d3a536e4d6dbd6114cc1ead35777bab948e3643": "2024-05-01T16:12:29.787Z", + "0x39aa39c021dfbae8fac545936693ac917d5e7563": "2024-05-01T16:12:30.022Z", + "0xf650c3d88d12db855b8bf7d11be6c55a4e07dcc9": "2024-05-01T16:12:30.189Z", + "0x041171993284df560249b57358f931d9eb7b925d": "2024-05-01T16:12:30.288Z", + "0x4ddc2d193948926d02f9b1fe9e1daa0718270ed5": "2024-05-01T16:12:30.721Z", + "0xccf4429db6322d5c611ee964527d42e5d685dd6a": "2024-05-01T16:12:30.991Z", + "0x465a5a630482f3abd6d3b84b39b29b07214d19e5": "2024-05-01T16:12:31.228Z", + "0x81994b9607e06ab3d5cf3afff9a67374f05f27d7": "2024-05-01T16:12:31.501Z", + "0x1c9a2d6b33b4826757273d47ebee0e2dddcd978b": "2024-05-01T16:12:31.605Z", + "0xe2ba8693ce7474900a045757fe0efca900f6530b": "2024-05-01T16:12:31.723Z", + "0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9": "2024-05-01T16:12:32.700Z", + "0x4da27a545c0c5b758a6ba100e3a049001de870f5": "2024-05-01T16:12:32.886Z", + "0xc00e94cb662c3520282e6f5717214004a7f26888": "2024-05-01T16:12:33.230Z", + "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2": "2024-05-01T16:12:33.980Z", + "0x9ff58f4ffb29fa2266ab25e75e2a8b3503311656": "2024-05-01T16:12:34.120Z", + "0x8dae6cb04688c62d939ed9b68d32bc62e49970b1": "2024-05-01T16:12:34.389Z", + "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599": "2024-05-01T16:12:34.970Z", + "0xc581b735a1688071a1746c968e0798d642ede491": "2024-05-01T16:12:35.065Z", + "0x320623b8e4ff03373931769a31fc52a4e78b5d70": "2024-05-01T16:12:35.305Z", + "0xd533a949740bb3306d119cc777fa900ba034cd52": "2024-05-01T16:12:35.845Z", + "0x4e3fbd56cd56c3e72c1403e103b45db9da5b9d2b": "2024-05-01T16:12:36.092Z", + "0xe95a203b1a91a908f9b9ce46459d101078c2c3cb": "2024-05-01T16:12:36.200Z", + "0x5e8422345238f34275888049021821e8e08caa1f": "2024-05-01T16:12:36.316Z", + "0xac3e018457b222d93114458476f3e3416abbe38f": "2024-05-01T16:12:36.462Z", + "0xae7ab96520de3a18e5e111b5eaab095312d7fe84": "2024-05-01T16:12:36.867Z", + "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0": "2024-05-01T16:12:37.045Z", + "0xae78736cd615f374d3085123a210448e74fc6393": "2024-05-01T16:12:37.238Z", + "0xc3d688b66703497daa19211eedff47f25384cdc3": "2024-05-01T16:12:37.349Z", + "0xfaba6f8e4a5e8ab82f62fe7c39859fa577269be3": "2024-05-01T16:12:37.800Z", + "0xa663b02cf0a4b149d2ad41910cb81e23e1c41c32": "2024-05-01T16:12:37.889Z", + "0x83f20f44975d03b1b09e64809b757c47f942beea": "2024-05-01T16:12:38.007Z", + "0xbe9895146f7af43049ca1c1ae358b0541ea49704": "2024-05-01T16:12:38.340Z", + "0xaf5191b0de278c7286d6c7cc6ab6bb8a73ba2cd6": "2024-05-01T16:12:38.615Z", + "0xdf0770df86a8034b3efef0a1bb3c889b8332ff56": "2024-05-01T16:12:38.909Z", + "0x38ea452219524bb87e18de1c24d3bb59510bd783": "2024-05-01T16:12:39.004Z", + "0x101816545f6bd2b1076434b54383a1e633390a2e": "2024-05-01T16:12:39.156Z", + "0x1982b2f5814301d4e9a8b0201555376e62f82428": "2024-05-01T16:12:39.350Z", + "0x9994e35db50125e0df82e4c2dde62496ce330999": "2024-05-01T16:12:39.452Z", + "0xf56fb6cc29f0666bdd1662feaae2a3c935ee3469": "2024-05-01T16:12:39.550Z", + "0x7ca00559b978cfde81297849be6151d3ccb408a9": "2024-05-01T16:12:39.629Z", + "0x6c3ea9036406852006290770bedfcaba0e23a0e8": "2024-05-01T16:12:39.775Z", + "0x0c0d01abf3e6adfca0989ebba9d6e85dd58eab1e": "2024-05-01T16:12:39.942Z", + "0xe72b141df173b999ae7c1adcbf60cc9833ce56a8": "2024-05-01T16:12:40.337Z", + "0xacdf0dba4b9839b96221a8487e9ca660a48212be": "2024-05-01T16:12:40.447Z", + "0xfc0b1eef20e4c68b3dcf36c4537cfa7ce46ca70b": "2024-05-01T16:12:40.528Z", + "0x0d86883faf4ffd7aeb116390af37746f45b6f378": "2024-05-01T16:12:40.659Z", + "0x78da5799cf427fee11e9996982f4150ece7a99a7": "2024-05-01T16:12:40.776Z" + } +} \ No newline at end of file diff --git a/tasks/validation/whales/whales_8453.json b/tasks/validation/whales/whales_8453.json new file mode 100644 index 0000000000..1b7fdbe5d6 --- /dev/null +++ b/tasks/validation/whales/whales_8453.json @@ -0,0 +1,54 @@ +{ + "tokens": { + "0x50c5725949a6f0c72e6c4a641f24049a917db0cb": "0x73b06d8d18de422e269645eace15400de7462417", + "0xd9aaec86b65d86f6a7b5b1b0c42ffa531710b6ca": "0x0b25c51637c43decd6cc1c1e3da4518d54ddb528", + "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913": "0x7c41fdced2ea646ed85665d1a9b28e6632b61c41", + "0xab36452dbac151be02b16ca17d8919826072f64a": "0x796d2367af69deb3319b8e10712b8b65957371c3", + "0x9e1028f5f1d5ede59748ffcee5532509976840e0": "0x123964802e6ababbe1bc9547d72ef1b69b00a6b1", + "0x4200000000000000000000000000000000000006": "0xcdac0d6c6c59727a65f871236188350531885c43", + "0x2ae3f1ec7f1f5012cfeab0185bfc7aa3cf0dec22": "0x3bf93770f2d4a794c3d9ebefbaebae2a8f09a5e5", + "0x9c4ec768c28520b50860ea7a15bd7213a9ff58bf": "0xd2c32f54a26285decf30e6d208f722e7d5fd3f58", + "0xb125e6687d4313864e53df431d5425969c15eb2f": "0xa694f7177c6c839c951c74c797283b35d0a486c8", + "0xa694f7177c6c839c951c74c797283b35d0a486c8": "0xa1e1a94977ec3159db546bf01d7a8d17dd3ebbed", + "0x4e65fe4dba92790696d040ac24aa414708f5c0ab": "0x09ad6981381610a5f58c56219f0fe939043f0a36", + "0x184460704886f9f2a7f3a0c2887680867954dc6e": "0xa1e1a94977ec3159db546bf01d7a8d17dd3ebbed", + "0xd4a0e0b9149bcee3c920d2e00b5de09138fd8bb7": "0x28b41cf49c00fe3787cd962feef93238f569c77b", + "0xcf3d55c10db69f28fd1a75bd73f3d8a2d9c595ad": "0x8c789c68cd1277846c6ffdbf3ea0ca460a0fe78b", + "0x4c80e24119cfb836cdf0a6b53dc23f04f7e652ca": "0x06eb48763f117c7be887296cdcdfad2e4092739c", + "0xc1cba3fcea344f92d9239c08c0568f6f2f0ee452": "0x627fe393bc6edda28e99ae648fd6ff362514304b", + "0xe3b53af74a4bf62ae5511055290838050bf764df": "0x1d7c6783328c145393e84fb47a7f7c548f5ee28d", + "0xcfa3ef56d303ae4faaba0592388f19d7c3399fb4": "0xb5e331615fdba7df49e05cdeaceb14acdd5091c3", + "0xefb97aaf77993922ac4be4da8fbc9a2425322677": "0xd3561da2bfcac843494854f7de1af98a3962925f", + "0x8e5e9df4f0ea39ae5270e79bbabfcc34203a3470": "0xd7adbf474e991f4aebf95c0b095001ce661aad17", + "0xcc7ff230365bd730ee4b352cc2492cedac49383e": "0xb5e331615fdba7df49e05cdeaceb14acdd5091c3", + "0xcb327b99ff831bf8223cced12b1338ff3aa322ff": "0x6b87b8663ee63191887f18225f79d9eeb2de0d34", + "0xfe0d6d83033e313691e96909d2188c150b834285": "0x1ef46018244179810dec43291d693cb2bf7f40e5", + "0xc9a3e2b3064c1c0546d3d0edc0a748e9f93cf18d": "0x6f1d6b86d4ad705385e751e6e88b0fdfdbadf298" + }, + "lastUpdated": { + "0x50c5725949a6f0c72e6c4a641f24049a917db0cb": "2024-05-02T02:08:54.913Z", + "0xd9aaec86b65d86f6a7b5b1b0c42ffa531710b6ca": "2024-05-02T02:09:09.449Z", + "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913": "2024-05-02T02:09:20.185Z", + "0xab36452dbac151be02b16ca17d8919826072f64a": "2024-05-02T02:09:20.356Z", + "0x9e1028f5f1d5ede59748ffcee5532509976840e0": "2024-05-02T02:09:20.574Z", + "0x4200000000000000000000000000000000000006": "2024-05-02T02:09:23.915Z", + "0x2ae3f1ec7f1f5012cfeab0185bfc7aa3cf0dec22": "2024-05-02T02:09:24.479Z", + "0x9c4ec768c28520b50860ea7a15bd7213a9ff58bf": "2024-05-02T02:09:24.656Z", + "0xb125e6687d4313864e53df431d5425969c15eb2f": "2024-05-02T02:09:24.843Z", + "0xa694f7177c6c839c951c74c797283b35d0a486c8": "2024-05-02T02:09:24.946Z", + "0x4e65fe4dba92790696d040ac24aa414708f5c0ab": "2024-05-02T02:09:25.575Z", + "0x184460704886f9f2a7f3a0c2887680867954dc6e": "2024-05-02T02:09:25.682Z", + "0xd4a0e0b9149bcee3c920d2e00b5de09138fd8bb7": "2024-05-02T02:09:27.328Z", + "0xcf3d55c10db69f28fd1a75bd73f3d8a2d9c595ad": "2024-05-02T02:09:27.473Z", + "0x4c80e24119cfb836cdf0a6b53dc23f04f7e652ca": "2024-05-02T02:09:28.015Z", + "0xc1cba3fcea344f92d9239c08c0568f6f2f0ee452": "2024-05-02T02:09:28.612Z", + "0xe3b53af74a4bf62ae5511055290838050bf764df": "2024-05-02T02:09:30.272Z", + "0xcfa3ef56d303ae4faaba0592388f19d7c3399fb4": "2024-05-02T02:09:30.448Z", + "0xefb97aaf77993922ac4be4da8fbc9a2425322677": "2024-05-02T02:09:30.580Z", + "0x8e5e9df4f0ea39ae5270e79bbabfcc34203a3470": "2024-05-02T02:09:30.808Z", + "0xcc7ff230365bd730ee4b352cc2492cedac49383e": "2024-05-02T02:09:30.955Z", + "0xcb327b99ff831bf8223cced12b1338ff3aa322ff": "2024-05-02T02:09:31.083Z", + "0xfe0d6d83033e313691e96909d2188c150b834285": "2024-05-02T02:09:31.159Z", + "0xc9a3e2b3064c1c0546d3d0edc0a748e9f93cf18d": "2024-05-02T02:09:31.258Z" + } +} \ No newline at end of file diff --git a/test/Facade.test.ts b/test/Facade.test.ts index 903d9bee7a..6b2b8f5d5e 100644 --- a/test/Facade.test.ts +++ b/test/Facade.test.ts @@ -55,13 +55,7 @@ import { PRICE_TIMEOUT, } from './fixtures' import { advanceToTimestamp, getLatestBlockTimestamp, setNextBlockTimestamp } from './utils/time' -import { - CollateralStatus, - TradeKind, - MAX_UINT256, - ONE_PERIOD, - ZERO_ADDRESS, -} from '#/common/constants' +import { CollateralStatus, TradeKind, MAX_UINT256, ZERO_ADDRESS } from '#/common/constants' import { expectTrade } from './utils/trades' import { mintCollaterals } from './utils/tokens' @@ -214,7 +208,7 @@ describe('Facade + FacadeMonitor contracts', () => { }) }) - describe('ReadFacet + ActFacet', () => { + describe('Facets', () => { let issueAmount: BigNumber const expectValidBasketBreakdown = async (rToken: TestIRToken) => { diff --git a/test/ZTradingExtremes.test.ts b/test/ZTradingExtremes.test.ts index 111faaefd4..e394a2105d 100644 --- a/test/ZTradingExtremes.test.ts +++ b/test/ZTradingExtremes.test.ts @@ -3,7 +3,13 @@ import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' import { expect } from 'chai' import { BigNumber, ContractFactory } from 'ethers' import { ethers } from 'hardhat' -import { IConfig, MAX_ORACLE_TIMEOUT, MAX_THROTTLE_AMT_RATE } from '../common/configuration' +import { + IConfig, + MAX_ORACLE_TIMEOUT, + MAX_THROTTLE_AMT_RATE, + MAX_BASKET_SIZE, + MAX_BACKUP_SIZE, +} from '../common/configuration' import { FURNACE_DEST, STRSR_DEST, MAX_UINT256, ZERO_ADDRESS } from '../common/constants' import { bn, fp, shortString, toBNDecimals, divCeil } from '../common/numbers' import { @@ -365,11 +371,11 @@ describeExtreme(`Trading Extreme Values (${SLOW ? 'slow mode' : 'fast mode'})`, if (SLOW) { dimensions = [ [fp('1e-6'), fp('1e30')], // RToken supply - [1, 100], // basket size + [1, MAX_BASKET_SIZE], // basket size [fp('1e-6'), fp('1e3'), fp('1')], // prime basket weights [8, 18], // collateral decimals [fp('1e9'), fp('1').add(fp('1e-9'))], // exchange rate at appreciation - [1, 100], // how many collateral assets appreciate (up to) + [1, MAX_BASKET_SIZE], // how many collateral assets appreciate (up to) [fp('0'), fp('1'), fp('0.6')], // StRSR cut (f) ] } else { @@ -515,7 +521,7 @@ describeExtreme(`Trading Extreme Values (${SLOW ? 'slow mode' : 'fast mode'})`, if (SLOW) { dimensions = [ [fp('1e-6'), fp('1e30')], // RToken supply - [1, 100], // basket size + [1, MAX_BASKET_SIZE], // basket size [1, 2], // num reward tokens [bn('0'), bn('1e11'), bn('1e6')], // reward amount (whole tokens), up to 100B supply tokens [fp('0'), fp('1'), fp('0.6')], // StRSR cut (f) @@ -638,11 +644,14 @@ describeExtreme(`Trading Extreme Values (${SLOW ? 'slow mode' : 'fast mode'})`, primeBasket.map((c) => c.address), targetAmts ) + + const bkpSize = basketSize <= MAX_BACKUP_SIZE ? basketSize : MAX_BACKUP_SIZE await basketHandler.connect(owner).setBackupConfig( ethers.utils.formatBytes32String('USD'), - basketSize, - primeBasket.map((c) => c.address) + bkpSize, + primeBasket.slice(-1 * bkpSize).map((c) => c.address) ) + await basketHandler.connect(owner).refreshBasket() await advanceTime(Number(config.warmupPeriod) + 1) @@ -680,10 +689,10 @@ describeExtreme(`Trading Extreme Values (${SLOW ? 'slow mode' : 'fast mode'})`, if (SLOW) { dimensions = [ [fp('1e-6'), fp('1e30')], // RToken supply - [2, 100], // basket size + [2, MAX_BASKET_SIZE], // basket size [fp('1e-6'), fp('1e3'), fp('1')], // prime basket weights [8, 18], // collateral decimals - [1, 99], // how many collateral assets default (up to) + [1, MAX_BASKET_SIZE - 1], // how many collateral assets default (up to) ] } else { dimensions = [ @@ -796,7 +805,7 @@ describeExtreme(`Trading Extreme Values (${SLOW ? 'slow mode' : 'fast mode'})`, } for (let i = 0; i < targetUnits; i++) { const targetUnit = ethers.utils.formatBytes32String(i.toString()) - await basketHandler.setBackupConfig(targetUnit, numPrimeTokens, backups[i]) + await basketHandler.setBackupConfig(targetUnit, numBackupTokens, backups[i]) } // Set prime basket with all collateral @@ -813,11 +822,12 @@ describeExtreme(`Trading Extreme Values (${SLOW ? 'slow mode' : 'fast mode'})`, } } - const size = SLOW ? 100 : 4 // Currently 100 takes >5 minutes to execute 32 cases + const size = SLOW ? MAX_BASKET_SIZE : 4 // Currently 100 takes >5 minutes to execute 32 cases + const bkpsize = SLOW ? MAX_BACKUP_SIZE : 4 const primeTokens = [size, 1] - const backupTokens = [size, 0] + const backupTokens = [bkpsize, 0] const targetUnits = [size, 1] diff --git a/test/fixtures.ts b/test/fixtures.ts index 1af9aa578d..c769bd5e94 100644 --- a/test/fixtures.ts +++ b/test/fixtures.ts @@ -46,6 +46,7 @@ import { GnosisTrade, IAssetRegistry, MainP1, + MaxIssuableFacet, MockV3Aggregator, RevenueTraderP1, RTokenAsset, @@ -411,6 +412,7 @@ export interface DefaultFixture extends RSRAndCompAaveAndCollateralAndModuleFixt facade: TestIFacade readFacet: ReadFacet actFacet: ActFacet + maxIssuableFacet: MaxIssuableFacet facadeTest: FacadeTest facadeMonitor: FacadeMonitor broker: TestIBroker @@ -751,6 +753,18 @@ const makeDefaultFixture = async (setBasket: boolean): Promise = Object.entries(actFacet.functions).map(([fn]) => actFacet.interface.getSighash(fn)) ) + // Save MaxIssuableFacet to Facade + const MaxIssuableFacetFactory: ContractFactory = await ethers.getContractFactory( + 'MaxIssuableFacet' + ) + const maxIssuableFacet = await MaxIssuableFacetFactory.deploy() + await facade.save( + maxIssuableFacet.address, + Object.entries(maxIssuableFacet.functions).map(([fn]) => + maxIssuableFacet.interface.getSighash(fn) + ) + ) + return { rsr, rsrAsset, @@ -782,6 +796,7 @@ const makeDefaultFixture = async (setBasket: boolean): Promise = facade, readFacet, actFacet, + maxIssuableFacet, facadeTest, facadeMonitor, rsrTrader, diff --git a/test/integration/fork-block-numbers.ts b/test/integration/fork-block-numbers.ts index a6ac53aa39..e0adbbffc9 100644 --- a/test/integration/fork-block-numbers.ts +++ b/test/integration/fork-block-numbers.ts @@ -9,7 +9,7 @@ const forkBlockNumber = { 'old-curve-plugins': 16915576, // Ethereum 'new-curve-plugins': 19626711, // Ethereum // TODO add all the block numbers we fork from to benefit from caching - default: 19635384, // Ethereum + default: 19742528, // Ethereum } export default forkBlockNumber diff --git a/test/plugins/individual-collateral/compoundv3/CometTestSuite.test.ts b/test/plugins/individual-collateral/compoundv3/CometTestSuite.test.ts index 008c69d1c3..78c334c90c 100644 --- a/test/plugins/individual-collateral/compoundv3/CometTestSuite.test.ts +++ b/test/plugins/individual-collateral/compoundv3/CometTestSuite.test.ts @@ -27,12 +27,7 @@ import { bn, fp } from '../../../../common/numbers' import { MAX_UINT48 } from '../../../../common/constants' import { expect } from 'chai' import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' -import { - advanceBlocks, - advanceTime, - getLatestBlockTimestamp, - setNextBlockTimestamp, -} from '../../../utils/time' +import { advanceBlocks, getLatestBlockTimestamp, setNextBlockTimestamp } from '../../../utils/time' import { forkNetwork, ORACLE_ERROR, diff --git a/test/plugins/individual-collateral/curve/collateralTests.ts b/test/plugins/individual-collateral/curve/collateralTests.ts index 25e8a39c40..572fef573c 100644 --- a/test/plugins/individual-collateral/curve/collateralTests.ts +++ b/test/plugins/individual-collateral/curve/collateralTests.ts @@ -88,10 +88,11 @@ export default function fn( describeFork(`Collateral: ${collateralName}`, () => { let defaultOpts: CurveCollateralOpts let mockERC20: ERC20Mock + let collateral: TestICollateral before(async () => { await resetFork() - ;[, defaultOpts] = await deployCollateral({}) + ;[collateral, defaultOpts] = await deployCollateral({}) const ERC20Factory = await ethers.getContractFactory('ERC20Mock') mockERC20 = await ERC20Factory.deploy('Mock ERC20', 'ERC20') }) @@ -147,7 +148,7 @@ export default function fn( await expect( deployCollateral({ - erc20: mockERC20.address, // can be anything. + erc20: await collateral.erc20(), feeds, oracleTimeouts, oracleErrors, @@ -343,11 +344,11 @@ export default function fn( await advanceToTimestamp((await getLatestBlockTimestamp()) + 12000) const before = await Promise.all( - ctx.rewardTokens.map((t) => t.balanceOf(ctx.wrapper.address)) + ctx.rewardTokens.map((t) => t.balanceOf(ctx.collateral.address)) ) - await expect(ctx.wrapper.claimRewards()).to.emit(ctx.wrapper, 'RewardsClaimed') + await expect(ctx.collateral.claimRewards()).to.emit(ctx.collateral, 'RewardsClaimed') const after = await Promise.all( - ctx.rewardTokens.map((t) => t.balanceOf(ctx.wrapper.address)) + ctx.rewardTokens.map((t) => t.balanceOf(ctx.collateral.address)) ) // Each reward token should have grew diff --git a/test/plugins/individual-collateral/curve/constants.ts b/test/plugins/individual-collateral/curve/constants.ts index cf99ac72e6..27039b9f5e 100644 --- a/test/plugins/individual-collateral/curve/constants.ts +++ b/test/plugins/individual-collateral/curve/constants.ts @@ -73,8 +73,19 @@ export const pyUSD = networkConfig['1'].tokens.pyUSD! export const RSR = networkConfig['1'].tokens.RSR! export const CRV = networkConfig['1'].tokens.CRV! export const CVX = networkConfig['1'].tokens.CVX! +export const SDT = networkConfig['1'].tokens.SDT! +// ETH+ export const ETHPLUS = networkConfig['1'].tokens.ETHPLUS! +export const ETHPLUS_ASSET_REGISTRY = '0xf526f058858E4cD060cFDD775077999562b31bE0' +export const ETHPLUS_BASKET_HANDLER = '0x56f40A33e3a3fE2F1614bf82CBeb35987ac10194' +export const ETHPLUS_TIMELOCK = '0x5f4A10aE2fF68bE3cdA7d7FB432b10C6BFA6457B' + +// USDC+ +export const USDCPLUS = networkConfig['1'].tokens.USDCPLUS! +export const USDCPLUS_ASSET_REGISTRY = '0xbCd2719E4862d1Eb32A36e8C956D3118ebB2f511' +export const USDCPLUS_BASKET_HANDLER = '0x162587b5B4c01d26AfaFD4A1ccA61CdC632c9508' +export const USDCPLUS_TIMELOCK = '0x6C957417cB6DF6e821eec8555DEE8b116C291999' // 3pool - USDC, USDT, DAI export const THREE_POOL = '0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7' @@ -113,7 +124,13 @@ export const ETHPLUS_BP_POOL = '0x7fb53345f1b21ab5d9510adb38f7d3590be6364b' export const ETHPLUS_BP_TOKEN = '0xe8a5677171c87fcb65b76957f2852515b404c7b1' export const ETHPLUS_BP_POOL_ID = 185 export const ETHPLUS_ETH_HOLDER = '0x298bf7b80a6343214634aF16EB41Bb5B9fC6A1F1' -export const ETHPLUS_GAUGE = '0x298bf7b80a6343214634af16eb41bb5b9fc6a1f1' + +// USDC + USDC+ +export const USDC_USDCPLUS_GAUGE = networkConfig['1'].tokens.sdUSDCUSDCPlus! +export const USDC_USDCPLUS_GAUGE_HOLDER = '0xC6625129C9df3314a4dd604845488f4bA62F9dB8' +export const USDC_USDCPLUS_POOL = '0xf2b25362a03f6eacca8de8d5350a9f37944c1e59' +export const USDC_USDCPLUS_LP_TOKEN = '0xfed2B54453F75634bcdaEA5e5b11a3f99b9C28Fa' +export const USDC_USDCPLUS_POOL_ID = 238 // MIM + 3pool export const MIM_THREE_POOL = '0x5a6A4D54456819380173272A5E8E9B9904BdF41B' diff --git a/test/plugins/individual-collateral/curve/cvx/CvxAppreciatingRTokenSelfReferential.test.ts b/test/plugins/individual-collateral/curve/cvx/CvxAppreciatingRTokenSelfReferential.test.ts index 0aa2d6883d..fd4df26b5b 100644 --- a/test/plugins/individual-collateral/curve/cvx/CvxAppreciatingRTokenSelfReferential.test.ts +++ b/test/plugins/individual-collateral/curve/cvx/CvxAppreciatingRTokenSelfReferential.test.ts @@ -40,15 +40,14 @@ import { CurvePoolType, CRV, ETHPLUS, + ETHPLUS_ASSET_REGISTRY, + ETHPLUS_BASKET_HANDLER, + ETHPLUS_TIMELOCK, } from '../constants' import { whileImpersonating } from '../../../../utils/impersonation' type Fixture = () => Promise -const ETHPLUS_ASSET_REGISTRY = '0xf526f058858E4cD060cFDD775077999562b31bE0' -const ETHPLUS_BASKET_HANDLER = '0x56f40A33e3a3fE2F1614bf82CBeb35987ac10194' -const ETHPLUS_TIMELOCK = '0x5f4A10aE2fF68bE3cdA7d7FB432b10C6BFA6457B' - export const defaultCvxAppreciatingCollateralOpts: CurveCollateralOpts = { erc20: ZERO_ADDRESS, targetName: ethers.utils.formatBytes32String('ETH'), @@ -63,7 +62,7 @@ export const defaultCvxAppreciatingCollateralOpts: CurveCollateralOpts = { nTokens: 2, curvePool: ETHPLUS_BP_POOL, lpToken: ETHPLUS_BP_TOKEN, - poolType: CurvePoolType.Plain, // for fraxBP, not the top-level pool + poolType: CurvePoolType.Plain, feeds: [[ONE_ADDRESS], [WETH_USD_FEED]], oracleTimeouts: [[bn('1')], [WETH_ORACLE_TIMEOUT]], oracleErrors: [[bn('1')], [WETH_ORACLE_ERROR]], diff --git a/test/plugins/individual-collateral/curve/cvx/helpers.ts b/test/plugins/individual-collateral/curve/cvx/helpers.ts index 6ed06a37fa..f137faa3b9 100644 --- a/test/plugins/individual-collateral/curve/cvx/helpers.ts +++ b/test/plugins/individual-collateral/curve/cvx/helpers.ts @@ -40,6 +40,8 @@ import { ETHPLUS, ETHPLUS_BP_POOL, ETHPLUS_BP_POOL_ID, + ETHPLUS_ASSET_REGISTRY, + ETHPLUS_TIMELOCK, } from '../constants' import { CurveBase } from '../pluginTestTypes' @@ -371,11 +373,8 @@ export const makeWETHPlusETH = async ( fp('1e6'), bn('1e1') ) - const ethplusAssetRegistry = await ethers.getContractAt( - 'IAssetRegistry', - '0xf526f058858E4cD060cFDD775077999562b31bE0' - ) - await whileImpersonating('0x5f4A10aE2fF68bE3cdA7d7FB432b10C6BFA6457B', async (signer) => { + const ethplusAssetRegistry = await ethers.getContractAt('IAssetRegistry', ETHPLUS_ASSET_REGISTRY) + await whileImpersonating(ETHPLUS_TIMELOCK, async (signer) => { await ethplusAssetRegistry.connect(signer).swapRegistered(mockRTokenAsset.address) }) @@ -383,7 +382,7 @@ export const makeWETHPlusETH = async ( const ethplus = await ethers.getContractAt('ERC20Mock', ETHPLUS) const weth = await ethers.getContractAt('ERC20Mock', WETH) - // Get real fraxBP pool + // Get real ETH+ pool const realCurvePool = await ethers.getContractAt('ICurvePool', ETHPLUS_BP_POOL) // Use mock curvePool seeded with initial balances @@ -398,8 +397,6 @@ export const makeWETHPlusETH = async ( const wrapperFactory = await ethers.getContractFactory('ConvexStakingWrapper') const wPool = await wrapperFactory.deploy() await wPool.initialize(ETHPLUS_BP_POOL_ID) - - // Ensure ETH+ isReady() return { ethplus, weth, curvePool, wPool } } diff --git a/test/plugins/individual-collateral/curve/stakedao/StakeDAORecursiveCollateral.test.ts b/test/plugins/individual-collateral/curve/stakedao/StakeDAORecursiveCollateral.test.ts new file mode 100644 index 0000000000..81c98fab5f --- /dev/null +++ b/test/plugins/individual-collateral/curve/stakedao/StakeDAORecursiveCollateral.test.ts @@ -0,0 +1,311 @@ +import collateralTests from '../collateralTests' +import forkBlockNumber from '#/test/integration/fork-block-numbers' +import { anyValue } from '@nomicfoundation/hardhat-chai-matchers/withArgs' +import { CollateralStatus } from '../../pluginTestTypes' +import { + CurveCollateralFixtureContext, + CurveCollateralOpts, + MintCurveCollateralFunc, +} from '../pluginTestTypes' +import { ORACLE_TIMEOUT_BUFFER } from '../../fixtures' +import { makeUSDCUSDCPlus, mintUSDCUSDCPlus } from './helpers' +import { expectEvents } from '#/common/events' +import { ethers } from 'hardhat' +import { ContractFactory, BigNumberish } from 'ethers' +import { expectExactPrice } from '../../../../utils/oracles' +import { getResetFork } from '../../helpers' +import { CurveBase } from '../pluginTestTypes' +import { + advanceBlocks, + advanceTime, + advanceToTimestamp, + getLatestBlockTimestamp, +} from '#/test/utils/time' +import { + ConvexStakingWrapper, + ERC20Mock, + MockV3Aggregator, + MockV3Aggregator__factory, + TestICollateral, +} from '../../../../../typechain' +import { bn } from '../../../../../common/numbers' +import { ZERO_ADDRESS, ONE_ADDRESS, MAX_UINT192 } from '../../../../../common/constants' +import { expect } from 'chai' +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +import { + PRICE_TIMEOUT, + USDC_USDCPLUS_POOL, + USDC_USDCPLUS_LP_TOKEN, + USDCPLUS_ASSET_REGISTRY, + USDCPLUS_TIMELOCK, + CVX, + USDC_USD_FEED, + USDC_ORACLE_TIMEOUT, + USDC_ORACLE_ERROR, + MAX_TRADE_VOL, + DEFAULT_THRESHOLD, + RTOKEN_DELAY_UNTIL_DEFAULT, + CurvePoolType, + CRV, + SDT, + USDCPLUS, +} from '../constants' +import { whileImpersonating } from '../../../../utils/impersonation' + +type Fixture = () => Promise + +export const defaultCvxRecursiveCollateralOpts: CurveCollateralOpts = { + erc20: ZERO_ADDRESS, + targetName: ethers.utils.formatBytes32String('USD'), + priceTimeout: PRICE_TIMEOUT, + chainlinkFeed: ONE_ADDRESS, // unused but cannot be zero + oracleTimeout: USDC_ORACLE_TIMEOUT, // max of oracleTimeouts + oracleError: bn('1'), // unused but cannot be zero + maxTradeVolume: MAX_TRADE_VOL, + defaultThreshold: DEFAULT_THRESHOLD, + delayUntilDefault: RTOKEN_DELAY_UNTIL_DEFAULT, + revenueHiding: bn('0'), + nTokens: 2, + curvePool: USDC_USDCPLUS_POOL, + lpToken: USDC_USDCPLUS_LP_TOKEN, + poolType: CurvePoolType.Plain, + feeds: [[USDC_USD_FEED], [ONE_ADDRESS]], + oracleTimeouts: [[USDC_ORACLE_TIMEOUT], [bn('1')]], + oracleErrors: [[USDC_ORACLE_ERROR], [bn('1')]], +} + +export const deployCollateral = async ( + opts: CurveCollateralOpts = {} +): Promise<[TestICollateral, CurveCollateralOpts]> => { + if (!opts.erc20 && !opts.feeds) { + const MockV3AggregatorFactory = ( + await ethers.getContractFactory('MockV3Aggregator') + ) + + // Substitute both feeds: USDC, USDC+ + const usdcFeed = await MockV3AggregatorFactory.deploy(8, bn('1e8')) + const usdcplusFeed = await MockV3AggregatorFactory.deploy(8, bn('1e8')) + const fix = await makeUSDCUSDCPlus(usdcplusFeed) + + opts.feeds = [[usdcFeed.address], [usdcplusFeed.address]] + opts.erc20 = fix.gauge.address + } + + opts = { ...defaultCvxRecursiveCollateralOpts, ...opts } + + const StakeDAORecursiveCollateralFactory: ContractFactory = await ethers.getContractFactory( + 'StakeDAORecursiveCollateral' + ) + + const collateral = await StakeDAORecursiveCollateralFactory.deploy( + { + erc20: opts.erc20, + targetName: opts.targetName, + priceTimeout: opts.priceTimeout, + chainlinkFeed: opts.chainlinkFeed, + oracleError: opts.oracleError, + oracleTimeout: opts.oracleTimeout, + maxTradeVolume: opts.maxTradeVolume, + defaultThreshold: opts.defaultThreshold, + delayUntilDefault: opts.delayUntilDefault, + }, + opts.revenueHiding, + { + nTokens: opts.nTokens, + curvePool: opts.curvePool, + poolType: opts.poolType, + feeds: opts.feeds, + oracleTimeouts: opts.oracleTimeouts, + oracleErrors: opts.oracleErrors, + lpToken: opts.lpToken, + } + ) + await collateral.deployed() + + // sometimes we are trying to test a negative test case and we want this to fail silently + // fortunately this syntax fails silently because our tools are terrible + await expect(collateral.refresh()) + + return [collateral as unknown as TestICollateral, opts] +} + +const makeCollateralFixtureContext = ( + alice: SignerWithAddress, + opts: CurveCollateralOpts = {} +): Fixture => { + const collateralOpts = { ...defaultCvxRecursiveCollateralOpts, ...opts } + + const makeCollateralFixtureContext = async () => { + const MockV3AggregatorFactory = ( + await ethers.getContractFactory('MockV3Aggregator') + ) + + // Substitute both feeds: USDC, USDC+ + const usdcFeed = await MockV3AggregatorFactory.deploy(8, bn('1e8')) + const usdcplusFeed = await MockV3AggregatorFactory.deploy(8, bn('1e8')) + const fix = await makeUSDCUSDCPlus(usdcplusFeed) + + collateralOpts.feeds = [[usdcFeed.address], [usdcplusFeed.address]] + collateralOpts.erc20 = fix.gauge.address + collateralOpts.curvePool = fix.curvePool.address + + const collateral = ((await deployCollateral(collateralOpts))[0] as unknown) + const sdt = await ethers.getContractAt('ERC20Mock', SDT) + const cvx = await ethers.getContractAt('ERC20Mock', CVX) + const crv = await ethers.getContractAt('ERC20Mock', CRV) + + return { + alice, + collateral, + curvePool: fix.curvePool, + wrapper: fix.gauge as unknown as ConvexStakingWrapper, // cast to make work with curve tests + rewardTokens: [sdt, cvx, crv], + chainlinkFeed: usdcFeed, + poolTokens: [fix.usdc, fix.usdcplus], + feeds: [usdcFeed, usdcplusFeed], + } + } + + return makeCollateralFixtureContext +} + +/* + Define helper functions +*/ + +const mintCollateralTo: MintCurveCollateralFunc = async ( + ctx: CurveCollateralFixtureContext, + amount: BigNumberish, + user: SignerWithAddress, + recipient: string +) => { + await mintUSDCUSDCPlus(ctx, amount, user, recipient) +} + +/* + Define collateral-specific tests +*/ + +// eslint-disable-next-line @typescript-eslint/no-empty-function +const collateralSpecificConstructorTests = () => {} + +// eslint-disable-next-line @typescript-eslint/no-empty-function +const collateralSpecificStatusTests = () => { + it('Does not depend on USDC+ RTokenAsset.price()', async () => { + const [collateral, opts] = await deployCollateral({}) + const initialPrice = await collateral.price() + expect(initialPrice[0]).to.be.gt(0) + expect(initialPrice[1]).to.be.lt(MAX_UINT192) + + // Swap out USDCPLUS's RTokenAsset with a mock one, which should be IGNORED + const AssetMockFactory = await ethers.getContractFactory('AssetMock') + const mockRTokenAsset = await AssetMockFactory.deploy( + bn('1'), // unused + ONE_ADDRESS, // unused + bn('1'), // unused + USDCPLUS, + bn('1'), // unused + bn('1') // unused + ) + const usdcplusAssetRegistry = await ethers.getContractAt( + 'IAssetRegistry', + USDCPLUS_ASSET_REGISTRY + ) + const usdcFeed = await ethers.getContractAt('MockV3Aggregator', opts.feeds![0][0]) + const initialAnswer = await usdcFeed.latestAnswer() + await whileImpersonating(USDCPLUS_TIMELOCK, async (signer) => { + await usdcplusAssetRegistry.connect(signer).swapRegistered(mockRTokenAsset.address) + }) + + // Set RTokenAsset to unpriced, which should end up being IGNORED + await mockRTokenAsset.setPrice(0, MAX_UINT192) + + // Should be SOUND still + await collateral.refresh() + expect(await collateral.status()).to.equal(CollateralStatus.SOUND) + await expectExactPrice(collateral.address, initialPrice) + + // SOUND after decay period + await advanceTime((await collateral.maxOracleTimeout()) + ORACLE_TIMEOUT_BUFFER) + await usdcFeed.updateAnswer(initialAnswer) + await collateral.refresh() + expect(await collateral.status()).to.equal(CollateralStatus.SOUND) + await expectExactPrice(collateral.address, initialPrice) + + // SOUND after full price timeout + await advanceTime(await collateral.priceTimeout()) + await usdcFeed.updateAnswer(initialAnswer) + await collateral.refresh() + expect(await collateral.status()).to.equal(CollateralStatus.SOUND) + await expectExactPrice(collateral.address, initialPrice) + }) + + it('Claims rewards', async () => { + // Reward claiming is tested here instead of in the generic suite due to not all 3 + // reward tokens being claimed for positive token balances + + const [collateral] = await deployCollateral() + const [alice] = await ethers.getSigners() + const amt = bn('200').mul(bn(10).pow(await collateral.erc20Decimals())) + + // Transfer some gauge token to the collateral plugin + await mintUSDCUSDCPlus({} as CurveBase, amt, alice, collateral.address) + + await advanceBlocks(1000) + await advanceToTimestamp((await getLatestBlockTimestamp()) + 12000) + + const rewardTokens = [ + // StakeDAO is waiting to start SDT/CVX rewards as of the time of this plugin development + // await ethers.getContractAt('ERC20Mock', SDT), + // await ethers.getContractAt('ERC20Mock', CVX), + await ethers.getContractAt('ERC20Mock', CRV), + ] + + // Expect 3 RewardsClaimed events to be emitted: [SDT, CVX, CRV] + const before = await Promise.all(rewardTokens.map((t) => t.balanceOf(collateral.address))) + await expectEvents(collateral.claimRewards(), [ + { + contract: collateral, + name: 'RewardsClaimed', + args: [SDT, anyValue], + emitted: true, + }, + { + contract: collateral, + name: 'RewardsClaimed', + args: [CRV, anyValue], + emitted: true, + }, + { + contract: collateral, + name: 'RewardsClaimed', + args: [CVX, anyValue], + emitted: true, + }, + ]) + + // All 3 reward token balances should grow + const after = await Promise.all(rewardTokens.map((t) => t.balanceOf(collateral.address))) + for (let i = 0; i < rewardTokens.length; i++) { + expect(after[i]).gt(before[i]) + } + }) +} + +/* + Run the test suite +*/ + +const opts = { + deployCollateral, + collateralSpecificConstructorTests, + collateralSpecificStatusTests, + makeCollateralFixtureContext, + mintCollateralTo, + itClaimsRewards: it.skip, // in this file + isMetapool: false, + resetFork: getResetFork(forkBlockNumber['new-curve-plugins']), + collateralName: 'StakeDAORecursiveCollateral - StakeDAOGauge', +} + +collateralTests(opts) diff --git a/test/plugins/individual-collateral/curve/stakedao/helpers.ts b/test/plugins/individual-collateral/curve/stakedao/helpers.ts new file mode 100644 index 0000000000..53c13e7269 --- /dev/null +++ b/test/plugins/individual-collateral/curve/stakedao/helpers.ts @@ -0,0 +1,82 @@ +import { ethers } from 'hardhat' +import { BigNumberish } from 'ethers' +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +import { whileImpersonating } from '../../../../utils/impersonation' +import { bn, fp } from '../../../../../common/numbers' +import { + CurvePoolMock, + ERC20Mock, + IStakeDAOGauge, + MockV3Aggregator, +} from '../../../../../typechain' +import { + USDC, + USDCPLUS, + USDC_USDCPLUS_POOL, + USDCPLUS_ASSET_REGISTRY, + USDCPLUS_TIMELOCK, + USDC_USDCPLUS_GAUGE, + USDC_USDCPLUS_GAUGE_HOLDER, +} from '../constants' +import { CurveBase } from '../pluginTestTypes' + +// ===== USDC/USDC+ + +export interface WrappedUSDCUSDCPlusFixture { + usdcplus: ERC20Mock + usdc: ERC20Mock + curvePool: CurvePoolMock + gauge: IStakeDAOGauge +} + +export const makeUSDCUSDCPlus = async ( + usdcplusFeed: MockV3Aggregator +): Promise => { + // Make a fake RTokenAsset and register it with USDC+'s assetRegistry + const AssetFactory = await ethers.getContractFactory('Asset') + const mockRTokenAsset = await AssetFactory.deploy( + bn('604800'), + usdcplusFeed.address, + fp('0.01'), + USDCPLUS, + fp('1e6'), + bn('1e1') + ) + const usdcplusAssetRegistry = await ethers.getContractAt( + 'IAssetRegistry', + USDCPLUS_ASSET_REGISTRY + ) + await whileImpersonating(USDCPLUS_TIMELOCK, async (signer) => { + await usdcplusAssetRegistry.connect(signer).swapRegistered(mockRTokenAsset.address) + }) + + // Use real reference ERC20s + const usdc = await ethers.getContractAt('ERC20Mock', USDC) + const usdcplus = await ethers.getContractAt('ERC20Mock', USDCPLUS) + + // Get real USDC+ pool + const realCurvePool = await ethers.getContractAt('ICurvePool', USDC_USDCPLUS_POOL) + + // Use mock curvePool seeded with initial balances + const CurveMockFactory = await ethers.getContractFactory('CurvePoolMock') + const curvePool = await CurveMockFactory.deploy( + [await realCurvePool.balances(0), await realCurvePool.balances(1)], + [await realCurvePool.coins(0), await realCurvePool.coins(1)] + ) + await curvePool.setVirtualPrice(await realCurvePool.get_virtual_price()) + + const gauge = await ethers.getContractAt('IStakeDAOGauge', USDC_USDCPLUS_GAUGE) + return { usdcplus, usdc, curvePool, gauge } +} + +export const mintUSDCUSDCPlus = async ( + ctx: CurveBase, + amount: BigNumberish, + user: SignerWithAddress, + recipient: string +) => { + const gauge = await ethers.getContractAt('IStakeDAOGauge', USDC_USDCPLUS_GAUGE) + await whileImpersonating(USDC_USDCPLUS_GAUGE_HOLDER, async (signer) => { + await gauge.connect(signer).transfer(recipient, amount) + }) +} diff --git a/test/plugins/individual-collateral/morpho-aave/MorphoAAVEFiatCollateral.test.ts b/test/plugins/individual-collateral/morpho-aave/MorphoAAVEFiatCollateral.test.ts index 7f1a19c867..9a9b94fad7 100644 --- a/test/plugins/individual-collateral/morpho-aave/MorphoAAVEFiatCollateral.test.ts +++ b/test/plugins/individual-collateral/morpho-aave/MorphoAAVEFiatCollateral.test.ts @@ -23,9 +23,11 @@ import hre from 'hardhat' import { MorphoAaveCollateralFixtureContext, mintCollateralTo } from './mintCollateralTo' import { setCode } from '@nomicfoundation/hardhat-network-helpers' import { whileImpersonating } from '#/utils/impersonation' -import { whales } from '#/tasks/testing/upgrade-checker-utils/constants' +import { whales } from '#/tasks/validation/utils/constants' import { advanceBlocks, advanceTime } from '#/utils/time' +whales[networkConfig['1'].tokens.USDC!.toLowerCase()] = '0xD6153F5af5679a75cC85D8974463545181f48772' + interface MAFiatCollateralOpts extends CollateralOpts { underlyingToken?: string poolToken?: string @@ -402,16 +404,16 @@ const makeOpts = ( Run the test suite */ const { tokens, chainlinkFeeds } = networkConfig[31337] -makeAaveFiatCollateralTestSuite( - 'MorphoAAVEV2FiatCollateral - USDT', - makeOpts(tokens.USDT!, tokens.aUSDT!, chainlinkFeeds.USDT!), - true // Only run specific tests once, since they are slow -) +// makeAaveFiatCollateralTestSuite( +// 'MorphoAAVEV2FiatCollateral - USDT', +// makeOpts(tokens.USDT!, tokens.aUSDT!, chainlinkFeeds.USDT!), +// true // Only run specific tests once, since they are slow +// ) makeAaveFiatCollateralTestSuite( 'MorphoAAVEV2FiatCollateral - USDC', makeOpts(tokens.USDC!, tokens.aUSDC!, chainlinkFeeds.USDC!) ) -makeAaveFiatCollateralTestSuite( - 'MorphoAAVEV2FiatCollateral - DAI', - makeOpts(tokens.DAI!, tokens.aDAI!, chainlinkFeeds.DAI!) -) +// makeAaveFiatCollateralTestSuite( +// 'MorphoAAVEV2FiatCollateral - DAI', +// makeOpts(tokens.DAI!, tokens.aDAI!, chainlinkFeeds.DAI!) +// ) diff --git a/test/plugins/individual-collateral/morpho-aave/MorphoAaveV2TokenisedDeposit.test.ts b/test/plugins/individual-collateral/morpho-aave/MorphoAaveV2TokenisedDeposit.test.ts index a23666dfd6..aa5a764dd4 100644 --- a/test/plugins/individual-collateral/morpho-aave/MorphoAaveV2TokenisedDeposit.test.ts +++ b/test/plugins/individual-collateral/morpho-aave/MorphoAaveV2TokenisedDeposit.test.ts @@ -2,7 +2,7 @@ import hre from 'hardhat' import { ITokens, networkConfig } from '#/common/configuration' import { ethers } from 'hardhat' import { whileImpersonating } from '../../../utils/impersonation' -import { whales } from '#/tasks/testing/upgrade-checker-utils/constants' +import { whales } from '#/tasks/validation/utils/constants' import { BigNumber, Signer } from 'ethers' import { formatUnits, parseUnits } from 'ethers/lib/utils' import { expect } from 'chai' diff --git a/test/plugins/individual-collateral/morpho-aave/mintCollateralTo.ts b/test/plugins/individual-collateral/morpho-aave/mintCollateralTo.ts index 300d04712d..1b817a821b 100644 --- a/test/plugins/individual-collateral/morpho-aave/mintCollateralTo.ts +++ b/test/plugins/individual-collateral/morpho-aave/mintCollateralTo.ts @@ -1,12 +1,14 @@ import { CollateralFixtureContext, MintCollateralFunc } from '../pluginTestTypes' import hre from 'hardhat' +import { networkConfig } from '#/common/configuration' import { BigNumberish, constants } from 'ethers' import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' -import { whales } from '#/tasks/testing/upgrade-checker-utils/constants' import { whileImpersonating } from '#/utils/impersonation' import { IERC20 } from '@typechain/IERC20' import { MockV3Aggregator } from '@typechain/MockV3Aggregator' import { MorphoAaveV2TokenisedDepositMock } from '@typechain/MorphoAaveV2TokenisedDepositMock' +import { getChainId } from '#/common/blockchain-utils' +import { Whales, getWhalesFile } from '#/scripts/whalesConfig' /** * Interface representing the context object for the MorphoAaveCollateralFixture. @@ -32,6 +34,11 @@ export const mintCollateralTo: MintCollateralFunc { + const chainId = await getChainId(hre) + const whales: Whales = getWhalesFile(chainId).tokens + whales[networkConfig['1'].tokens.USDC!.toLowerCase()] = + '0xD6153F5af5679a75cC85D8974463545181f48772' + await whileImpersonating( hre, whales[ctx.underlyingErc20.address.toLowerCase()], diff --git a/utils/env.ts b/utils/env.ts index 69b7ad5e7b..8deae52e77 100644 --- a/utils/env.ts +++ b/utils/env.ts @@ -28,6 +28,7 @@ type IEnvVars = | 'ARBITRUM_RPC_URL' | 'FORK_NETWORK' | 'FORK_BLOCK' + | 'FORCE_WHALE_REFRESH' export function useEnv(key: IEnvVars | IEnvVars[], _default = ''): string { if (typeof key === 'string') { diff --git a/yarn.lock b/yarn.lock index a016a1ddf8..2d1ce5e6aa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2846,6 +2846,17 @@ __metadata: languageName: node linkType: hard +"axios-retry@npm:^4.1.0": + version: 4.1.0 + resolution: "axios-retry@npm:4.1.0" + dependencies: + is-retry-allowed: ^2.2.0 + peerDependencies: + axios: 0.x || 1.x + checksum: e1e07f710d12e3367bc1e934b49f3056bc6a1d8c4b1c5cc69afb89841c5ee360fe36565894d53c043c7ea43bc7ac353b87573c8d6d721b12ac4d567be38cc117 + languageName: node + linkType: hard + "axios@npm:^0.21.1, axios@npm:^0.21.2": version: 0.21.4 resolution: "axios@npm:0.21.4" @@ -2855,15 +2866,6 @@ __metadata: languageName: node linkType: hard -"axios@npm:^0.24.0": - version: 0.24.0 - resolution: "axios@npm:0.24.0" - dependencies: - follow-redirects: ^1.14.4 - checksum: 468cf496c08a6aadfb7e699bebdac02851e3043d4e7d282350804ea8900e30d368daa6e3cd4ab83b8ddb5a3b1e17a5a21ada13fc9cebd27b74828f47a4236316 - languageName: node - linkType: hard - "axios@npm:^0.27.2": version: 0.27.2 resolution: "axios@npm:0.27.2" @@ -2885,6 +2887,17 @@ __metadata: languageName: node linkType: hard +"axios@npm:^1.6.8": + version: 1.6.8 + resolution: "axios@npm:1.6.8" + dependencies: + follow-redirects: ^1.15.6 + form-data: ^4.0.0 + proxy-from-env: ^1.1.0 + checksum: bf007fa4b207d102459300698620b3b0873503c6d47bf5a8f6e43c0c64c90035a4f698b55027ca1958f61ab43723df2781c38a99711848d232cad7accbcdfcdd + languageName: node + linkType: hard + "babel-plugin-istanbul@npm:^6.1.1": version: 6.1.1 resolution: "babel-plugin-istanbul@npm:6.1.1" @@ -3028,6 +3041,13 @@ __metadata: languageName: node linkType: hard +"boolbase@npm:^1.0.0": + version: 1.0.0 + resolution: "boolbase@npm:1.0.0" + checksum: 3e25c80ef626c3a3487c73dbfc70ac322ec830666c9ad915d11b701142fab25ec1e63eff2c450c74347acfd2de854ccde865cd79ef4db1683f7c7b046ea43bb0 + languageName: node + linkType: hard + "brace-expansion@npm:^1.1.7": version: 1.1.11 resolution: "brace-expansion@npm:1.1.11" @@ -3385,6 +3405,35 @@ __metadata: languageName: node linkType: hard +"cheerio-select@npm:^2.1.0": + version: 2.1.0 + resolution: "cheerio-select@npm:2.1.0" + dependencies: + boolbase: ^1.0.0 + css-select: ^5.1.0 + css-what: ^6.1.0 + domelementtype: ^2.3.0 + domhandler: ^5.0.3 + domutils: ^3.0.1 + checksum: 843d6d479922f28a6c5342c935aff1347491156814de63c585a6eb73baf7bb4185c1b4383a1195dca0f12e3946d737c7763bcef0b9544c515d905c5c44c5308b + languageName: node + linkType: hard + +"cheerio@npm:^1.0.0-rc.12": + version: 1.0.0-rc.12 + resolution: "cheerio@npm:1.0.0-rc.12" + dependencies: + cheerio-select: ^2.1.0 + dom-serializer: ^2.0.0 + domhandler: ^5.0.3 + domutils: ^3.0.1 + htmlparser2: ^8.0.1 + parse5: ^7.0.0 + parse5-htmlparser2-tree-adapter: ^7.0.0 + checksum: 5d4c1b7a53cf22d3a2eddc0aff70cf23cbb30d01a4c79013e703a012475c02461aa1fcd99127e8d83a02216386ed6942b2c8103845fd0812300dd199e6e7e054 + languageName: node + linkType: hard + "chokidar@npm:3.3.0": version: 3.3.0 resolution: "chokidar@npm:3.3.0" @@ -3851,6 +3900,26 @@ __metadata: languageName: node linkType: hard +"css-select@npm:^5.1.0": + version: 5.1.0 + resolution: "css-select@npm:5.1.0" + dependencies: + boolbase: ^1.0.0 + css-what: ^6.1.0 + domhandler: ^5.0.2 + domutils: ^3.0.1 + nth-check: ^2.0.1 + checksum: 2772c049b188d3b8a8159907192e926e11824aea525b8282981f72ba3f349cf9ecd523fdf7734875ee2cb772246c22117fc062da105b6d59afe8dcd5c99c9bda + languageName: node + linkType: hard + +"css-what@npm:^6.1.0": + version: 6.1.0 + resolution: "css-what@npm:6.1.0" + checksum: b975e547e1e90b79625918f84e67db5d33d896e6de846c9b584094e529f0c63e2ab85ee33b9daffd05bff3a146a1916bec664e18bb76dd5f66cbff9fc13b2bbe + languageName: node + linkType: hard + "dashdash@npm:^1.12.0": version: 1.14.1 resolution: "dashdash@npm:1.14.1" @@ -4065,6 +4134,44 @@ __metadata: languageName: node linkType: hard +"dom-serializer@npm:^2.0.0": + version: 2.0.0 + resolution: "dom-serializer@npm:2.0.0" + dependencies: + domelementtype: ^2.3.0 + domhandler: ^5.0.2 + entities: ^4.2.0 + checksum: cd1810544fd8cdfbd51fa2c0c1128ec3a13ba92f14e61b7650b5de421b88205fd2e3f0cc6ace82f13334114addb90ed1c2f23074a51770a8e9c1273acbc7f3e6 + languageName: node + linkType: hard + +"domelementtype@npm:^2.3.0": + version: 2.3.0 + resolution: "domelementtype@npm:2.3.0" + checksum: ee837a318ff702622f383409d1f5b25dd1024b692ef64d3096ff702e26339f8e345820f29a68bcdcea8cfee3531776b3382651232fbeae95612d6f0a75efb4f6 + languageName: node + linkType: hard + +"domhandler@npm:^5.0.2, domhandler@npm:^5.0.3": + version: 5.0.3 + resolution: "domhandler@npm:5.0.3" + dependencies: + domelementtype: ^2.3.0 + checksum: 0f58f4a6af63e6f3a4320aa446d28b5790a009018707bce2859dcb1d21144c7876482b5188395a188dfa974238c019e0a1e610d2fc269a12b2c192ea2b0b131c + languageName: node + linkType: hard + +"domutils@npm:^3.0.1": + version: 3.1.0 + resolution: "domutils@npm:3.1.0" + dependencies: + dom-serializer: ^2.0.0 + domelementtype: ^2.3.0 + domhandler: ^5.0.3 + checksum: e5757456ddd173caa411cfc02c2bb64133c65546d2c4081381a3bafc8a57411a41eed70494551aa58030be9e58574fcc489828bebd673863d39924fb4878f416 + languageName: node + linkType: hard + "dotenv@npm:^16.0.0": version: 16.3.1 resolution: "dotenv@npm:16.3.1" @@ -4172,6 +4279,13 @@ __metadata: languageName: node linkType: hard +"entities@npm:^4.2.0, entities@npm:^4.4.0": + version: 4.5.0 + resolution: "entities@npm:4.5.0" + checksum: 853f8ebd5b425d350bffa97dd6958143179a5938352ccae092c62d1267c4e392a039be1bae7d51b6e4ffad25f51f9617531fedf5237f15df302ccfb452cbf2d7 + languageName: node + linkType: hard + "env-paths@npm:^2.2.0": version: 2.2.1 resolution: "env-paths@npm:2.2.1" @@ -5276,7 +5390,7 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.12.1, follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.14.4, follow-redirects@npm:^1.14.9, follow-redirects@npm:^1.15.0": +"follow-redirects@npm:^1.12.1, follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.14.9, follow-redirects@npm:^1.15.0": version: 1.15.2 resolution: "follow-redirects@npm:1.15.2" peerDependenciesMeta: @@ -5286,6 +5400,16 @@ __metadata: languageName: node linkType: hard +"follow-redirects@npm:^1.15.6": + version: 1.15.6 + resolution: "follow-redirects@npm:1.15.6" + peerDependenciesMeta: + debug: + optional: true + checksum: a62c378dfc8c00f60b9c80cab158ba54e99ba0239a5dd7c81245e5a5b39d10f0c35e249c3379eae719ff0285fff88c365dd446fab19dee771f1d76252df1bbf5 + languageName: node + linkType: hard + "for-each@npm:^0.3.3": version: 0.3.3 resolution: "for-each@npm:0.3.3" @@ -6151,6 +6275,18 @@ __metadata: languageName: node linkType: hard +"htmlparser2@npm:^8.0.1": + version: 8.0.2 + resolution: "htmlparser2@npm:8.0.2" + dependencies: + domelementtype: ^2.3.0 + domhandler: ^5.0.3 + domutils: ^3.0.1 + entities: ^4.4.0 + checksum: 29167a0f9282f181da8a6d0311b76820c8a59bc9e3c87009e21968264c2987d2723d6fde5a964d4b7b6cba663fca96ffb373c06d8223a85f52a6089ced942700 + languageName: node + linkType: hard + "http-basic@npm:^8.1.1": version: 8.1.3 resolution: "http-basic@npm:8.1.3" @@ -6600,6 +6736,13 @@ __metadata: languageName: node linkType: hard +"is-retry-allowed@npm:^2.2.0": + version: 2.2.0 + resolution: "is-retry-allowed@npm:2.2.0" + checksum: 3d1103a9290b5d03626756a41054844633eac78bc5d3e3a95b13afeae94fa3cfbcf7f0b5520d83f75f48a25ce7b142fdbac4217dc4b0630f3ea55e866ec3a029 + languageName: node + linkType: hard + "is-shared-array-buffer@npm:^1.0.2": version: 1.0.2 resolution: "is-shared-array-buffer@npm:1.0.2" @@ -8004,6 +8147,15 @@ __metadata: languageName: node linkType: hard +"nth-check@npm:^2.0.1": + version: 2.1.1 + resolution: "nth-check@npm:2.1.1" + dependencies: + boolbase: ^1.0.0 + checksum: 5afc3dafcd1573b08877ca8e6148c52abd565f1d06b1eb08caf982e3fa289a82f2cae697ffb55b5021e146d60443f1590a5d6b944844e944714a5b549675bcd3 + languageName: node + linkType: hard + "number-to-bn@npm:1.7.0": version: 1.7.0 resolution: "number-to-bn@npm:1.7.0" @@ -8289,6 +8441,25 @@ __metadata: languageName: node linkType: hard +"parse5-htmlparser2-tree-adapter@npm:^7.0.0": + version: 7.0.0 + resolution: "parse5-htmlparser2-tree-adapter@npm:7.0.0" + dependencies: + domhandler: ^5.0.2 + parse5: ^7.0.0 + checksum: fc5d01e07733142a1baf81de5c2a9c41426c04b7ab29dd218acb80cd34a63177c90aff4a4aee66cf9f1d0aeecff1389adb7452ad6f8af0a5888e3e9ad6ef733d + languageName: node + linkType: hard + +"parse5@npm:^7.0.0": + version: 7.1.2 + resolution: "parse5@npm:7.1.2" + dependencies: + entities: ^4.4.0 + checksum: 59465dd05eb4c5ec87b76173d1c596e152a10e290b7abcda1aecf0f33be49646ea74840c69af975d7887543ea45564801736356c568d6b5e71792fd0f4055713 + languageName: node + linkType: hard + "parseurl@npm:~1.3.3": version: 1.3.3 resolution: "parseurl@npm:1.3.3" @@ -8878,10 +9049,12 @@ __metadata: "@types/node": ^12.20.37 "@typescript-eslint/eslint-plugin": 5.17.0 "@typescript-eslint/parser": 5.17.0 - axios: ^0.24.0 + axios: ^1.6.8 + axios-retry: ^4.1.0 bignumber.js: ^9.1.1 caip: ^1.1.0 chai: ^4.3.4 + cheerio: ^1.0.0-rc.12 decimal.js: ^10.4.3 dotenv: ^16.0.0 eslint: 8.14.0