From ee65afbdb235f3761543093f3d004dda572e66f7 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Fri, 25 Jul 2025 19:04:16 +0300 Subject: [PATCH 01/65] current dev --- .github/workflows/deploy-market.yaml | 5 +- .github/workflows/enact-migration.yaml | 54 +- .github/workflows/prepare-migration.yaml | 8 +- .github/workflows/run-contract-linter.yaml | 2 - .github/workflows/run-coverage.yaml | 2 - .github/workflows/run-eslint.yaml | 2 - .github/workflows/run-gas-profiler.yaml | 2 - .github/workflows/run-scenarios.yaml | 9 +- .github/workflows/run-slither.yaml | 3 + .github/workflows/run-unit-tests.yaml | 6 +- deployments/arbitrum/usdt/deploy.ts | 2 +- deployments/base/usdc/relations.ts | 8 + deployments/base/weth/relations.ts | 8 + deployments/linea/usdc/configuration.json | 55 + deployments/linea/usdc/deploy.ts | 141 + .../1736257010_configurate_and_ens.ts | 312 + deployments/linea/usdc/relations.ts | 41 + deployments/linea/usdc/roots.json | 18 +- deployments/linea/usdt/configuration.json | 55 + deployments/linea/usdt/deploy.ts | 100 + .../1736946439_configurate_and_ens.ts | 340 + deployments/linea/usdt/relations.ts | 33 + deployments/linea/usdt/roots.json | 11 + deployments/linea/weth/configuration.json | 68 + deployments/linea/weth/deploy.ts | 158 + .../1737020138_configurate_and_ens.ts | 325 + deployments/linea/weth/relations.ts | 33 + deployments/linea/weth/roots.json | 11 + deployments/localhost/dai/configuration.json | 26 + deployments/localhost/dai/deploy.ts | 604 ++ deployments/mainnet/usdc/relations.ts | 32 + deployments/mainnet/usdc/roots.json | 53 +- deployments/mainnet/weth/relations.ts | 16 + deployments/ronin/weth/roots.json | 3 +- hardhat.config.ts | 176 +- package.json | 25 +- plugins/deployment_manager/Deploy.ts | 10 +- .../deployment_manager/DeploymentManager.ts | 102 +- plugins/deployment_manager/Migration.ts | 8 +- plugins/deployment_manager/Spider.ts | 3 +- plugins/import/etherscan.ts | 62 +- plugins/import/import.ts | 15 +- plugins/scenario/utils/TokenSourcer.ts | 4 +- plugins/scenario/utils/hreForBase.ts | 2 + scenario/BulkerScenario.ts | 10 +- scenario/LiquidationScenario.ts | 2 +- scenario/SupplyScenario.ts | 22 +- scenario/TransferScenario.ts | 28 +- scenario/WithdrawScenario.ts | 28 +- scenario/constraints/MigrationConstraint.ts | 4 +- scenario/utils/hreUtils.ts | 4 +- scenario/utils/index.ts | 973 ++- scenario/utils/isBridgeProposal.ts | 19 + scenario/utils/relayArbitrumMessage.ts | 207 +- scenario/utils/relayBaseMessage.ts | 149 +- scenario/utils/relayLineaMessage.ts | 237 +- scenario/utils/relayMantleMessage.ts | 77 +- scenario/utils/relayMessage.ts | 66 +- scenario/utils/relayOptimismMessage.ts | 109 +- scenario/utils/relayPolygonMessage.ts | 116 +- scenario/utils/relayRoninMessage.ts | 141 +- scenario/utils/relayScrollMessage.ts | 77 +- scenario/utils/relayUnichainMessage.ts | 169 +- scenario/utils/scenarioHelper.ts | 36 +- scripts/clone-multisig.ts | 2 +- src/deploy/Network.ts | 2 +- src/deploy/index.ts | 85 +- tasks/deployment_manager/task.ts | 57 +- tsconfig.json | 42 +- types/tenderly.d.ts | 61 + yarn.lock | 6230 +++++++++++------ 71 files changed, 8965 insertions(+), 2941 deletions(-) create mode 100644 deployments/linea/usdc/configuration.json create mode 100644 deployments/linea/usdc/deploy.ts create mode 100644 deployments/linea/usdc/migrations/1736257010_configurate_and_ens.ts create mode 100644 deployments/linea/usdc/relations.ts create mode 100644 deployments/linea/usdt/configuration.json create mode 100644 deployments/linea/usdt/deploy.ts create mode 100644 deployments/linea/usdt/migrations/1736946439_configurate_and_ens.ts create mode 100644 deployments/linea/usdt/relations.ts create mode 100644 deployments/linea/usdt/roots.json create mode 100644 deployments/linea/weth/configuration.json create mode 100644 deployments/linea/weth/deploy.ts create mode 100644 deployments/linea/weth/migrations/1737020138_configurate_and_ens.ts create mode 100644 deployments/linea/weth/relations.ts create mode 100644 deployments/linea/weth/roots.json create mode 100644 deployments/localhost/dai/configuration.json create mode 100644 deployments/localhost/dai/deploy.ts create mode 100644 types/tenderly.d.ts diff --git a/.github/workflows/deploy-market.yaml b/.github/workflows/deploy-market.yaml index 29b9e614d..21faa47c6 100644 --- a/.github/workflows/deploy-market.yaml +++ b/.github/workflows/deploy-market.yaml @@ -15,6 +15,7 @@ on: - optimism - mantle - unichain + - linea - scroll - ronin deployment: @@ -35,9 +36,7 @@ jobs: INFURA_KEY: ${{ secrets.INFURA_KEY }} ANKR_KEY: ${{ secrets.ANKR_KEY }} POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} - ARBISCAN_KEY: ${{ secrets.ARBISCAN_KEY }} BASESCAN_KEY: ${{ secrets.BASESCAN_KEY }} - LINEASCAN_KEY: ${{ secrets.LINEASCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} @@ -49,7 +48,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"ronin\":\"https://ronin.gateway.tenderly.co/$_TENDERLY_KEY_RONIN\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://mantle-mainnet.infura.io/v3/$INFURA_KEY\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/$INFURA_KEY\",\"sepolia\":\"https://sepolia.infura.io/v3/$INFURA_KEY\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://arbitrum-mainnet.infura.io/v3/$INFURA_KEY\",\"base\":\"https://rpc.ankr.com/base/$ANKR_KEY\",\"scroll\":\"https://rpc.scroll.io\"}')[inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"https://rpc.ankr.com/linea/${ANKR_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/$_TENDERLY_KEY_RONIN\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://mantle-mainnet.infura.io/v3/$INFURA_KEY\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/$INFURA_KEY\",\"sepolia\":\"https://sepolia.infura.io/v3/$INFURA_KEY\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://arbitrum-mainnet.infura.io/v3/$INFURA_KEY\",\"base\":\"https://rpc.ankr.com/base/$ANKR_KEY\",\"scroll\":\"https://rpc.scroll.io\"}')[inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' diff --git a/.github/workflows/enact-migration.yaml b/.github/workflows/enact-migration.yaml index e76592f9e..cc9bc49bd 100644 --- a/.github/workflows/enact-migration.yaml +++ b/.github/workflows/enact-migration.yaml @@ -13,6 +13,7 @@ on: - arbitrum - base - optimism + - linea - mantle - unichain - scroll @@ -42,6 +43,11 @@ on: description: Deploy Market required: false default: false + tenderly: + type: boolean + description: Use Tenderly for simulation + required: false + default: false jobs: enact-migration: name: Enact Migration @@ -52,15 +58,14 @@ jobs: INFURA_KEY: ${{ secrets.INFURA_KEY }} ANKR_KEY: ${{ secrets.ANKR_KEY }} POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} - ARBISCAN_KEY: ${{ secrets.ARBISCAN_KEY }} BASESCAN_KEY: ${{ secrets.BASESCAN_KEY }} - LINEASCAN_KEY: ${{ secrets.LINEASCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} + _TENDERLY_KEY_POLYGON: ${{ secrets._TENDERLY_KEY_POLYGON }} UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} - GOV_NETWORK: ${{ secrets.GOV_NETWORK }} + GOV_NETWORK: ${{ vars.GOV_NETWORK }} steps: - name: Get governance network run: | @@ -72,13 +77,22 @@ jobs: *) echo "No governance network for selected network" ;; esac + + - name: Export Tenderly secrets + if: github.event.inputs.tenderly == 'true' + env: + TENDERLY_USERNAME: ${{ secrets.TENDERLY_USERNAME }} + TENDERLY_ACCESS_KEY: ${{ secrets.TENDERLY_ACCESS_KEY }} + run: | + echo "TENDERLY_USERNAME=$TENDERLY_USERNAME" >> "$GITHUB_ENV" + echo "TENDERLY_ACCESS_KEY=$TENDERLY_ACCESS_KEY" >> "$GITHUB_ENV" - name: Seacrest uses: hayesgm/seacrest@af229b0a00b73cb6fa9940a836a62fa3b918fd77 with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://mantle-mainnet.infura.io/v3/$INFURA_KEY\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/$INFURA_KEY\",\"sepolia\":\"https://sepolia.infura.io/v3/$INFURA_KEY\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://arbitrum-mainnet.infura.io/v3/$INFURA_KEY\",\"base\":\"https://rpc.ankr.com/base/$ANKR_KEY\",\"scroll\":\"https://rpc.scroll.io\"}')[inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"https://rpc.ankr.com/linea/${ANKR_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://mantle-mainnet.infura.io/v3/$INFURA_KEY\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/$INFURA_KEY\",\"sepolia\":\"https://sepolia.infura.io/v3/$INFURA_KEY\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://arbitrum-mainnet.infura.io/v3/$INFURA_KEY\",\"base\":\"https://rpc.ankr.com/base/$ANKR_KEY\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' @@ -86,10 +100,10 @@ jobs: uses: hayesgm/seacrest@af229b0a00b73cb6fa9940a836a62fa3b918fd77 with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} - requested_network: "${{ env.GOV_NETWORK }}" - ethereum_url: "${{ fromJSON('{\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://mantle-mainnet.infura.io/v3/$INFURA_KEY\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/$INFURA_KEY\",\"sepolia\":\"https://sepolia.infura.io/v3/$INFURA_KEY\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://arbitrum-mainnet.infura.io/v3/$INFURA_KEY\"}')[env.GOV_NETWORK] }}" + requested_network: "${{ vars.GOV_NETWORK }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"https://rpc.ankr.com/linea/${ANKR_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://mantle-mainnet.infura.io/v3/$INFURA_KEY\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/$INFURA_KEY\",\"sepolia\":\"https://sepolia.infura.io/v3/$INFURA_KEY\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://arbitrum-mainnet.infura.io/v3/$INFURA_KEY\"}')[vars.GOV_NETWORK] }}" port: 8685 - if: github.event.inputs.eth_pk == '' && env.GOV_NETWORK != '' && github.event.inputs.impersonateAccount == '' + if: github.event.inputs.eth_pk == '' && vars.GOV_NETWORK != '' && github.event.inputs.network != vars.GOV_NETWORK - name: Checkout repository uses: actions/checkout@v4 @@ -117,13 +131,13 @@ jobs: - name: Run Deploy Market and Enact Migration (impersonate) run: | - yarn hardhat deploy_and_migrate --network ${{ github.event.inputs.network }} --deployment ${{ github.event.inputs.deployment }} --enact --overwrite ${{ fromJSON('["", "--simulate"]')[github.event.inputs.simulate == 'true'] }} ${{ fromJSON('["", "--no-enacted"]')[github.event.inputs.no_enacted == 'true'] }} ${{ github.event.inputs.migration }} --impersonate ${{ github.event.inputs.impersonateAccount }} + yarn hardhat deploy_and_migrate --network ${{ github.event.inputs.network }} --deployment ${{ github.event.inputs.deployment }} --enact --overwrite ${{ fromJSON('["", "--simulate"]')[github.event.inputs.simulate == 'true'] }} ${{ fromJSON('["", "--no-enacted"]')[github.event.inputs.no_enacted == 'true'] }} ${{ github.event.inputs.migration }} --impersonate ${{ github.event.inputs.impersonateAccount }} ${{ fromJSON('["", "--tenderly"]')[github.event.inputs.tenderly == 'true'] }} env: DEBUG: true ETH_PK: "${{ inputs.eth_pk }}" NETWORK_PROVIDER: ${{ fromJSON('["", "http://localhost:8585"]')[github.event.inputs.eth_pk == ''] }} - GOV_NETWORK_PROVIDER: ${{ fromJSON('["", "http://localhost:8685"]')[github.event.inputs.eth_pk == '' && env.GOV_NETWORK != ''] }} - GOV_NETWORK: ${{ env.GOV_NETWORK }} + GOV_NETWORK_PROVIDER: ${{ github.event.inputs.network != vars.GOV_NETWORK && github.event.inputs.eth_pk == '' && vars.GOV_NETWORK != '' && 'http://localhost:8685' || '' }} + GOV_NETWORK: ${{ github.event.inputs.network != vars.GOV_NETWORK && vars.GOV_NETWORK || '' }} REMOTE_ACCOUNTS: ${{ fromJSON('["", "true"]')[github.event.inputs.eth_pk == ''] }} if: github.event.inputs.impersonateAccount != '' && github.event.inputs.with_deploy == 'true' - name: Run Enact Migration @@ -133,32 +147,32 @@ jobs: DEBUG: true ETH_PK: "${{ inputs.eth_pk }}" NETWORK_PROVIDER: ${{ fromJSON('["", "http://localhost:8585"]')[github.event.inputs.eth_pk == ''] }} - GOV_NETWORK_PROVIDER: ${{ fromJSON('["", "http://localhost:8685"]')[github.event.inputs.eth_pk == '' && env.GOV_NETWORK != ''] }} - GOV_NETWORK: ${{ env.GOV_NETWORK }} + GOV_NETWORK_PROVIDER: ${{ github.event.inputs.network != vars.GOV_NETWORK && github.event.inputs.eth_pk == '' && vars.GOV_NETWORK != '' && 'http://localhost:8685' || '' }} + GOV_NETWORK: ${{ github.event.inputs.network != vars.GOV_NETWORK && vars.GOV_NETWORK || '' }} REMOTE_ACCOUNTS: ${{ fromJSON('["", "true"]')[github.event.inputs.eth_pk == ''] }} if: github.event.inputs.impersonateAccount == '' && github.event.inputs.with_deploy == 'false' - name: Run Enact Migration (impersonate) run: | - yarn hardhat migrate --network ${{ github.event.inputs.network }} --deployment ${{ github.event.inputs.deployment }} --enact --overwrite ${{ fromJSON('["", "--simulate"]')[github.event.inputs.simulate == 'true'] }} ${{ fromJSON('["", "--no-enacted"]')[github.event.inputs.no_enacted == 'true'] }} ${{ github.event.inputs.migration }} --impersonate ${{ github.event.inputs.impersonateAccount }} + yarn hardhat migrate --network ${{ github.event.inputs.network }} --deployment ${{ github.event.inputs.deployment }} --enact --overwrite ${{ fromJSON('["", "--simulate"]')[github.event.inputs.simulate == 'true'] }} ${{ fromJSON('["", "--no-enacted"]')[github.event.inputs.no_enacted == 'true'] }} ${{ github.event.inputs.migration }} --impersonate ${{ github.event.inputs.impersonateAccount }} ${{ fromJSON('["", "--tenderly"]')[github.event.inputs.tenderly == 'true'] }} env: DEBUG: true ETH_PK: "${{ inputs.eth_pk }}" NETWORK_PROVIDER: ${{ fromJSON('["", "http://localhost:8585"]')[github.event.inputs.eth_pk == ''] }} - GOV_NETWORK_PROVIDER: ${{ fromJSON('["", "http://localhost:8685"]')[github.event.inputs.eth_pk == '' && env.GOV_NETWORK != ''] }} - GOV_NETWORK: ${{ env.GOV_NETWORK }} + GOV_NETWORK_PROVIDER: ${{ github.event.inputs.network != vars.GOV_NETWORK && github.event.inputs.eth_pk == '' && vars.GOV_NETWORK != '' && 'http://localhost:8685' || '' }} + GOV_NETWORK: ${{ github.event.inputs.network != vars.GOV_NETWORK && vars.GOV_NETWORK || '' }} REMOTE_ACCOUNTS: ${{ fromJSON('["", "true"]')[github.event.inputs.eth_pk == ''] }} if: github.event.inputs.impersonateAccount != '' && github.event.inputs.run_id != 0 - name: Run Prepare and Enact Migration (impersonate) run: | - yarn hardhat migrate --network ${{ github.event.inputs.network }} --deployment ${{ github.event.inputs.deployment }} --prepare --enact --overwrite ${{ fromJSON('["", "--simulate"]')[github.event.inputs.simulate == 'true'] }} ${{ fromJSON('["", "--no-enacted"]')[github.event.inputs.no_enacted == 'true'] }} ${{ github.event.inputs.migration }} --impersonate ${{ github.event.inputs.impersonateAccount }} + yarn hardhat migrate --network ${{ github.event.inputs.network }} --deployment ${{ github.event.inputs.deployment }} --prepare --enact --overwrite ${{ fromJSON('["", "--simulate"]')[github.event.inputs.simulate == 'true'] }} ${{ fromJSON('["", "--no-enacted"]')[github.event.inputs.no_enacted == 'true'] }} ${{ github.event.inputs.migration }} --impersonate ${{ github.event.inputs.impersonateAccount }} ${{ fromJSON('["", "--tenderly"]')[github.event.inputs.tenderly == 'true'] }} env: DEBUG: true ETH_PK: "${{ inputs.eth_pk }}" NETWORK_PROVIDER: ${{ fromJSON('["", "http://localhost:8585"]')[github.event.inputs.eth_pk == ''] }} - GOV_NETWORK_PROVIDER: ${{ fromJSON('["", "http://localhost:8685"]')[github.event.inputs.eth_pk == '' && env.GOV_NETWORK != ''] }} - GOV_NETWORK: ${{ env.GOV_NETWORK }} + GOV_NETWORK_PROVIDER: ${{ github.event.inputs.network != vars.GOV_NETWORK && github.event.inputs.eth_pk == '' && vars.GOV_NETWORK != '' && 'http://localhost:8685' || '' }} + GOV_NETWORK: ${{ github.event.inputs.network != vars.GOV_NETWORK && vars.GOV_NETWORK || '' }} REMOTE_ACCOUNTS: ${{ fromJSON('["", "true"]')[github.event.inputs.eth_pk == ''] }} - if: github.event.inputs.impersonateAccount != '' && github.event.inputs.with_deploy == 'false' + if: github.event.inputs.impersonateAccount != '' && github.event.inputs.with_deploy == 'false' && github.event.inputs.run_id == '' - name: Commit changes if: ${{ github.event.inputs.simulate == 'false' }} run: | @@ -166,4 +180,4 @@ jobs: git config user.email "<>" git add deployments/${{ github.event.inputs.network }}/${{ github.event.inputs.deployment }}/migrations/${{ github.event.inputs.migration }}.ts git commit -m "Modified migration from GitHub Actions" || echo "No changes to commit" - git push origin \ No newline at end of file + git push origin diff --git a/.github/workflows/prepare-migration.yaml b/.github/workflows/prepare-migration.yaml index b4260d10d..afe6ae5ac 100644 --- a/.github/workflows/prepare-migration.yaml +++ b/.github/workflows/prepare-migration.yaml @@ -16,6 +16,7 @@ on: - mantle - ronin - unichain + - linea - scroll deployment: description: Deployment Name (e.g. "usdc") @@ -39,19 +40,18 @@ jobs: ANKR_KEY: ${{ secrets.ANKR_KEY }} _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} - ARBISCAN_KEY: ${{ secrets.ARBISCAN_KEY }} BASESCAN_KEY: ${{ secrets.BASESCAN_KEY }} - LINEASCAN_KEY: ${{ secrets.LINEASCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} + UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} steps: - name: Seacrest uses: hayesgm/seacrest@af229b0a00b73cb6fa9940a836a62fa3b918fd77 with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"ronin\":\"https://ronin.gateway.tenderly.co/$_TENDERLY_KEY_RONIN\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://mantle-mainnet.infura.io/v3/$INFURA_KEY\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/$INFURA_KEY\",\"sepolia\":\"https://sepolia.infura.io/v3/$INFURA_KEY\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://arbitrum-mainnet.infura.io/v3/$INFURA_KEY\",\"base\":\"https://rpc.ankr.com/base/$ANKR_KEY\",\"scroll\":\"https://rpc.scroll.io\"}')[inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"https://rpc.ankr.com/linea/${ANKR_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/$_TENDERLY_KEY_RONIN\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://mantle-mainnet.infura.io/v3/$INFURA_KEY\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/$INFURA_KEY\",\"sepolia\":\"https://sepolia.infura.io/v3/$INFURA_KEY\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://arbitrum-mainnet.infura.io/v3/$INFURA_KEY\",\"base\":\"https://rpc.ankr.com/base/$ANKR_KEY\",\"scroll\":\"https://rpc.scroll.io\"}')[inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' @@ -84,4 +84,4 @@ jobs: if: success() || failure() # run this step even if previous step failed with: name: ${{ github.event.inputs.network }}-${{ github.event.inputs.deployment }}-${{ github.event.inputs.migration }} - path: deployments/${{ github.event.inputs.network }}/${{ github.event.inputs.deployment }}/artifacts/${{ github.event.inputs.migration }}.json \ No newline at end of file + path: deployments/${{ github.event.inputs.network }}/${{ github.event.inputs.deployment }}/artifacts/${{ github.event.inputs.migration }}.json diff --git a/.github/workflows/run-contract-linter.yaml b/.github/workflows/run-contract-linter.yaml index 6b78a255b..cc327d696 100644 --- a/.github/workflows/run-contract-linter.yaml +++ b/.github/workflows/run-contract-linter.yaml @@ -13,8 +13,6 @@ jobs: ANKR_KEY: ${{ secrets.ANKR_KEY }} _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} - ARBISCAN_KEY: ${{ secrets.ARBISCAN_KEY }} - LINEASCAN_KEY: ${{ secrets.LINEASCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} diff --git a/.github/workflows/run-coverage.yaml b/.github/workflows/run-coverage.yaml index 197a99660..56daa7969 100644 --- a/.github/workflows/run-coverage.yaml +++ b/.github/workflows/run-coverage.yaml @@ -15,8 +15,6 @@ jobs: ANKR_KEY: ${{ secrets.ANKR_KEY }} _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} - ARBISCAN_KEY: ${{ secrets.ARBISCAN_KEY }} - LINEASCAN_KEY: ${{ secrets.LINEASCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} diff --git a/.github/workflows/run-eslint.yaml b/.github/workflows/run-eslint.yaml index f3518c21a..c9424d91f 100644 --- a/.github/workflows/run-eslint.yaml +++ b/.github/workflows/run-eslint.yaml @@ -13,8 +13,6 @@ jobs: ANKR_KEY: ${{ secrets.ANKR_KEY }} _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} - ARBISCAN_KEY: ${{ secrets.ARBISCAN_KEY }} - LINEASCAN_KEY: ${{ secrets.LINEASCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} diff --git a/.github/workflows/run-gas-profiler.yaml b/.github/workflows/run-gas-profiler.yaml index b986dad80..615b39383 100644 --- a/.github/workflows/run-gas-profiler.yaml +++ b/.github/workflows/run-gas-profiler.yaml @@ -14,8 +14,6 @@ jobs: ANKR_KEY: ${{ secrets.ANKR_KEY }} _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} - ARBISCAN_KEY: ${{ secrets.ARBISCAN_KEY }} - LINEASCAN_KEY: ${{ secrets.LINEASCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} diff --git a/.github/workflows/run-scenarios.yaml b/.github/workflows/run-scenarios.yaml index 40de968cf..f6ba283cf 100644 --- a/.github/workflows/run-scenarios.yaml +++ b/.github/workflows/run-scenarios.yaml @@ -2,23 +2,24 @@ name: Run Scenarios on: workflow_dispatch: pull_request: +permissions: + checks: write jobs: run-scenarios: strategy: fail-fast: false matrix: - bases: [ development, mainnet, mainnet-weth, mainnet-wbtc, mainnet-usdt, mainnet-wsteth, mainnet-usds, sepolia-usdc, sepolia-weth, fuji, polygon, polygon-usdt, arbitrum-usdc.e, arbitrum-usdc, arbitrum-weth, arbitrum-usdt, base-usdbc, base-weth, base-usdc, base-aero, base-usds, optimism-usdc, optimism-usdt, optimism-weth, mantle-usde, scroll-usdc, ronin-weth, ronin-wron, unichain-usdc, unichain-weth] + bases: [ development, mainnet, mainnet-weth, mainnet-wbtc, mainnet-usdt, mainnet-wsteth, mainnet-usds, sepolia-usdc, sepolia-weth, fuji, polygon, polygon-usdt, arbitrum-usdc.e, arbitrum-usdc, arbitrum-weth, arbitrum-usdt, base-usdbc, base-weth, base-usdc, base-aero, base-usds, optimism-usdc, optimism-usdt, optimism-weth, mantle-usde, linea-usdc, linea-usdt, linea-weth, scroll-usdc, ronin-weth, ronin-wron, unichain-usdc, unichain-weth] name: Run scenarios env: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} ANKR_KEY: ${{ secrets.ANKR_KEY }} + _TENDERLY_KEY_POLYGON: ${{ secrets._TENDERLY_KEY_POLYGON }} _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} - ARBISCAN_KEY: ${{ secrets.ARBISCAN_KEY }} BASESCAN_KEY: ${{ secrets.BASESCAN_KEY }} - LINEASCAN_KEY: ${{ secrets.LINEASCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} @@ -68,4 +69,4 @@ jobs: with: name: Scenario Tests (${{ matrix.bases }}) # Name of the check run which will be created path: scenario-results.json # Path to test results (inside artifact .zip) - reporter: mocha-json # Format of test results \ No newline at end of file + reporter: mocha-json # Format of test results diff --git a/.github/workflows/run-slither.yaml b/.github/workflows/run-slither.yaml index f8e031b6f..18355f755 100644 --- a/.github/workflows/run-slither.yaml +++ b/.github/workflows/run-slither.yaml @@ -24,6 +24,9 @@ jobs: - name: Install packages run: pip install slither-analyzer solc-select + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + - name: Switch to solidity version run: solc-select install 0.8.15;solc-select use 0.8.15 diff --git a/.github/workflows/run-unit-tests.yaml b/.github/workflows/run-unit-tests.yaml index 0574accdf..b9cb8fe63 100644 --- a/.github/workflows/run-unit-tests.yaml +++ b/.github/workflows/run-unit-tests.yaml @@ -2,6 +2,10 @@ name: Run Unit Tests on: workflow_dispatch: pull_request: + +permissions: + checks: write # Grant write permission to checks + jobs: unit-tests: name: Unit tests @@ -13,8 +17,6 @@ jobs: ANKR_KEY: ${{ secrets.ANKR_KEY }} _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} - ARBISCAN_KEY: ${{ secrets.ARBISCAN_KEY }} - LINEASCAN_KEY: ${{ secrets.LINEASCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} diff --git a/deployments/arbitrum/usdt/deploy.ts b/deployments/arbitrum/usdt/deploy.ts index 0ebe246de..f88d6d74a 100644 --- a/deployments/arbitrum/usdt/deploy.ts +++ b/deployments/arbitrum/usdt/deploy.ts @@ -39,7 +39,7 @@ export default async function deploy(deploymentManager: DeploymentManager, deplo const bridgeReceiver = await deploymentManager.fromDep('bridgeReceiver', 'arbitrum', 'usdc.e'); // Deploy Comet - const deployed = await deployComet(deploymentManager, deploySpec); + const deployed = await deployComet(deploymentManager, deploySpec, {}, true); return { ...deployed, diff --git a/deployments/base/usdc/relations.ts b/deployments/base/usdc/relations.ts index 5a4805d34..ef28b871d 100644 --- a/deployments/base/usdc/relations.ts +++ b/deployments/base/usdc/relations.ts @@ -34,4 +34,12 @@ export default { } } }, + TransparentUpgradeableProxy: { + artifact: 'contracts/ERC20.sol:ERC20', + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, }; \ No newline at end of file diff --git a/deployments/base/weth/relations.ts b/deployments/base/weth/relations.ts index ac825da26..348581fb1 100644 --- a/deployments/base/weth/relations.ts +++ b/deployments/base/weth/relations.ts @@ -49,4 +49,12 @@ export default { } }, + WOETHBaseProxy: { + artifact: 'contracts/ERC20.sol:ERC20', + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, }; \ No newline at end of file diff --git a/deployments/linea/usdc/configuration.json b/deployments/linea/usdc/configuration.json new file mode 100644 index 000000000..cf5673169 --- /dev/null +++ b/deployments/linea/usdc/configuration.json @@ -0,0 +1,55 @@ +{ + "name": "Compound USDC", + "symbol": "cUSDCv3", + "baseToken": "USDC", + "baseTokenAddress": "0x176211869cA2b568f2A7D4EE941E073a821EE1ff", + "baseTokenPriceFeed": "0xAADAa473C1bDF7317ec07c915680Af29DeBfdCb5", + "pauseGuardian": "0x5A1e5d7E09cA94506084a26304d53A138145bF52", + "borrowMin": "1e6", + "storeFrontPriceFactor": 0.6, + "targetReserves": "20_000_000e6", + "rates": { + "supplyKink": 0.9, + "supplySlopeLow": 0.054, + "supplySlopeHigh": 3.034, + "supplyBase": 0, + "borrowKink": 0.9, + "borrowSlopeLow": 0.05, + "borrowSlopeHigh": 3.4, + "borrowBase": 0.015 + }, + "tracking": { + "indexScale": "1e15", + "baseSupplySpeed": "46296296296e0", + "baseBorrowSpeed": "34722222222e0", + "baseMinForRewards": "1000e6" + }, + "assets": { + "WETH": { + "address": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f", + "priceFeed": "0x3c6Cd9Cc7c7a4c2Cf5a82734CD249D7D593354dA", + "decimals": "18", + "borrowCF": 0.83, + "liquidateCF": 0.9, + "liquidationFactor": 0.95, + "supplyCap": "530e18" + }, + "wstETH": { + "address": "0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F", + "decimals": "18", + "borrowCF": 0.82, + "liquidateCF": 0.87, + "liquidationFactor": 0.95, + "supplyCap": "340e18" + }, + "WBTC": { + "address": "0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4", + "priceFeed": "0x7A99092816C8BD5ec8ba229e3a6E6Da1E628E1F9", + "decimals": "8", + "borrowCF": 0.8, + "liquidateCF": 0.85, + "liquidationFactor": 0.9, + "supplyCap": "18e8" + } + } +} \ No newline at end of file diff --git a/deployments/linea/usdc/deploy.ts b/deployments/linea/usdc/deploy.ts new file mode 100644 index 000000000..264ff3566 --- /dev/null +++ b/deployments/linea/usdc/deploy.ts @@ -0,0 +1,141 @@ +import { + Deployed, + DeploymentManager, +} from '../../../plugins/deployment_manager'; +import { DeploySpec, deployComet } from '../../../src/deploy'; + +const HOUR = 60 * 60; +const DAY = 24 * HOUR; + +const MAINNET_TIMELOCK = '0x6d903f6003cca6255d85cca4d3b5e5146dc33925'; + +const WSTETH_TO_STETH_PRICE_FEED = '0x3C8A95F2264bB3b52156c766b738357008d87cB7'; +const ETH_TO_USD_PRICE_FEED = '0x3c6Cd9Cc7c7a4c2Cf5a82734CD249D7D593354dA'; + +const L2MESSAGE_SERVICE_ADDRESS = '0x508Ca82Df566dCD1B0DE8296e70a96332cD644ec'; +const L2STANDARD_BRIDGE_ADDRESS = '0x353012dc4a9A6cF55c941bADC267f82004A8ceB9'; +const L2USDC_BRIDGE_ADDRESS = '0xA2Ee6Fce4ACB62D95448729cDb781e3BEb62504A'; + +export default async function deploy( + deploymentManager: DeploymentManager, + deploySpec: DeploySpec +): Promise { + const deployed = await deployContracts(deploymentManager, deploySpec); + return deployed; +} + +async function deployContracts( + deploymentManager: DeploymentManager, + deploySpec: DeploySpec +): Promise { + const trace = deploymentManager.tracer(); + + // Pull in existing assets + const USDC = await deploymentManager.existing( + 'USDC', + '0x176211869cA2b568f2A7D4EE941E073a821EE1ff', + 'linea' + ); + const WETH = await deploymentManager.existing( + 'WETH', + '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f', + 'linea' + ); + const WBTC = await deploymentManager.existing( + 'WBTC', + '0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4', + 'linea' + ); + + const wstETH = await deploymentManager.existing( + 'wstETH', + '0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F', + 'linea' + ); + + const wstETHtoUsdPriceFeed = await deploymentManager.deploy( + 'wstETH:priceFeed', + 'pricefeeds/MultiplicativePriceFeed.sol', + [ + WSTETH_TO_STETH_PRICE_FEED, // wstETH / stETH price feed + ETH_TO_USD_PRICE_FEED, // ETH / USD price feed (we consider stETH / ETH as 1:1) + 8, // decimals + 'wstETH / USD price feed' // description + ] + ); + + + const l2MessageService = await deploymentManager.existing( + 'l2MessageService', + L2MESSAGE_SERVICE_ADDRESS, + 'linea' + ); + + const l2StandardBridge = await deploymentManager.existing( + 'l2StandardBridge', + L2STANDARD_BRIDGE_ADDRESS, + 'linea' + ); + + const l2USDCBridge = await deploymentManager.existing( + 'l2USDCBridge', + L2USDC_BRIDGE_ADDRESS, + 'linea' + ); + + // Deploy LineaBridgeReceiver + const bridgeReceiver = await deploymentManager.deploy( + 'bridgeReceiver', + 'bridges/linea/LineaBridgeReceiver.sol', + [l2MessageService.address] + ); + + // Deploy Local Timelock + const localTimelock = await deploymentManager.deploy( + 'timelock', + 'vendor/Timelock.sol', + [ + bridgeReceiver.address, // admin + 1 * DAY, // delay + 14 * DAY, // grace period + 12 * HOUR, // minimum delay + 30 * DAY, // maxiumum delay + ] + ); + + // Initialize OptimismBridgeReceiver + await deploymentManager.idempotent( + async () => !(await bridgeReceiver.initialized()), + async () => { + trace(`Initializing BridgeReceiver`); + await bridgeReceiver.initialize( + MAINNET_TIMELOCK, // govTimelock + localTimelock.address // localTimelock + ); + trace(`BridgeReceiver initialized`); + } + ); + + // Deploy Comet + const deployed = await deployComet(deploymentManager, deploySpec, {}, true); + const { comet } = deployed; + + // Deploy Bulker + const bulker = await deploymentManager.deploy( + 'bulker', + 'bulkers/BaseBulker.sol', + [ + await comet.governor(), // admin + WETH.address, // weth + ] + ); + + return { + ...deployed, + bridgeReceiver, + l2MessageService, + l2StandardBridge, + l2USDCBridge, + bulker, + }; +} diff --git a/deployments/linea/usdc/migrations/1736257010_configurate_and_ens.ts b/deployments/linea/usdc/migrations/1736257010_configurate_and_ens.ts new file mode 100644 index 000000000..e7ee8ac8d --- /dev/null +++ b/deployments/linea/usdc/migrations/1736257010_configurate_and_ens.ts @@ -0,0 +1,312 @@ +import { Contract } from 'ethers'; +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { diffState, getCometConfig } from '../../../../plugins/deployment_manager/DiffState'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { calldata, exp, getConfigurationStruct, proposal } from '../../../../src/deploy'; + +const ENSName = 'compound-community-licenses.eth'; +const ENSResolverAddress = '0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41'; +const ENSSubdomainLabel = 'v3-additional-grants'; +const ENSSubdomain = `${ENSSubdomainLabel}.${ENSName}`; +const ENSTextRecordKey = 'v3-official-markets'; + +const lineaCOMPAddress = '0x0ECE76334Fb560f2b1a49A60e38Cf726B02203f0'; + +const USDCAmountToBridge = exp(100_000, 6); +const COMPAmountToBridge = exp(5_110, 18); + +export default migration('1736257010_configurate_and_ens', { + prepare: async (_deploymentManager: DeploymentManager) => { + return {}; + }, + + enact: async (deploymentManager: DeploymentManager, govDeploymentManager: DeploymentManager) => { + const trace = deploymentManager.tracer(); + const ethers = deploymentManager.hre.ethers; + const { utils } = ethers; + + const { + bridgeReceiver, + timelock: l2Timelock, + comet, + cometAdmin, + configurator, + rewards, + } = await deploymentManager.getContracts(); + + const { + lineaMessageService, + lineaL1TokenBridge, + lineaL1USDCBridge, + governor, + USDC, + COMP, + } = await govDeploymentManager.getContracts(); + + const configuration = await getConfigurationStruct(deploymentManager); + + const setConfigurationCalldata = await calldata( + configurator.populateTransaction.setConfiguration(comet.address, configuration) + ); + const deployAndUpgradeToCalldata = utils.defaultAbiCoder.encode( + ['address', 'address'], + [configurator.address, comet.address] + ); + const setRewardConfigCalldata = utils.defaultAbiCoder.encode( + ['address', 'address'], + [comet.address, lineaCOMPAddress] + ); + const l2ProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [configurator.address, cometAdmin.address, rewards.address], + [0, 0, 0], + [ + 'setConfiguration(address,(address,address,address,address,address,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint104,uint104,uint104,(address,address,uint8,uint64,uint64,uint64,uint128)[]))', + 'deployAndUpgradeTo(address,address)', + 'setRewardConfig(address,address)' + ], + [ + setConfigurationCalldata, deployAndUpgradeToCalldata, setRewardConfigCalldata + ] + ] + ); + + const ENSResolver = await govDeploymentManager.existing('ENSResolver', ENSResolverAddress); + const subdomainHash = ethers.utils.namehash(ENSSubdomain); + const officialMarketsJSON = await ENSResolver.text(subdomainHash, ENSTextRecordKey); + const officialMarkets = JSON.parse(officialMarketsJSON); + const updatedMarkets = { + ...officialMarkets, + 59144: [ + { + baseSymbol: 'USDC', + cometAddress: comet.address, + } + ], + }; + + if (!(officialMarkets[8453] as { baseSymbol: string, cometAddress: string }[])?.find(({ baseSymbol }) => baseSymbol === 'USDS')) { + updatedMarkets[8453].push({ + baseSymbol: 'USDS', + cometAddress: '0x2c776041CCFe903071AF44aa147368a9c8EEA518' + }); + } + + const mainnetActions = [ + // 1. Set Comet configuration and deployAndUpgradeTo new Comet on Linea. + { + contract: lineaMessageService, + signature: 'sendMessage(address,uint256,bytes)', + args: [bridgeReceiver.address, 0, l2ProposalData], + }, + // 2. Approve the USDC gateway to take Timelock's USDC for bridging + { + contract: USDC, + signature: 'approve(address,uint256)', + args: [lineaL1USDCBridge.address, USDCAmountToBridge] + }, + // 3. Bridge USDC from mainnet to Linea Comet + { + contract: lineaL1USDCBridge, + signature: 'depositTo(uint256,address)', + args: [USDCAmountToBridge, comet.address], + }, + // 4. Approve the COMP gateway to take Timelock's COMP for bridging + { + contract: COMP, + signature: 'approve(address,uint256)', + args: [lineaL1TokenBridge.address, COMPAmountToBridge] + }, + // 5. Bridge COMP from mainnet to Linea rewards + { + contract: lineaL1TokenBridge, + signature: 'bridgeToken(address,uint256,address)', + args: [COMP.address, COMPAmountToBridge, rewards.address] + }, + // 6. Update the list of official markets + { + target: ENSResolverAddress, + signature: 'setText(bytes32,string,string)', + calldata: ethers.utils.defaultAbiCoder.encode( + ['bytes32', 'string', 'string'], + [subdomainHash, ENSTextRecordKey, JSON.stringify(updatedMarkets)] + ) + } + ]; + + const description = '# Initialize cUSDTv3 on Linea network\n\n## Proposal summary\n\nCompound Growth Program [AlphaGrowth] proposes the deployment of Compound III to the Linea network. This proposal takes the governance steps recommended and necessary to initialize a Compound III USDC market on Linea; upon execution, cUSDCv3 will be ready for use. Simulations have confirmed the market’s readiness, as much as possible, using the [Comet scenario suite](https://github.com/compound-finance/comet/tree/main/scenario). The new parameters include setting the risk parameters based off of the [recommendations from Gauntlet](https://www.comp.xyz/t/deploy-compound-iii-on-linea/4460/19).\n\nFurther detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/953), [deploy market GitHub action run](https://github.com/woof-software/comet/actions/runs/13041520838/job/36384262627) and [forum discussion](https://www.comp.xyz/t/deploy-compound-iii-on-linea/4460).\n\n\n## ENS TXT record update\n\n[USDS on Base proposal](https://www.tally.xyz/gov/compound/proposal/395?govId=eip155:1:0x309a862bbC1A00e45506cB8A802D1ff10004c8C0) is active on the moment of pushing this proposal. The proposal reached the quorum and we expect that the proposal will be executed without fail. In case we need to cancel proposal 395, we need to cancel this proposal too\n\n## Proposal Actions\n\nThe first proposal action sets the Comet configuration, deploys a new Comet implementation, and sets the reward config on Linea. This sends the encoded `setConfiguration`, `deployAndUpgradeTo`, `setRewardConfig` calls across the bridge to the governance receiver on Linea.\n\nThe second action approves USDC tokens to the bridge.\n\nThe third action sends USDC tokens to the Linea chain via a special native USDC bridge.\n\nThe fourth action approves COMP tokens to the bridge.\n\nThe fifth action sends COMP tokens to the Linea chain via bridge.\n\nThe sixth action updates the ENS TXT record `v3-official-markets` on `v3-additional-grants.compound-community-licenses.eth`, updating the official markets JSON to include the new Linea cUSDCv3 market.'; + const txn = await govDeploymentManager.retry(async () => + trace(await governor.propose(...(await proposal(mainnetActions, description)))) + ); + + const event = txn.events.find(event => event.event === 'ProposalCreated'); + const [proposalId] = event.args; + + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager, govDeploymentManager: DeploymentManager, preMigrationBlockNumber: number) { + const ethers = deploymentManager.hre.ethers; + await deploymentManager.spider(); // Pull in Linea COMP now that reward config has been set + + const { + comet, + rewards, + } = await deploymentManager.getContracts(); + + // 1. + const stateChanges = await diffState(comet, getCometConfig, preMigrationBlockNumber); + expect(stateChanges).to.deep.equal({ + WETH: { + supplyCap: exp(530, 18) + }, + wstETH: { + supplyCap: exp(340, 18) + }, + WBTC: { + supplyCap: exp(18, 8) + }, + baseTrackingSupplySpeed: exp(4 / 86400, 15, 18), + baseTrackingBorrowSpeed: exp(3 / 86400, 15, 18) + }); + + const config = await rewards.rewardConfig(comet.address); + expect(config.token).to.be.equal(lineaCOMPAddress); + expect(config.rescaleFactor).to.be.equal(exp(1, 12)); + expect(config.shouldUpscale).to.be.equal(true); + + // 2. & 3. + expect(await comet.getReserves()).to.be.equal(USDCAmountToBridge); + + // 4. & 5. + const lineaCOMP = new Contract( + lineaCOMPAddress, + ['function balanceOf(address account) external view returns (uint256)'], + deploymentManager.hre.ethers.provider + ); + expect(await lineaCOMP.balanceOf(rewards.address)).to.be.equal(COMPAmountToBridge); + + // 6. + const ENSResolver = await govDeploymentManager.existing('ENSResolver', ENSResolverAddress); + const subdomainHash = ethers.utils.namehash(ENSSubdomain); + const officialMarketsJSON = await ENSResolver.text(subdomainHash, ENSTextRecordKey); + const officialMarkets = JSON.parse(officialMarketsJSON); + + expect(officialMarkets).to.deep.equal({ + 1: [ + { + baseSymbol: 'USDC', + cometAddress: '0xc3d688B66703497DAA19211EEdff47f25384cdc3' + }, + { + baseSymbol: 'WETH', + cometAddress: '0xA17581A9E3356d9A858b789D68B4d866e593aE94' + }, + { + baseSymbol: 'USDT', + cometAddress: '0x3Afdc9BCA9213A35503b077a6072F3D0d5AB0840' + }, + { + baseSymbol: 'wstETH', + cometAddress: '0x3D0bb1ccaB520A66e607822fC55BC921738fAFE3' + }, + { + baseSymbol: 'USDS', + cometAddress: '0x5D409e56D886231aDAf00c8775665AD0f9897b56' + } + ], + 10: [ + { + baseSymbol: 'USDC', + cometAddress: '0x2e44e174f7D53F0212823acC11C01A11d58c5bCB' + }, + { + baseSymbol: 'USDT', + cometAddress: '0x995E394b8B2437aC8Ce61Ee0bC610D617962B214' + }, + { + baseSymbol: 'WETH', + cometAddress: '0xE36A30D249f7761327fd973001A32010b521b6Fd' + } + ], + 137: [ + { + baseSymbol: 'USDC', + cometAddress: '0xF25212E676D1F7F89Cd72fFEe66158f541246445' + }, + { + baseSymbol: 'USDT', + cometAddress: '0xaeB318360f27748Acb200CE616E389A6C9409a07' + } + ], + 42161: [ + { + baseSymbol: 'USDC.e', + cometAddress: '0xA5EDBDD9646f8dFF606d7448e414884C7d905dCA', + }, + { + baseSymbol: 'USDC', + cometAddress: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf', + }, + { + baseSymbol: 'WETH', + cometAddress: '0x6f7D514bbD4aFf3BcD1140B7344b32f063dEe486', + }, + { + baseSymbol: 'USDT', + cometAddress: '0xd98Be00b5D27fc98112BdE293e487f8D4cA57d07', + }, + ], + 5000: [ + { + baseSymbol: 'USDe', + cometAddress: '0x606174f62cd968d8e684c645080fa694c1D7786E' + } + ], + 8453: [ + { + baseSymbol: 'USDbC', + cometAddress: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf' + }, + { + baseSymbol: 'WETH', + cometAddress: '0x46e6b214b524310239732D51387075E0e70970bf' + }, + { + baseSymbol: 'USDC', + cometAddress: '0xb125E6687d4313864e53df431d5425969c15Eb2F' + }, + { + baseSymbol: 'AERO', + cometAddress: '0x784efeB622244d2348d4F2522f8860B96fbEcE89' + }, + { + baseSymbol: 'USDS', + cometAddress: '0x2c776041CCFe903071AF44aa147368a9c8EEA518' + } + ], + 534352: [ + { + baseSymbol: 'USDC', + cometAddress: '0xB2f97c1Bd3bf02f5e74d13f02E3e26F93D77CE44' + }, + ], + 59144: [ + { + baseSymbol: 'USDC', + cometAddress: comet.address, + } + ], + }); + + // 7. + expect(await comet.baseTrackingSupplySpeed()).to.be.equal(exp(4 / 86400, 15, 18)); // 46296296296 + expect(await comet.baseTrackingBorrowSpeed()).to.be.equal(exp(3 / 86400, 15, 18)); // 34722222222 + } +}); diff --git a/deployments/linea/usdc/relations.ts b/deployments/linea/usdc/relations.ts new file mode 100644 index 000000000..8b2449ced --- /dev/null +++ b/deployments/linea/usdc/relations.ts @@ -0,0 +1,41 @@ +import baseRelationConfig from '../../relations'; + +export default { + ...baseRelationConfig, + governor: { + artifact: + 'contracts/bridges/linea/LineaBridgeReceiver.sol:LineaBridgeReceiver', + }, + l2MessageService: { + delegates: { + field: { + slot: + '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc', + }, + }, + }, + l2USDCBridge: { + delegates: { + field: { + slot: + '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc', + }, + }, + }, + l2StandardBridge: { + delegates: { + field: { + slot: + '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc', + }, + }, + }, + 'TransparentUpgradeableProxy': { + artifact: 'contracts/ERC20.sol:ERC20', + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, +}; diff --git a/deployments/linea/usdc/roots.json b/deployments/linea/usdc/roots.json index 64806a9ea..03361ab19 100644 --- a/deployments/linea/usdc/roots.json +++ b/deployments/linea/usdc/roots.json @@ -1,11 +1,11 @@ { - "l2TokenBridge": "0x353012dc4a9a6cf55c941badc267f82004a8ceb9", - "l2USDCBridge": "0xA2Ee6Fce4ACB62D95448729cDb781e3BEb62504A", - "l2MessageService": "0x508Ca82Df566dCD1B0DE8296e70a96332cD644ec", - "comet": "0x8D38A3d6B3c3B7d96D6536DA7Eef94A9d7dbC991", - "configurator": "0x970FfD8E335B8fa4cd5c869c7caC3a90671d5Dc3", - "rewards": "0x2c7118c4C88B9841FCF839074c26Ae8f035f2921", - "bridgeReceiver": "0x1F71901daf98d70B4BAF40DE080321e5C2676856", - "l2StandardBridge": "0x353012dc4a9A6cF55c941bADC267f82004A8ceB9", - "bulker": "0x023ee795361B28cDbB94e302983578486A0A5f1B" + "l2TokenBridge": "0x353012dc4a9a6cf55c941badc267f82004a8ceb9", + "l2USDCBridge": "0xA2Ee6Fce4ACB62D95448729cDb781e3BEb62504A", + "l2MessageService": "0x508Ca82Df566dCD1B0DE8296e70a96332cD644ec", + "comet": "0x8D38A3d6B3c3B7d96D6536DA7Eef94A9d7dbC991", + "configurator": "0x970FfD8E335B8fa4cd5c869c7caC3a90671d5Dc3", + "rewards": "0x2c7118c4C88B9841FCF839074c26Ae8f035f2921", + "bridgeReceiver": "0x1F71901daf98d70B4BAF40DE080321e5C2676856", + "l2StandardBridge": "0x353012dc4a9A6cF55c941bADC267f82004A8ceB9", + "bulker": "0x023ee795361B28cDbB94e302983578486A0A5f1B" } \ No newline at end of file diff --git a/deployments/linea/usdt/configuration.json b/deployments/linea/usdt/configuration.json new file mode 100644 index 000000000..8084bd338 --- /dev/null +++ b/deployments/linea/usdt/configuration.json @@ -0,0 +1,55 @@ +{ + "name": "Compound USDT", + "symbol": "cUSDTv3", + "baseToken": "USDT", + "baseTokenAddress": "0xA219439258ca9da29E9Cc4cE5596924745e12B93", + "baseTokenPriceFeed": "0xefCA2bbe0EdD0E22b2e0d2F8248E99F4bEf4A7dB", + "pauseGuardian": "0x5A1e5d7E09cA94506084a26304d53A138145bF52", + "borrowMin": "1e6", + "storeFrontPriceFactor": 0.6, + "targetReserves": "20_000_000e6", + "rates": { + "borrowBase": 0.015, + "borrowSlopeLow": 0.02778, + "borrowKink": 0.9, + "borrowSlopeHigh": 3.6, + "supplyBase": 0, + "supplySlopeLow": 0.036, + "supplyKink": 0.9, + "supplySlopeHigh": 3.196 + }, + "tracking": { + "indexScale": "1e15", + "baseSupplySpeed": "23148148148e0", + "baseBorrowSpeed": "11574074074e0", + "baseMinForRewards": "1000e6" + }, + "assets": { + "WETH": { + "address": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f", + "priceFeed": "0x3c6Cd9Cc7c7a4c2Cf5a82734CD249D7D593354dA", + "decimals": "18", + "borrowCF": 0.83, + "liquidateCF": 0.90, + "liquidationFactor": 0.95, + "supplyCap": "270e18" + }, + "wstETH": { + "address": "0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F", + "decimals": "18", + "borrowCF": 0.82, + "liquidateCF": 0.87, + "liquidationFactor": 0.95, + "supplyCap": "60e18" + }, + "WBTC": { + "address": "0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4", + "priceFeed": "0x7A99092816C8BD5ec8ba229e3a6E6Da1E628E1F9", + "decimals": "8", + "borrowCF": 0.8, + "liquidateCF": 0.85, + "liquidationFactor": 0.9, + "supplyCap": "4e8" + } + } +} \ No newline at end of file diff --git a/deployments/linea/usdt/deploy.ts b/deployments/linea/usdt/deploy.ts new file mode 100644 index 000000000..15eb512b4 --- /dev/null +++ b/deployments/linea/usdt/deploy.ts @@ -0,0 +1,100 @@ +import { + Deployed, + DeploymentManager, +} from '../../../plugins/deployment_manager'; +import { DeploySpec, deployComet } from '../../../src/deploy'; + +const WSTETH_TO_STETH_PRICE_FEED = '0x3C8A95F2264bB3b52156c766b738357008d87cB7'; +const ETH_TO_USD_PRICE_FEED = '0x3c6Cd9Cc7c7a4c2Cf5a82734CD249D7D593354dA'; + +const L2MESSAGE_SERVICE_ADDRESS = '0x508Ca82Df566dCD1B0DE8296e70a96332cD644ec'; +const L2STANDARD_BRIDGE_ADDRESS = '0x353012dc4a9A6cF55c941bADC267f82004A8ceB9'; +const L2USDC_BRIDGE_ADDRESS = '0xA2Ee6Fce4ACB62D95448729cDb781e3BEb62504A'; + +export default async function deploy( + deploymentManager: DeploymentManager, + deploySpec: DeploySpec +): Promise { + const deployed = await deployContracts(deploymentManager, deploySpec); + return deployed; +} + +async function deployContracts( + deploymentManager: DeploymentManager, + deploySpec: DeploySpec +): Promise { + // Pull in existing assets + const _USDT = await deploymentManager.existing( + 'USDT', + '0xA219439258ca9da29E9Cc4cE5596924745e12B93', + 'linea' + ); + const _WETH = await deploymentManager.existing( + 'WETH', + '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f', + 'linea' + ); + const _WBTC = await deploymentManager.existing( + 'WBTC', + '0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4', + 'linea' + ); + + const _wstETH = await deploymentManager.existing( + 'wstETH', + '0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F', + 'linea' + ); + + const _wstETHtoUsdPriceFeed = await deploymentManager.deploy( + 'wstETH:priceFeed', + 'pricefeeds/MultiplicativePriceFeed.sol', + [ + WSTETH_TO_STETH_PRICE_FEED, // wstETH / stETH price feed + ETH_TO_USD_PRICE_FEED, // ETH / USD price feed (we consider stETH / ETH as 1:1) + 8, // decimals + 'wstETH / USD price feed' // description + ] + ); + + const l2MessageService = await deploymentManager.existing( + 'l2MessageService', + L2MESSAGE_SERVICE_ADDRESS, + 'linea' + ); + + const l2StandardBridge = await deploymentManager.existing( + 'l2StandardBridge', + L2STANDARD_BRIDGE_ADDRESS, + 'linea' + ); + + const l2USDCBridge = await deploymentManager.existing( + 'l2USDCBridge', + L2USDC_BRIDGE_ADDRESS, + 'linea' + ); + + // Import shared contracts from cUSDCv3 + const _cometAdmin = await deploymentManager.fromDep('cometAdmin', 'linea', 'usdc'); + const _assetListFactory = await deploymentManager.fromDep('assetListFactory', 'linea', 'usdc'); + const _cometFactory = await deploymentManager.fromDep('cometFactory', 'linea', 'usdc'); + const _$configuratorImpl = await deploymentManager.fromDep('configurator:implementation', 'linea', 'usdc'); + const _configurator = await deploymentManager.fromDep('configurator', 'linea', 'usdc'); + const _rewards = await deploymentManager.fromDep('rewards', 'linea', 'usdc'); + const bulker = await deploymentManager.fromDep('bulker', 'linea', 'usdc'); + const _localTimelock = await deploymentManager.fromDep('timelock', 'linea', 'usdc'); + const bridgeReceiver = await deploymentManager.fromDep('bridgeReceiver', 'linea', 'usdc'); + + // Deploy Comet + const deployed = await deployComet(deploymentManager, deploySpec, {}, true); + + return { + ...deployed, + bridgeReceiver, + l2MessageService, + l2StandardBridge, + l2USDCBridge, + bulker, + }; +} diff --git a/deployments/linea/usdt/migrations/1736946439_configurate_and_ens.ts b/deployments/linea/usdt/migrations/1736946439_configurate_and_ens.ts new file mode 100644 index 000000000..998d59bbf --- /dev/null +++ b/deployments/linea/usdt/migrations/1736946439_configurate_and_ens.ts @@ -0,0 +1,340 @@ +import { utils } from 'ethers'; +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { diffState, getCometConfig } from '../../../../plugins/deployment_manager/DiffState'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { calldata, exp, getConfigurationStruct, proposal } from '../../../../src/deploy'; + +const ENSName = 'compound-community-licenses.eth'; +const ENSResolverAddress = '0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41'; +const ENSSubdomainLabel = 'v3-additional-grants'; +const ENSSubdomain = `${ENSSubdomainLabel}.${ENSName}`; +const ENSTextRecordKey = 'v3-official-markets'; + +const lineaCOMPAddress = '0x0ECE76334Fb560f2b1a49A60e38Cf726B02203f0'; +const mainnetUsdtAddress = '0xdAC17F958D2ee523a2206206994597C13D831ec7'; +const cUSDTAddress = '0xf650c3d88d12db855b8bf7d11be6c55a4e07dcc9'; + +const USDTAmountToBridge = exp(100_000, 6); + +export default migration('1736946439_configurate_and_ens', { + prepare: async (_deploymentManager: DeploymentManager) => { + return {}; + }, + + enact: async (deploymentManager: DeploymentManager, govDeploymentManager: DeploymentManager) => { + const trace = deploymentManager.tracer(); + + const cometFactory = await deploymentManager.fromDep('cometFactory', 'linea', 'usdc'); + const { + bridgeReceiver, + comet, + cometAdmin, + configurator, + rewards, + } = await deploymentManager.getContracts(); + + const { + lineaMessageService, + lineaL1TokenBridge, + governor + } = await govDeploymentManager.getContracts(); + + const configuration = await getConfigurationStruct(deploymentManager); + + const _reduceReservesCalldata = utils.defaultAbiCoder.encode( + ['uint256'], + [USDTAmountToBridge] + ); + + const zeroApproveCalldata = utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [lineaL1TokenBridge.address, 0] + ); + + const approveCalldata = utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [lineaL1TokenBridge.address, USDTAmountToBridge] + ); + + const setFactoryCalldata = await calldata( + configurator.populateTransaction.setFactory(comet.address, cometFactory.address) + ); + const setConfigurationCalldata = await calldata( + configurator.populateTransaction.setConfiguration(comet.address, configuration) + ); + const deployAndUpgradeToCalldata = utils.defaultAbiCoder.encode( + ['address', 'address'], + [configurator.address, comet.address] + ); + const setRewardConfigCalldata = utils.defaultAbiCoder.encode( + ['address', 'address'], + [comet.address, lineaCOMPAddress] + ); + const l2ProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [configurator.address, configurator.address, cometAdmin.address, rewards.address], + [0, 0, 0, 0], + [ + 'setFactory(address,address)', + 'setConfiguration(address,(address,address,address,address,address,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint104,uint104,uint104,(address,address,uint8,uint64,uint64,uint64,uint128)[]))', + 'deployAndUpgradeTo(address,address)', + 'setRewardConfig(address,address)' + ], + [ + setFactoryCalldata, + setConfigurationCalldata, + deployAndUpgradeToCalldata, + setRewardConfigCalldata + ] + ] + ); + + const ENSResolver = await govDeploymentManager.existing('ENSResolver', ENSResolverAddress); + const subdomainHash = utils.namehash(ENSSubdomain); + const officialMarketsJSON = JSON.parse(await ENSResolver.text(subdomainHash, ENSTextRecordKey)); + const newMarketObject = { baseSymbol: 'USDT', cometAddress: comet.address }; + + if (officialMarketsJSON[59144]) { + officialMarketsJSON[59144].push(newMarketObject); + } else { + officialMarketsJSON[59144] = [newMarketObject]; + } + + const mainnetActions = [ + // 1. Set Comet configuration and deployAndUpgradeTo new Comet on Linea. + { + contract: lineaMessageService, + signature: 'sendMessage(address,uint256,bytes)', + args: [bridgeReceiver.address, 0, l2ProposalData], + }, + // 2. Get USDT reserves from cUSDT contract + { + target: cUSDTAddress, + signature: '_reduceReserves(uint256)', + calldata: _reduceReservesCalldata + }, + // 3. Reset approve of USDT from Timelock's to Gateway + { + target: mainnetUsdtAddress, + signature: 'approve(address,uint256)', + calldata: zeroApproveCalldata + }, + // 4. Approve the USDT gateway to take Timelock's USDT for bridging + { + target: mainnetUsdtAddress, + signature: 'approve(address,uint256)', + calldata: approveCalldata + }, + // 5. Bridge USDT from mainnet to Linea Comet + { + contract: lineaL1TokenBridge, + signature: 'bridgeToken(address,uint256,address)', + args: [mainnetUsdtAddress, USDTAmountToBridge, comet.address] + }, + // 6. Update the list of official markets + { + target: ENSResolverAddress, + signature: 'setText(bytes32,string,string)', + calldata: utils.defaultAbiCoder.encode( + ['bytes32', 'string', 'string'], + [subdomainHash, ENSTextRecordKey, JSON.stringify(officialMarketsJSON)] + ) + } + ]; + + const description = '# Initialize cUSDTv3 on Linea network\n\n## Proposal summary\n\nWOOF! proposes the deployment of Compound III to the Linea network. This proposal takes the governance steps recommended and necessary to initialize a Compound III USDT market on Linea; upon execution, cUSDTv3 will be ready for use. Simulations have confirmed the market’s readiness, as much as possible, using the [Comet scenario suite](https://github.com/compound-finance/comet/tree/main/scenario). The new parameters include setting the risk parameters based off of the [recommendations from Gauntlet](https://www.comp.xyz/t/deploy-compound-iii-on-linea/4460/19).\n\nFurther detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/982), [deploy market GitHub action run](https://github.com/woof-software/comet/actions/runs/15211082351) and [forum discussion](https://www.comp.xyz/t/deploy-compound-iii-on-linea/4460).\n\n\n## Proposal Actions\n\nThe first proposal action sets the Comet configuration and deploys a new Comet implementation on Linea. This sends the encoded `setFactory`, `setConfiguration`, `deployAndUpgradeTo` calls across the bridge to the governance receiver on Linea.\n\nThe second action reduces Compound’s [cUSDT](https://etherscan.io/address/0xf650c3d88d12db855b8bf7d11be6c55a4e07dcc9) reserves and transfers it to Timelock, in order to seed the market reserves for the Linea cUSDTv3 Comet.\n\nThe third action approves 0 USDT from Timelock to [LineaL1TokenBridge](https://etherscan.io/address/0x051F1D88f0aF5763fB888eC4378b4D8B29ea3319) to reset potential previous approves.\n\nThe fourth action approves 100K USDT to [LineaL1TokenBridge](https://etherscan.io/address/0x051F1D88f0aF5763fB888eC4378b4D8B29ea3319) to take Timelock\'s USDT on Mainnet, in order to seed the market reserves through the bridge.\n\nThe fifth action bridges USDT from mainnet via Linea`s bridge contract and sends it to Comet on Linea.\n\nThe sixth action updates the ENS TXT record `v3-official-markets` on `v3-additional-grants.compound-community-licenses.eth`, updating the official markets JSON to include the new Linea cUSDTv3 market.'; + const txn = await govDeploymentManager.retry(async () => + trace(await governor.propose(...(await proposal(mainnetActions, description)))) + ); + + const event = txn.events.find(event => event.event === 'ProposalCreated'); + const [proposalId] = event.args; + + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return false; + }, + + async verify(deploymentManager: DeploymentManager, govDeploymentManager: DeploymentManager, preMigrationBlockNumber: number) { + await deploymentManager.spider(); // Pull in Linea COMP now that reward config has been set + + const { + comet, + rewards, + } = await deploymentManager.getContracts(); + + // 1. + const stateChanges = await diffState(comet, getCometConfig, preMigrationBlockNumber); + + const secondsPerYear = 31_536_000; // 365 * 24 * 60 * 60 + expect(stateChanges).to.deep.equal({ + WETH: { + supplyCap: exp(270, 18) + }, + wstETH: { + supplyCap: exp(60, 18) + }, + WBTC: { + supplyCap: exp(4, 8) + }, + baseTrackingSupplySpeed: exp(2 / 86400, 15, 18), // 23148148148 + baseTrackingBorrowSpeed: exp(1 / 86400, 15, 18), // 11574074074 + supplyPerSecondRateSlopeLow: exp(0.036 / secondsPerYear, 18, 18), // 11415525114 + supplyPerSecondInterestRateSlopeHigh: exp(3.196 / secondsPerYear, 18, 18), // 101344495180 + borrowPerSecondInterestRateSlopeLow: exp(0.02778 / secondsPerYear, 18, 18), // 880898021 + borrowPerSecondInterestRateSlopeHigh: exp(3.6 / secondsPerYear, 18, 18), // 114155251141 + }); + + const config = await rewards.rewardConfig(comet.address); + expect(config.token).to.be.equal(lineaCOMPAddress); + expect(config.rescaleFactor).to.be.equal(exp(1, 12)); + expect(config.shouldUpscale).to.be.equal(true); + + // 2. & 3. + expect(await comet.getReserves()).to.be.equal(USDTAmountToBridge); + + // 6. + const ENSResolver = await govDeploymentManager.existing('ENSResolver', ENSResolverAddress); + const subdomainHash = utils.namehash(ENSSubdomain); + const officialMarketsJSON = await ENSResolver.text(subdomainHash, ENSTextRecordKey); + const officialMarkets = JSON.parse(officialMarketsJSON); + expect(officialMarkets).to.deep.equal({ + 1: [ + { + baseSymbol: 'USDC', + cometAddress: '0xc3d688B66703497DAA19211EEdff47f25384cdc3' + }, + { + baseSymbol: 'WETH', + cometAddress: '0xA17581A9E3356d9A858b789D68B4d866e593aE94' + }, + { + baseSymbol: 'USDT', + cometAddress: '0x3Afdc9BCA9213A35503b077a6072F3D0d5AB0840' + }, + { + baseSymbol: 'wstETH', + cometAddress: '0x3D0bb1ccaB520A66e607822fC55BC921738fAFE3' + }, + { + baseSymbol: 'USDS', + cometAddress: '0x5D409e56D886231aDAf00c8775665AD0f9897b56' + }, + { + baseSymbol: 'WBTC', + cometAddress: '0xe85Dc543813B8c2CFEaAc371517b925a166a9293' + } + ], + 10: [ + { + baseSymbol: 'USDC', + cometAddress: '0x2e44e174f7D53F0212823acC11C01A11d58c5bCB' + }, + { + baseSymbol: 'USDT', + cometAddress: '0x995E394b8B2437aC8Ce61Ee0bC610D617962B214' + }, + { + baseSymbol: 'WETH', + cometAddress: '0xE36A30D249f7761327fd973001A32010b521b6Fd' + } + ], + 130: [ + { + baseSymbol: 'USDC', + cometAddress: '0x2c7118c4C88B9841FCF839074c26Ae8f035f2921' + }, + { + baseSymbol: 'WETH', + cometAddress: '0x6C987dDE50dB1dcDd32Cd4175778C2a291978E2a' + } + ], + 137: [ + { + baseSymbol: 'USDC', + cometAddress: '0xF25212E676D1F7F89Cd72fFEe66158f541246445' + }, + { + baseSymbol: 'USDT', + cometAddress: '0xaeB318360f27748Acb200CE616E389A6C9409a07' + } + ], + 2020: [ + { + baseSymbol: 'WETH', + cometAddress: '0x4006eD4097Ee51c09A04c3B0951D28CCf19e6DFE' + }, + { + baseSymbol: 'WRON', + cometAddress: '0xc0Afdbd1cEB621Ef576BA969ce9D4ceF78Dbc0c0' + } + ], + 5000: [ + { + baseSymbol: 'USDe', + cometAddress: '0x606174f62cd968d8e684c645080fa694c1D7786E' + } + ], + 8453: [ + { + baseSymbol: 'USDbC', + cometAddress: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf' + }, + { + baseSymbol: 'WETH', + cometAddress: '0x46e6b214b524310239732D51387075E0e70970bf' + }, + { + baseSymbol: 'USDC', + cometAddress: '0xb125E6687d4313864e53df431d5425969c15Eb2F' + }, + { + baseSymbol: 'AERO', + cometAddress: '0x784efeB622244d2348d4F2522f8860B96fbEcE89' + }, + { + baseSymbol: 'USDS', + cometAddress: '0x2c776041CCFe903071AF44aa147368a9c8EEA518' + } + ], + 42161: [ + { + baseSymbol: 'USDC.e', + cometAddress: '0xA5EDBDD9646f8dFF606d7448e414884C7d905dCA' + }, + { + baseSymbol: 'USDC', + cometAddress: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf' + }, + { + baseSymbol: 'WETH', + cometAddress: '0x6f7D514bbD4aFf3BcD1140B7344b32f063dEe486' + }, + { + baseSymbol: 'USDT', + cometAddress: '0xd98Be00b5D27fc98112BdE293e487f8D4cA57d07' + } + ], + 59144: [ + { + baseSymbol: 'USDC', + cometAddress: '0x8D38A3d6B3c3B7d96D6536DA7Eef94A9d7dbC991' + }, + { + baseSymbol: 'USDT', + cometAddress: comet.address + } + ], + 534352: [ + { + baseSymbol: 'USDC', + cometAddress: '0xB2f97c1Bd3bf02f5e74d13f02E3e26F93D77CE44' + } + ] + }); + } +}); diff --git a/deployments/linea/usdt/relations.ts b/deployments/linea/usdt/relations.ts new file mode 100644 index 000000000..57b3392f0 --- /dev/null +++ b/deployments/linea/usdt/relations.ts @@ -0,0 +1,33 @@ +import baseRelationConfig from '../../relations'; + +export default { + ...baseRelationConfig, + governor: { + artifact: + 'contracts/bridges/linea/LineaBridgeReceiver.sol:LineaBridgeReceiver', + }, + l2MessageService: { + delegates: { + field: { + slot: + '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc', + }, + }, + }, + l2StandardBridge: { + delegates: { + field: { + slot: + '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc', + }, + }, + }, + 'TransparentUpgradeableProxy': { + artifact: 'contracts/ERC20.sol:ERC20', + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, +}; diff --git a/deployments/linea/usdt/roots.json b/deployments/linea/usdt/roots.json new file mode 100644 index 000000000..10c660ce4 --- /dev/null +++ b/deployments/linea/usdt/roots.json @@ -0,0 +1,11 @@ +{ + "comet": "0x2D86D6456682E0932e65869416c89fF8DB76381f", + "configurator": "0x970FfD8E335B8fa4cd5c869c7caC3a90671d5Dc3", + "rewards": "0x2c7118c4C88B9841FCF839074c26Ae8f035f2921", + "cometFactory": "0xaeB318360f27748Acb200CE616E389A6C9409a07", + "bridgeReceiver": "0x1F71901daf98d70B4BAF40DE080321e5C2676856", + "l2MessageService": "0x508Ca82Df566dCD1B0DE8296e70a96332cD644ec", + "l2StandardBridge": "0x353012dc4a9A6cF55c941bADC267f82004A8ceB9", + "l2USDCBridge": "0xA2Ee6Fce4ACB62D95448729cDb781e3BEb62504A", + "bulker": "0x023ee795361B28cDbB94e302983578486A0A5f1B" +} \ No newline at end of file diff --git a/deployments/linea/weth/configuration.json b/deployments/linea/weth/configuration.json new file mode 100644 index 000000000..8a8a4b5c9 --- /dev/null +++ b/deployments/linea/weth/configuration.json @@ -0,0 +1,68 @@ +{ + "name": "Compound WETH", + "symbol": "cWETHv3", + "baseToken": "WETH", + "baseTokenAddress": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f", + "pauseGuardian": "0x5A1e5d7E09cA94506084a26304d53A138145bF52", + "borrowMin": "0.01e18", + "storeFrontPriceFactor": 0.7, + "targetReserves": "5_000e18", + "rates": { + "borrowBase": 0.01, + "borrowSlopeLow": 0.0155, + "borrowKink": 0.9, + "borrowSlopeHigh": 1.26, + "supplyBase": 0, + "supplySlopeLow": 0.0216, + "supplyKink": 0.9, + "supplySlopeHigh": 1.125 + }, + "tracking": { + "indexScale": "1e15", + "baseSupplySpeed": "69444444444e0", + "baseBorrowSpeed": "46296296296e0", + "baseMinForRewards": "10e18" + }, + "assets": { + "ezETH": { + "address": "0x2416092f143378750bb29b79eD961ab195CcEea5", + "decimals": "18", + "borrowCF": 0.90, + "liquidateCF": 0.93, + "liquidationFactor": 0.94, + "supplyCap": "4830e18" + }, + "wstETH": { + "address": "0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F", + "decimals": "18", + "borrowCF": 0.90, + "liquidateCF": 0.93, + "liquidationFactor": 0.97, + "supplyCap": "260e18" + }, + "WBTC": { + "address": "0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4", + "decimals": "8", + "borrowCF": 0.8, + "liquidateCF": 0.85, + "liquidationFactor": 0.9, + "supplyCap": "5e8" + }, + "weETH": { + "address": "0x1Bf74C010E6320bab11e2e5A532b5AC15e0b8aA6", + "decimals": "18", + "borrowCF": 0.90, + "liquidateCF": 0.93, + "liquidationFactor": 0.96, + "supplyCap": "3550e18" + }, + "wrsETH": { + "address": "0xD2671165570f41BBB3B0097893300b6EB6101E6C", + "decimals": "18", + "borrowCF": 0.90, + "liquidateCF": 0.93, + "liquidationFactor": 0.96, + "supplyCap": "500e18" + } + } +} \ No newline at end of file diff --git a/deployments/linea/weth/deploy.ts b/deployments/linea/weth/deploy.ts new file mode 100644 index 000000000..78ae844f3 --- /dev/null +++ b/deployments/linea/weth/deploy.ts @@ -0,0 +1,158 @@ +import { + Deployed, + DeploymentManager, +} from '../../../plugins/deployment_manager'; +import { DeploySpec, deployComet, exp } from '../../../src/deploy'; + +const L2MESSAGE_SERVICE_ADDRESS = '0x508Ca82Df566dCD1B0DE8296e70a96332cD644ec'; +const L2STANDARD_BRIDGE_ADDRESS = '0x353012dc4a9A6cF55c941bADC267f82004A8ceB9'; +const L2USDC_BRIDGE_ADDRESS = '0xA2Ee6Fce4ACB62D95448729cDb781e3BEb62504A'; + +export default async function deploy( + deploymentManager: DeploymentManager, + deploySpec: DeploySpec +): Promise { + const deployed = await deployContracts(deploymentManager, deploySpec); + return deployed; +} + +async function deployContracts( + deploymentManager: DeploymentManager, + deploySpec: DeploySpec +): Promise { + const _WETH = await deploymentManager.existing( + 'WETH', + '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f', + 'linea' + ); + + const _wethConstantPriceFeed = await deploymentManager.deploy( + 'WETH:priceFeed', + 'pricefeeds/ConstantPriceFeed.sol', + [ + 8, // decimals + exp(1, 8) // constantPrice + ] + ); + + // Pull in existing assets + const _ezETH = await deploymentManager.existing( + 'ezETH', + '0x2416092f143378750bb29b79eD961ab195CcEea5', + 'linea' + ); + + const _ezETHPriceFeed = await deploymentManager.deploy( + 'ezETH:priceFeed', + 'pricefeeds/ScalingPriceFeed.sol', + [ + '0xb71F79770BA599940F454c70e63d4DE0E8606731', // ezETH / ETH price feed + 8 // decimals + ] + ); + + const _wstETH = await deploymentManager.existing( + 'wstETH', + '0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F', + 'linea' + ); + + const _wstETHPriceFeed = await deploymentManager.deploy( + 'wstETH:priceFeed', + 'pricefeeds/ScalingPriceFeed.sol', + [ + '0x3C8A95F2264bB3b52156c766b738357008d87cB7', // wstETH / stETH (we consider stETH / ETH as 1:1) price feed + 8 // decimals + ] + ); + + const _WBTC = await deploymentManager.existing( + 'WBTC', + '0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4', + 'linea' + ); + + const _wbtcPriceFeed = await deploymentManager.deploy( + 'WBTC:priceFeed', + 'pricefeeds/ReverseMultiplicativePriceFeed.sol', + [ + '0x7A99092816C8BD5ec8ba229e3a6E6Da1E628E1F9', // WBTC / USD price feed + '0x3c6Cd9Cc7c7a4c2Cf5a82734CD249D7D593354dA', // USD / ETH price feed + 8, // decimals + 'WBTC / ETH price feed' // description + ] + ); + + const _weETH = await deploymentManager.existing( + 'weETH', + '0x1Bf74C010E6320bab11e2e5A532b5AC15e0b8aA6', + 'linea' + ); + + const _weETHPriceFeed = await deploymentManager.deploy( + 'weETH:priceFeed', + 'pricefeeds/ScalingPriceFeed.sol', + [ + '0x1FBc7d24654b10c71fd74d3730d9Df17836181EF', // weETH / eETH (we consider eETH / ETH as 1:1) price feed + 8 // decimals + ] + ); + + const _wrsETH = await deploymentManager.existing( + 'wrsETH', + '0xD2671165570f41BBB3B0097893300b6EB6101E6C', + 'linea' + ); + + const _wrsETHPriceFeed = await deploymentManager.deploy( + 'wrsETH:priceFeed', + 'pricefeeds/ScalingPriceFeedWithCustomDescription.sol', + [ + '0xEEDF0B095B5dfe75F3881Cb26c19DA209A27463a', // wrsETH / ETH price feed + 8, // decimals + 'wrsETH / ETH price feed' // description + ], + true + ); + + const l2MessageService = await deploymentManager.existing( + 'l2MessageService', + L2MESSAGE_SERVICE_ADDRESS, + 'linea' + ); + + const l2StandardBridge = await deploymentManager.existing( + 'l2StandardBridge', + L2STANDARD_BRIDGE_ADDRESS, + 'linea' + ); + + const l2USDCBridge = await deploymentManager.existing( + 'l2USDCBridge', + L2USDC_BRIDGE_ADDRESS, + 'linea' + ); + + // Import shared contracts from cUSDCv3 + const _cometAdmin = await deploymentManager.fromDep('cometAdmin', 'linea', 'usdc'); + const _assetListFactory = await deploymentManager.fromDep('assetListFactory', 'linea', 'usdc'); + const _cometFactory = await deploymentManager.fromDep('cometFactory', 'linea', 'usdc'); + const _$configuratorImpl = await deploymentManager.fromDep('configurator:implementation', 'linea', 'usdc'); + const _configurator = await deploymentManager.fromDep('configurator', 'linea', 'usdc'); + const _rewards = await deploymentManager.fromDep('rewards', 'linea', 'usdc'); + const bulker = await deploymentManager.fromDep('bulker', 'linea', 'usdc'); + const _localTimelock = await deploymentManager.fromDep('timelock', 'linea', 'usdc'); + const bridgeReceiver = await deploymentManager.fromDep('bridgeReceiver', 'linea', 'usdc'); + + // Deploy Comet + const deployed = await deployComet(deploymentManager, deploySpec, {}, true); + + return { + ...deployed, + bridgeReceiver, + l2MessageService, + l2StandardBridge, + l2USDCBridge, + bulker, + }; +} diff --git a/deployments/linea/weth/migrations/1737020138_configurate_and_ens.ts b/deployments/linea/weth/migrations/1737020138_configurate_and_ens.ts new file mode 100644 index 000000000..dc66fd371 --- /dev/null +++ b/deployments/linea/weth/migrations/1737020138_configurate_and_ens.ts @@ -0,0 +1,325 @@ +import { utils } from 'ethers'; +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { diffState, getCometConfig } from '../../../../plugins/deployment_manager/DiffState'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { calldata, exp, getConfigurationStruct, proposal } from '../../../../src/deploy'; + +const ENSName = 'compound-community-licenses.eth'; +const ENSResolverAddress = '0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41'; +const ENSSubdomainLabel = 'v3-additional-grants'; +const ENSSubdomain = `${ENSSubdomainLabel}.${ENSName}`; +const ENSTextRecordKey = 'v3-official-markets'; + +const lineaCOMPAddress = '0x0ECE76334Fb560f2b1a49A60e38Cf726B02203f0'; + +const WETHAmountToBridge = exp(25, 18); + +export default migration('1737020138_configurate_and_ens', { + prepare: async (_deploymentManager: DeploymentManager) => { + return {}; + }, + + enact: async ( + deploymentManager: DeploymentManager, + govDeploymentManager: DeploymentManager + ) => { + const trace = deploymentManager.tracer(); + + const cometFactory = await deploymentManager.fromDep('cometFactory', 'linea', 'usdc'); + const { + bridgeReceiver, + comet, + cometAdmin, + configurator, + rewards, + timelock: l2Timelock, + WETH + } = await deploymentManager.getContracts(); + + const { + lineaMessageService, + governor + } = await govDeploymentManager.getContracts(); + + const configuration = await getConfigurationStruct(deploymentManager); + + const setFactoryCalldata = await calldata( + configurator.populateTransaction.setFactory(comet.address, cometFactory.address) + ); + const setConfigurationCalldata = await calldata( + configurator.populateTransaction.setConfiguration(comet.address, configuration) + ); + const deployAndUpgradeToCalldata = utils.defaultAbiCoder.encode( + ['address', 'address'], + [configurator.address, comet.address] + ); + const setRewardConfigCalldata = utils.defaultAbiCoder.encode( + ['address', 'address'], + [comet.address, lineaCOMPAddress] + ); + const sweepNativeTokenCalldata = await calldata(bridgeReceiver.populateTransaction.sweepNativeToken(l2Timelock.address)); + const transferCalldata = await calldata(WETH.populateTransaction.transfer(comet.address, WETHAmountToBridge)); + + const l2ProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + configurator.address, + configurator.address, + cometAdmin.address, + rewards.address, + bridgeReceiver.address, + WETH.address, + WETH.address + ], + [0, 0, 0, 0, 0, WETHAmountToBridge, 0], + [ + 'setFactory(address,address)', + 'setConfiguration(address,(address,address,address,address,address,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint104,uint104,uint104,(address,address,uint8,uint64,uint64,uint64,uint128)[]))', + 'deployAndUpgradeTo(address,address)', + 'setRewardConfig(address,address)', + 'sweepNativeToken(address)', + 'deposit()', + 'transfer(address,uint256)' + ], + [ + setFactoryCalldata, + setConfigurationCalldata, + deployAndUpgradeToCalldata, + setRewardConfigCalldata, + sweepNativeTokenCalldata, + '0x', + transferCalldata + ] + ] + ); + + const ENSResolver = await govDeploymentManager.existing('ENSResolver', ENSResolverAddress); + const subdomainHash = utils.namehash(ENSSubdomain); + const officialMarketsJSON = JSON.parse(await ENSResolver.text(subdomainHash, ENSTextRecordKey)); + const newMarketObject = { baseSymbol: 'WETH', cometAddress: comet.address }; + + if (officialMarketsJSON[59144]) { + officialMarketsJSON[59144].push(newMarketObject); + } else { + officialMarketsJSON[59144] = [newMarketObject]; + } + + const mainnetActions = [ + // 1. Set Comet configuration and deployAndUpgradeTo new Comet on Linea. + { + contract: lineaMessageService, + signature: 'sendMessage(address,uint256,bytes)', + args: [bridgeReceiver.address, 0, l2ProposalData], + value: WETHAmountToBridge + }, + // 2. Update the list of official markets + { + target: ENSResolverAddress, + signature: 'setText(bytes32,string,string)', + calldata: utils.defaultAbiCoder.encode( + ['bytes32', 'string', 'string'], + [subdomainHash, ENSTextRecordKey, JSON.stringify(officialMarketsJSON)] + ) + } + ]; + + const description = '# Initialize cWETHv3 on Linea network\n\n## Proposal summary\n\nWOOF! proposes the deployment of Compound III to the Linea network. This proposal takes the governance steps recommended and necessary to initialize a Compound III WETH market on Linea; upon execution, cWETHv3 will be ready for use. Simulations have confirmed the market’s readiness, as much as possible, using the [Comet scenario suite](https://github.com/compound-finance/comet/tree/main/scenario). The new parameters include setting the risk parameters based off of the [recommendations from Gauntlet](https://www.comp.xyz/t/deploy-compound-iii-on-linea/4460/20).\n\nFurther detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/982), [deploy market GitHub action run](https://github.com/woof-software/comet/actions/runs/15211470652) and [forum discussion](https://www.comp.xyz/t/deploy-compound-iii-on-linea/4460).\n\n\n## wrsETH Price Feed\n\n[wrsETH/ETH exchange rate](https://lineascan.build/address/0xEEDF0B095B5dfe75F3881Cb26c19DA209A27463a#readContract) price oracle has a wrong label. The information is confirmed with ChainLink and Kelp teams internally.\n\n\n## Proposal Actions\n\nThe first proposal action sends ether to the Linea Timelock so it can be wrapped and used to seed the reserves, sets the Comet configuration and deploys a new Comet implementation on Linea. This sends the encoded `setFactory`, `setConfiguration`, `deployAndUpgradeTo` calls across the bridge to the governance receiver on Linea.\n\nThe second action updates the ENS TXT record `v3-official-markets` on `v3-additional-grants.compound-community-licenses.eth`, updating the official markets JSON to include the new Linea cWETHv3 market.'; + const txn = await govDeploymentManager.retry(async () => + trace(await governor.propose(...(await proposal(mainnetActions, description)))) + ); + + const event = txn.events.find(event => event.event === 'ProposalCreated'); + const [proposalId] = event.args; + + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return false; + }, + + async verify( + deploymentManager: DeploymentManager, + govDeploymentManager: DeploymentManager, + preMigrationBlockNumber: number + ) { + await deploymentManager.spider(); // Pull in Linea COMP now that reward config has been set + + const { + comet, + rewards, + } = await deploymentManager.getContracts(); + + // 1. + const stateChanges = await diffState(comet, getCometConfig, preMigrationBlockNumber); + expect(stateChanges).to.deep.equal({ + ezETH: { + supplyCap: exp(4830, 18) + }, + wstETH: { + supplyCap: exp(260, 18) + }, + WBTC: { + supplyCap: exp(5, 8) + }, + weETH: { + supplyCap: exp(3550, 18) + }, + wrsETH: { + supplyCap: exp(500, 18) + }, + baseTrackingSupplySpeed: exp(6 / 86400, 15, 18), // 69444444444 + baseTrackingBorrowSpeed: exp(4 / 86400, 15, 18), // 46296296296 + }); + + const config = await rewards.rewardConfig(comet.address); + expect(config.token).to.be.equal(lineaCOMPAddress); + expect(config.rescaleFactor).to.be.equal(exp(1, 12)); + expect(config.shouldUpscale).to.be.equal(true); + + // 2. & 3. + expect(await comet.getReserves()).to.be.equal(WETHAmountToBridge); + + // 6. + const ENSResolver = await govDeploymentManager.existing('ENSResolver', ENSResolverAddress); + const subdomainHash = utils.namehash(ENSSubdomain); + const officialMarketsJSON = await ENSResolver.text(subdomainHash, ENSTextRecordKey); + const officialMarkets = JSON.parse(officialMarketsJSON); + expect(officialMarkets).to.deep.equal({ + 1: [ + { + baseSymbol: 'USDC', + cometAddress: '0xc3d688B66703497DAA19211EEdff47f25384cdc3' + }, + { + baseSymbol: 'WETH', + cometAddress: '0xA17581A9E3356d9A858b789D68B4d866e593aE94' + }, + { + baseSymbol: 'USDT', + cometAddress: '0x3Afdc9BCA9213A35503b077a6072F3D0d5AB0840' + }, + { + baseSymbol: 'wstETH', + cometAddress: '0x3D0bb1ccaB520A66e607822fC55BC921738fAFE3' + }, + { + baseSymbol: 'USDS', + cometAddress: '0x5D409e56D886231aDAf00c8775665AD0f9897b56' + }, + { + baseSymbol: 'WBTC', + cometAddress: '0xe85Dc543813B8c2CFEaAc371517b925a166a9293' + } + ], + 10: [ + { + baseSymbol: 'USDC', + cometAddress: '0x2e44e174f7D53F0212823acC11C01A11d58c5bCB' + }, + { + baseSymbol: 'USDT', + cometAddress: '0x995E394b8B2437aC8Ce61Ee0bC610D617962B214' + }, + { + baseSymbol: 'WETH', + cometAddress: '0xE36A30D249f7761327fd973001A32010b521b6Fd' + } + ], + 130: [ + { + baseSymbol: 'USDC', + cometAddress: '0x2c7118c4C88B9841FCF839074c26Ae8f035f2921' + }, + { + baseSymbol: 'WETH', + cometAddress: '0x6C987dDE50dB1dcDd32Cd4175778C2a291978E2a' + } + ], + 137: [ + { + baseSymbol: 'USDC', + cometAddress: '0xF25212E676D1F7F89Cd72fFEe66158f541246445' + }, + { + baseSymbol: 'USDT', + cometAddress: '0xaeB318360f27748Acb200CE616E389A6C9409a07' + } + ], + 2020: [ + { + baseSymbol: 'WETH', + cometAddress: '0x4006eD4097Ee51c09A04c3B0951D28CCf19e6DFE' + }, + { + baseSymbol: 'WRON', + cometAddress: '0xc0Afdbd1cEB621Ef576BA969ce9D4ceF78Dbc0c0' + } + ], + 5000: [ + { + baseSymbol: 'USDe', + cometAddress: '0x606174f62cd968d8e684c645080fa694c1D7786E' + } + ], + 8453: [ + { + baseSymbol: 'USDbC', + cometAddress: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf' + }, + { + baseSymbol: 'WETH', + cometAddress: '0x46e6b214b524310239732D51387075E0e70970bf' + }, + { + baseSymbol: 'USDC', + cometAddress: '0xb125E6687d4313864e53df431d5425969c15Eb2F' + }, + { + baseSymbol: 'AERO', + cometAddress: '0x784efeB622244d2348d4F2522f8860B96fbEcE89' + }, + { + baseSymbol: 'USDS', + cometAddress: '0x2c776041CCFe903071AF44aa147368a9c8EEA518' + } + ], + 42161: [ + { + baseSymbol: 'USDC.e', + cometAddress: '0xA5EDBDD9646f8dFF606d7448e414884C7d905dCA' + }, + { + baseSymbol: 'USDC', + cometAddress: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf' + }, + { + baseSymbol: 'WETH', + cometAddress: '0x6f7D514bbD4aFf3BcD1140B7344b32f063dEe486' + }, + { + baseSymbol: 'USDT', + cometAddress: '0xd98Be00b5D27fc98112BdE293e487f8D4cA57d07' + } + ], + 59144: [ + { + baseSymbol: 'USDC', + cometAddress: '0x8D38A3d6B3c3B7d96D6536DA7Eef94A9d7dbC991' + }, + { + baseSymbol: 'WETH', + cometAddress: comet.address + } + ], + 534352: [ + { + baseSymbol: 'USDC', + cometAddress: '0xB2f97c1Bd3bf02f5e74d13f02E3e26F93D77CE44' + } + ] + }); + } +}); diff --git a/deployments/linea/weth/relations.ts b/deployments/linea/weth/relations.ts new file mode 100644 index 000000000..57b3392f0 --- /dev/null +++ b/deployments/linea/weth/relations.ts @@ -0,0 +1,33 @@ +import baseRelationConfig from '../../relations'; + +export default { + ...baseRelationConfig, + governor: { + artifact: + 'contracts/bridges/linea/LineaBridgeReceiver.sol:LineaBridgeReceiver', + }, + l2MessageService: { + delegates: { + field: { + slot: + '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc', + }, + }, + }, + l2StandardBridge: { + delegates: { + field: { + slot: + '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc', + }, + }, + }, + 'TransparentUpgradeableProxy': { + artifact: 'contracts/ERC20.sol:ERC20', + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, +}; diff --git a/deployments/linea/weth/roots.json b/deployments/linea/weth/roots.json new file mode 100644 index 000000000..c774096d0 --- /dev/null +++ b/deployments/linea/weth/roots.json @@ -0,0 +1,11 @@ +{ + "comet": "0x60F2058379716A64a7A5d29219397e79bC552194", + "configurator": "0x970FfD8E335B8fa4cd5c869c7caC3a90671d5Dc3", + "rewards": "0x2c7118c4C88B9841FCF839074c26Ae8f035f2921", + "cometFactory": "0xaeB318360f27748Acb200CE616E389A6C9409a07", + "bridgeReceiver": "0x1F71901daf98d70B4BAF40DE080321e5C2676856", + "l2MessageService": "0x508Ca82Df566dCD1B0DE8296e70a96332cD644ec", + "l2StandardBridge": "0x353012dc4a9A6cF55c941bADC267f82004A8ceB9", + "l2USDCBridge": "0xA2Ee6Fce4ACB62D95448729cDb781e3BEb62504A", + "bulker": "0x023ee795361B28cDbB94e302983578486A0A5f1B" +} \ No newline at end of file diff --git a/deployments/localhost/dai/configuration.json b/deployments/localhost/dai/configuration.json new file mode 100644 index 000000000..61cbcd5db --- /dev/null +++ b/deployments/localhost/dai/configuration.json @@ -0,0 +1,26 @@ +{ + "name": "Compound DAI", + "symbol": "cDAIv3", + "baseToken": "DAI", + "borrowMin": "1000e6", + "storeFrontPriceFactor": 0.5, + "targetReserves": "5000000e6", + "rates": { + "supplyKink": 0.8, + "supplySlopeLow": 0.0325, + "supplySlopeHigh": 0.4, + "supplyBase": 0, + "borrowKink": 0.8, + "borrowSlopeLow": 0.035, + "borrowSlopeHigh": 0.25, + "borrowBase": 0.015 + }, + "tracking": { + "indexScale": "1e15", + "baseSupplySpeed": "0.000011574074074074073e15", + "baseBorrowSpeed": "0.0011458333333333333e15", + "baseMinForRewards": "1000000e6" + }, + "rewardToken": "GOLD", + "assets": {} +} diff --git a/deployments/localhost/dai/deploy.ts b/deployments/localhost/dai/deploy.ts new file mode 100644 index 000000000..af92db1a0 --- /dev/null +++ b/deployments/localhost/dai/deploy.ts @@ -0,0 +1,604 @@ +import { Deployed, DeploymentManager } from '../../../plugins/deployment_manager'; +import {Comet, FaucetToken, SimplePriceFeed, MarketUpdateProposer, CometProxyAdmin, SimpleTimelock, CometProxyAdminOld, MarketUpdateTimelock, CometFactory, ConfiguratorProxy, Configurator__factory} from '../../../build/types'; +import { + DeploySpec, + exp, + wait, + getConfiguration, + sameAddress, + getConfigurationStruct +} from '../../../src/deploy'; +import '@nomiclabs/hardhat-ethers'; +import { ethers } from 'hardhat'; + +async function makeToken( + deploymentManager: DeploymentManager, + amount: number, + name: string, + decimals: number, + symbol: string +): Promise { + const mint = (BigInt(amount) * 10n ** BigInt(decimals)).toString(); + return deploymentManager.deploy(symbol, 'test/FaucetToken.sol', [mint, name, decimals, symbol]); +} + +async function makePriceFeed( + deploymentManager: DeploymentManager, + alias: string, + initialPrice: number, + decimals: number +): Promise { + return deploymentManager.deploy(alias, 'test/SimplePriceFeed.sol', [initialPrice * 1e8, decimals]); +} + +async function advanceTimeAndMineBlock(delay: number) { + await ethers.provider.send('evm_increaseTime', [delay + 10]); + await ethers.provider.send('evm_mine', []); // Mine a new block to apply the time increase +} + +// TODO: Support configurable assets as well? +export default async function deploy(deploymentManager: DeploymentManager, deploySpec: DeploySpec): Promise { + const trace = deploymentManager.tracer(); + const signer = await deploymentManager.getSigner(); + const ethers = deploymentManager.hre.ethers; + const admin = signer; + + // Deploy governance contracts + const clone = { + comp: '0xc00e94cb662c3520282e6f5717214004a7f26888', + governorBravoImpl: '0xef3b6e9e13706a8f01fe98fdcf66335dc5cfdeed', + governorBravo: '0xc0da02939e1441f497fd74f78ce7decb17b66529', + }; + + const fauceteer = await deploymentManager.deploy('fauceteer', 'test/Fauceteer.sol', []); + const timelock = await deploymentManager.deploy('timelock', 'test/SimpleTimelock.sol', [admin.address]) as SimpleTimelock; + const COMP = await deploymentManager.clone('COMP', clone.comp, [admin.address]); + + const governorImpl = await deploymentManager.clone( + 'governor:implementation', + clone.governorBravoImpl, + [] + ); + const governorProxy = await deploymentManager.clone( + 'governor', + clone.governorBravo, + [ + timelock.address, + COMP.address, + admin.address, + governorImpl.address, + await governorImpl.MIN_VOTING_PERIOD(), + await governorImpl.MIN_VOTING_DELAY(), + await governorImpl.MIN_PROPOSAL_THRESHOLD(), + ] + ); + const governorBravo = governorImpl.attach(governorProxy.address); + await deploymentManager.idempotent( + async () => (await governorBravo.proposalCount()).eq(0), + async () => { + trace(`Initiating Governor using patched Timelock`); + trace(await wait(governorBravo.connect(admin)._initiate(timelock.address))); + } + ); + await timelock.connect(admin).setAdmin(governorBravo.address); + + await deploymentManager.idempotent( + async () => (await COMP.balanceOf(admin.address)).gte((await COMP.totalSupply()).div(3)), + async () => { + trace(`Sending 1/4 of COMP to fauceteer, 1/4 to timelock`); + const amount = (await COMP.balanceOf(admin.address)).div(4); + trace(await wait(COMP.connect(admin).transfer(fauceteer.address, amount))); + trace(await wait(COMP.connect(admin).transfer(timelock.address, amount))); + trace(`COMP.balanceOf(${fauceteer.address}): ${await COMP.balanceOf(fauceteer.address)}`); + trace(`COMP.balanceOf(${timelock.address}): ${await COMP.balanceOf(timelock.address)}`); + } + ); + + await deploymentManager.idempotent( + async () => (await COMP.getCurrentVotes(admin.address)).eq(0), + async () => { + trace(`Delegating COMP votes to ${admin.address}`); + trace(await wait(COMP.connect(admin).delegate(admin.address))); + trace(`COMP.getCurrentVotes(${admin.address}): ${await COMP.getCurrentVotes(admin.address)}`); + } + ); + + const DAI = await makeToken(deploymentManager, 10000000, 'DAI', 18, 'DAI'); + const GOLD = await makeToken(deploymentManager, 20000000, 'GOLD', 8, 'GOLD'); + const SILVER = await makeToken(deploymentManager, 30000000, 'SILVER', 10, 'SILVER'); + + const daiPriceFeed = await makePriceFeed(deploymentManager, 'DAI:priceFeed', 1, 8); + const goldPriceFeed = await makePriceFeed(deploymentManager, 'GOLD:priceFeed', 0.5, 8); + const silverPriceFeed = await makePriceFeed(deploymentManager, 'SILVER:priceFeed', 0.05, 8); + + const assetConfig0 = { + asset: GOLD.address, + priceFeed: goldPriceFeed.address, + decimals: (8).toString(), + borrowCollateralFactor: (0.9e18).toString(), + liquidateCollateralFactor: (0.91e18).toString(), + liquidationFactor: (0.95e18).toString(), + supplyCap: (1000000e8).toString(), + }; + + const assetConfig1 = { + asset: SILVER.address, + priceFeed: silverPriceFeed.address, + decimals: (10).toString(), + borrowCollateralFactor: (0.4e18).toString(), + liquidateCollateralFactor: (0.5e18).toString(), + liquidationFactor: (0.9e18).toString(), + supplyCap: (500000e10).toString(), + }; + + const configOverrides = { + baseTokenPriceFeed: daiPriceFeed.address, + assetConfigs: [assetConfig0, assetConfig1], + }; + + const rewards = await deploymentManager.deploy( + 'rewards', + 'CometRewards.sol', + [admin.address], + maybeForce(deploySpec.rewards) + ); + + await deploymentManager.idempotent( + async () => (await GOLD.balanceOf(rewards.address)).eq(0), + async () => { + trace(`Sending some GOLD to CometRewards`); + const amount = exp(2_000_000, 8); + trace(await wait(GOLD.connect(signer).transfer(rewards.address, amount))); + trace(`GOLD.balanceOf(${rewards.address}): ${await GOLD.balanceOf(rewards.address)}`); + } + ); + + function maybeForce(flag?: boolean): boolean { + return deploySpec.all || flag; + } + + + const { + name, + symbol, + governor, // NB: generally 'timelock' alias, not 'governor' + pauseGuardian, + baseToken, + baseTokenPriceFeed, + supplyKink, + supplyPerYearInterestRateSlopeLow, + supplyPerYearInterestRateSlopeHigh, + supplyPerYearInterestRateBase, + borrowKink, + borrowPerYearInterestRateSlopeLow, + borrowPerYearInterestRateSlopeHigh, + borrowPerYearInterestRateBase, + storeFrontPriceFactor, + trackingIndexScale, + baseTrackingSupplySpeed, + baseTrackingBorrowSpeed, + baseMinForRewards, + baseBorrowMin, + targetReserves, + assetConfigs, + } = await getConfiguration(deploymentManager, configOverrides); + + /* Deploy contracts */ + + const cometProxyAdminOld = await deploymentManager.deploy( + 'cometAdminOld', + 'marketupdates/CometProxyAdminOld.sol', + [], + maybeForce() + ) as CometProxyAdminOld; + + + + const extConfiguration = { + name32: ethers.utils.formatBytes32String(name), + symbol32: ethers.utils.formatBytes32String(symbol) + }; + const cometExt = await deploymentManager.deploy( + 'comet:implementation:implementation', + 'CometExt.sol', + [extConfiguration], + maybeForce(deploySpec.cometExt) + ); + + const cometFactory = await deploymentManager.deploy( + 'cometFactory', + 'CometFactory.sol', + [], + maybeForce(deploySpec.cometMain) + ) as CometFactory; + + const configuration = { + governor, + pauseGuardian, + baseToken, + baseTokenPriceFeed, + extensionDelegate: cometExt.address, + supplyKink, + supplyPerYearInterestRateSlopeLow, + supplyPerYearInterestRateSlopeHigh, + supplyPerYearInterestRateBase, + borrowKink, + borrowPerYearInterestRateSlopeLow, + borrowPerYearInterestRateSlopeHigh, + borrowPerYearInterestRateBase, + storeFrontPriceFactor, + trackingIndexScale, + baseTrackingSupplySpeed, + baseTrackingBorrowSpeed, + baseMinForRewards, + baseBorrowMin, + targetReserves, + assetConfigs, + }; + trace('Timelock address:', timelock.address); + trace('Governor address:', governor); + + const tmpCometImpl = await deploymentManager.deploy( + 'comet:implementation', + 'Comet.sol', + [configuration], + maybeForce(), + ) as Comet; + + trace('Checking tmpCometImpl:supplyKink'); + console.log('tmpCometImpl:supplyKink', await tmpCometImpl.supplyKink()); + const cometProxyContract = await deploymentManager.deploy( + 'comet', + 'vendor/proxy/transparent/TransparentUpgradeableProxy.sol', + [tmpCometImpl.address, cometProxyAdminOld.address, []], // NB: temporary implementation contract + maybeForce() + ); + const factory= await ethers.getContractFactory('Comet'); + const cometProxy= factory.attach(cometProxyContract.address) as Comet; + + trace('tmpCometImpl', tmpCometImpl.address); + + trace('Checking CometProxy:supplyKink'); + console.log('CometProxy:supplyKink', await cometProxy.supplyKink()); + + + const configuratorImpl = await deploymentManager.deploy( + 'configurator-old:implementation', + 'marketupdates/ConfiguratorOld.sol', + [], + maybeForce(deploySpec.cometMain) + ); + + // If we deploy a new proxy, we initialize it to the current/new impl + // If its an existing proxy, the impl we got for the alias must already be current + // In other words, we shan't have deployed an impl in the last step unless there was no proxy too + const configuratorProxyContract = await deploymentManager.deploy( + 'configurator', + 'ConfiguratorProxy.sol', + [configuratorImpl.address, signer.address, (await configuratorImpl.populateTransaction.initialize(admin.address)).data], + maybeForce() + ) as ConfiguratorProxy; + + const configuratorFactory = await ethers.getContractFactory('Configurator') as Configurator__factory; + const configuratorProxy = configuratorFactory.attach(configuratorProxyContract.address); + trace(`Setting factory in Configurator to ${cometFactory.address}`); + await configuratorProxy.connect(admin).setFactory(cometProxy.address, cometFactory.address); + + + const configurationStr = await getConfigurationStruct(deploymentManager); + trace(`Setting configuration in Configurator for ${cometProxy.address}`); + await configuratorProxy.connect(admin).setConfiguration(cometProxy.address, configurationStr); + // await txSetConfiguration.wait(); + + + trace(`Upgrading implementation of Comet...`); + + await configuratorProxyContract.changeAdmin(cometProxyAdminOld.address); + + await cometProxyAdminOld.deployAndUpgradeTo(configuratorProxy.address, cometProxy.address); + + await cometProxyAdminOld.transferOwnership(timelock.address); + + /* Wire things up */ + + // Now configure the configurator and actually deploy comet + // Note: the success of these calls is dependent on who the admin is and if/when its been transferred + // scenarios can pass in an impersonated signer, but real deploys may require proposals for some states + const configurator = configuratorImpl.attach(configuratorProxyContract.address); + + // Also get a handle for Comet, although it may not *actually* support the interface yet + const comet = await deploymentManager.cast(cometProxy.address, 'contracts/CometInterface.sol:CometInterface'); + + // Call initializeStorage if storage not initialized + // Note: we now rely on the fact that anyone may call, which helps separate the proposal + await deploymentManager.idempotent( + async () => (await comet.totalsBasic()).lastAccrualTime == 0, + async () => { + trace(`Initializing Comet at ${comet.address}`); + trace(await wait(comet.connect(admin).initializeStorage())); + } + ); + + // If we aren't admin, we'll need proposals to configure things + const amAdmin = sameAddress(await cometProxyAdminOld.owner(), admin.address); + trace(`Am I admin? ${amAdmin}`); + + // Get the current impl addresses for the proxies, and determine if we've configurated + const $cometImpl = await cometProxyAdminOld.getProxyImplementation(comet.address); + const isTmpImpl = sameAddress($cometImpl, tmpCometImpl.address); + trace(`isTmpImpl ${isTmpImpl} deploySpec.all ${deploySpec.all} deploySpec.cometMain ${deploySpec.cometMain} deploySpec.cometExt ${deploySpec.cometExt}`); + + + /* Transfer to Gov */ + + await deploymentManager.idempotent( + async () => !sameAddress(await configurator.governor(), governor), + async () => { + trace(`Transferring governor of Configurator to ${governor}`); + trace(await wait(configurator.connect(admin).transferGovernor(governor))); + } + ); + + await deploymentManager.idempotent( + async () => !sameAddress(await cometProxyAdminOld.owner(), governor), + async () => { + trace(`Transferring ownership of CometProxyAdmin to ${governor}`); + trace(await wait(cometProxyAdminOld.connect(admin).transferOwnership(governor))); + } + ); + + await deploymentManager.idempotent( + async () => !sameAddress(await rewards.governor(), governor), + async () => { + trace(`Transferring governor of CometRewards to ${governor}`); + trace(await wait(rewards.connect(admin).transferGovernor(governor))); + } + ); + + + // Mint some tokens + trace(`Attempting to mint as ${signer.address}...`); + + await Promise.all( + [[DAI, 1e8], [GOLD, 2e6], [SILVER, 1e7]].map(([faucetToken, unitOfToken]) => { + const asset = faucetToken as FaucetToken; + const units = unitOfToken as number; + + return deploymentManager.idempotent( + async () => (await asset.balanceOf(fauceteer.address)).eq(0), + async () => { + trace(`Minting ${units} ${await asset.symbol()} to fauceteer`); + const amount = exp(units, await asset.decimals()); + trace(await wait(asset.connect(signer).allocateTo(fauceteer.address, amount))); + trace(`asset.balanceOf(${signer.address}): ${await asset.balanceOf(signer.address)}`); + } + ); + }) + ); + + const supplyKinkOld = await comet.supplyKink(); + trace(`supplyKink:`, supplyKinkOld); + + const signers = await ethers.getSigners(); + + const marketUpdateTimelock = (await deploymentManager.deploy( + 'marketUpdateTimelock', + 'marketupdates/MarketUpdateTimelock.sol', + [governor, 2 * 24 * 60 * 60], + maybeForce() + )) as MarketUpdateTimelock; + + // 1) Deploy the address of MarketAdminMultiSig + const marketUpdateMultiSig = signers[3]; + const proposalGuardian = signers[11]; + + const marketUpdateProposer = await deploymentManager.deploy( + 'marketUpdateProposer', + 'marketupdates/MarketUpdateProposer.sol', + [governor, marketUpdateMultiSig.address, proposalGuardian.address, marketUpdateTimelock.address], + maybeForce() + ) as MarketUpdateProposer; + + const cometProxyAdminNew = await deploymentManager.deploy( + 'cometProxyAdminNew', + 'CometProxyAdmin.sol', + [], + maybeForce() + ) as CometProxyAdmin; + + await cometProxyAdminNew.transferOwnership(governor); + + const configuratorNew = await deploymentManager.deploy( + 'configuratorNew', + 'Configurator.sol', + [], + maybeForce() + ); + + const marketAdminPermissionChecker = await deploymentManager.deploy( + 'marketAdminPermissionChecker', + 'marketupdates/MarketAdminPermissionChecker.sol', + [ethers.constants.AddressZero, ethers.constants.AddressZero], + maybeForce() + ); + + await marketAdminPermissionChecker.transferOwnership( + governor + ); + + const newSupplyKinkByGovernorTimelock = 300n; + + trace('Trigger updates to enable market admin'); + const firstProposalTxn = await governorBravo + .connect(admin) + .propose( + [ + cometProxyAdminOld.address, + cometProxyAdminOld.address, + cometProxyAdminNew.address, + marketAdminPermissionChecker.address, + configuratorProxyContract.address, + cometProxyAdminNew.address, + marketUpdateTimelock.address, + ], + [0, 0, 0, 0, 0, 0, 0], + [ + 'changeProxyAdmin(address,address)', + 'changeProxyAdmin(address,address)', + 'upgrade(address,address)', + 'setMarketAdmin(address)', + 'setMarketAdminPermissionChecker(address)', + 'setMarketAdminPermissionChecker(address)', + 'setMarketUpdateProposer(address)', + ], + [ + ethers.utils.defaultAbiCoder.encode( + ['address', 'address'], + [configuratorProxyContract.address, cometProxyAdminNew.address] + ), + ethers.utils.defaultAbiCoder.encode( + ['address', 'address'], + [cometProxy.address, cometProxyAdminNew.address] + ), + ethers.utils.defaultAbiCoder.encode( + ['address', 'address'], + [configuratorProxyContract.address, configuratorNew.address] + ), + ethers.utils.defaultAbiCoder.encode( + ['address'], + [marketUpdateTimelock.address] + ), + ethers.utils.defaultAbiCoder.encode( + ['address'], + [marketAdminPermissionChecker.address] + ), + ethers.utils.defaultAbiCoder.encode( + ['address'], + [marketAdminPermissionChecker.address] + ), + ethers.utils.defaultAbiCoder.encode( + ['address'], + [marketUpdateProposer.address] + ), + ], + 'Proposal to trigger updates for market admin' + ); + const firstProposalReceipt = await firstProposalTxn.wait(); + + const firstProposalID = firstProposalReceipt.events.find( + (event) => event.event === 'ProposalCreated' + ).args.id; + console.log('first proposal id: ', firstProposalID); + + const stateBeforeStart = await governorBravo.state(firstProposalID); + console.log('Proposal State before start block forwarding:', stateBeforeStart); + + const votingDelay = await governorBravo.votingDelay(); + // Fast-forward by votingDelay blocks to reach the start of the voting period + for (let i = 0; i < votingDelay.toNumber(); i++) { + await ethers.provider.send('evm_mine', []); + } + const stateAfterStart = await governorBravo.state(firstProposalID); + console.log('Proposal State after start block forwarding:', stateAfterStart); + + await governorBravo.connect(admin).castVote(firstProposalID, 1); + + const votingPeriod = await governorBravo.votingPeriod(); + // Fast-forward to the end of the voting period + for (let i = 0; i <= votingPeriod.toNumber(); i++) { + await ethers.provider.send('evm_mine', []); // fast-forward remaining blocks + } + + const stateAfter = await governorBravo.state(firstProposalID); + console.log('Proposal State after fast-forward:', stateAfter); + + trace('Queue from Governor Bravo'); + await governorBravo.connect(admin).queue(firstProposalID); + trace('Execute from Governor Bravo'); + await governorBravo.connect(admin).execute(firstProposalID); + + trace('Update supply kink through GovernorBravo'); + const secondProposalTxn = await governorBravo.connect(admin).propose( + [ + configuratorProxyContract.address, + cometProxyAdminNew.address + ], + [0,0], + [ + 'setSupplyKink(address,uint64)', + 'deployAndUpgradeTo(address,address)' + ], + [ + ethers.utils.defaultAbiCoder.encode(['address', 'uint64'], [cometProxy.address, newSupplyKinkByGovernorTimelock]), + ethers.utils.defaultAbiCoder.encode(['address', 'address'], [configuratorProxyContract.address, cometProxy.address]) + ], + 'Proposal to update supply kink' + ); + const secondProposalReceipt = await secondProposalTxn.wait(); + + const secondProposalID = secondProposalReceipt.events.find( + (event) => event.event === 'ProposalCreated' + ).args.id; + console.log('second proposal id: ', secondProposalID); + + const stateBeforeStart2 = await governorBravo.state(secondProposalID); + console.log('Proposal State before start block forwarding #2:', stateBeforeStart2); + + const votingDelay2 = await governorBravo.votingDelay(); + // Fast-forward by votingDelay blocks to reach the start of the voting period + for (let i = 0; i < votingDelay2.toNumber(); i++) { + await ethers.provider.send('evm_mine', []); + } + const stateAfterStart2 = await governorBravo.state(secondProposalID); + console.log('Proposal State after start block forwarding #2:', stateAfterStart2); + + await governorBravo.connect(admin).castVote(secondProposalID, 1); + + const votingPeriod2 = await governorBravo.votingPeriod(); + // Fast-forward to the end of the voting period + for (let i = 0; i <= votingPeriod2.toNumber(); i++) { + await ethers.provider.send('evm_mine', []); // fast-forward remaining blocks + } + + const stateAfter2 = await governorBravo.state(secondProposalID); + console.log('Proposal State after fast-forward #2:', stateAfter2); + + trace('Queue from Governor Bravo #2'); + await governorBravo.connect(admin).queue(secondProposalID); + trace('Execute from Governor Bravo #2'); + await governorBravo.connect(admin).execute(secondProposalID); + + const supplyKinkByGovernorTimelock = await (comet).supplyKink(); + trace(`supplyKinkByGovernorTimelock:`, supplyKinkByGovernorTimelock); + + trace('MarketAdmin: Setting new supplyKink in Configurator and deploying Comet'); + const newSupplyKinkByMarketAdmin = 100n; + await marketUpdateProposer.connect(marketUpdateMultiSig).propose( + [ + configuratorProxyContract.address, + cometProxyAdminNew.address + ], + [0, 0], + [ + 'setSupplyKink(address,uint64)', + 'deployAndUpgradeTo(address,address)' + ], + [ + ethers.utils.defaultAbiCoder.encode(['address', 'uint64'], [cometProxy.address, newSupplyKinkByMarketAdmin]), + ethers.utils.defaultAbiCoder.encode(['address', 'address'], [configuratorProxyContract.address, cometProxy.address]) + ], + 'Test market update' + ); + + await advanceTimeAndMineBlock(2 * 24 * 60 * 60 + 10); // Fast forwarding by 2 days and a few seconds + + trace('Executing market update proposal'); + + await marketUpdateProposer.connect(marketUpdateMultiSig).execute(1); + + trace('checking supplyKink after market update'); + const supplyKinkByMarketAdmin = await (cometProxy).supplyKink(); + trace(`supplyKinkByMarketAdmin:`, supplyKinkByMarketAdmin); + + return { comet, configurator, rewards, fauceteer }; +} diff --git a/deployments/mainnet/usdc/relations.ts b/deployments/mainnet/usdc/relations.ts index 3baa92f06..043007f41 100644 --- a/deployments/mainnet/usdc/relations.ts +++ b/deployments/mainnet/usdc/relations.ts @@ -29,6 +29,14 @@ export default { } } }, + ERC1967Proxy: { + artifact: 'contracts/ERC20.sol:ERC20', + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, arbitrumInbox: { delegates: { field: { @@ -107,6 +115,30 @@ export default { } } }, + lineaMessageService: { + delegates: { + field: { + slot: + '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, + lineaL1TokenBridge: { + delegates: { + field: { + slot: + '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, + lineaL1USDCBridge: { + delegates: { + field: { + slot: + '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, scrollMessenger: { delegates: { field: { diff --git a/deployments/mainnet/usdc/roots.json b/deployments/mainnet/usdc/roots.json index 922ba04ce..f01a53815 100644 --- a/deployments/mainnet/usdc/roots.json +++ b/deployments/mainnet/usdc/roots.json @@ -1,27 +1,30 @@ { - "l1TokenAdminRegistry": "0xb22764f98dD05c789929716D677382Df22C05Cb6", - "comptrollerV2": "0x3d9819210a31b4961b30ef54be2aed79b9c9cd3b", - "comet": "0xc3d688B66703497DAA19211EEdff47f25384cdc3", - "configurator": "0x316f9708bB98af7dA9c68C1C3b5e79039cD336E3", - "rewards": "0x1B0e765F6224C21223AeA2af16c1C46E38885a40", - "bulker": "0xa397a8C2086C554B531c02E29f3291c9704B00c7", - "fxRoot": "0xfe5e5D361b2ad62c541bAb87C45a0B9B018389a2", - "arbitrumInbox": "0x4Dbd4fc535Ac27206064B68FfCf827b0A60BAB3f", - "arbitrumL1GatewayRouter": "0x72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef", - "CCTPTokenMessenger": "0xbd3fa81b58ba92a82136038b25adec7066af3155", - "CCTPMessageTransmitter": "0x0a992d191deec32afe36203ad87d7d289a738f81", - "baseL1CrossDomainMessenger": "0x866E82a600A1414e583f7F13623F1aC5d58b0Afa", - "baseL1StandardBridge": "0x3154Cf16ccdb4C6d922629664174b904d80F2C35", - "baseL1USDSBridge": "0xA5874756416Fa632257eEA380CAbd2E87cED352A", - "opL1CrossDomainMessenger": "0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1", - "opL1StandardBridge": "0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1", - "mantleL1CrossDomainMessenger": "0x676A795fe6E43C17c668de16730c3F690FEB7120", - "mantleL1StandardBridge": "0x95fC37A27a2f68e3A647CDc081F0A89bb47c3012", - "unichainL1CrossDomainMessenger": "0x9A3D64E386C18Cb1d6d5179a9596A4B5736e98A6", - "unichainL1StandardBridge": "0x81014F44b0a345033bB2b3B21C7a1A308B35fEeA", - "scrollMessenger": "0x6774Bcbd5ceCeF1336b5300fb5186a12DDD8b367", - "scrollL1USDCGateway": "0xf1AF3b23DE0A5Ca3CAb7261cb0061C0D779A5c7B", - "l1CCIPRouter": "0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D", - "roninl1CCIPOnRamp": "0xdC5b578ff3AFcC4A4a6E149892b9472390b50844", - "roninl1NativeBridge": "0x64192819Ac13Ef72bF6b5AE239AC672B43a9AF08" + "l1TokenAdminRegistry": "0xb22764f98dD05c789929716D677382Df22C05Cb6", + "comptrollerV2": "0x3d9819210a31b4961b30ef54be2aed79b9c9cd3b", + "comet": "0xc3d688B66703497DAA19211EEdff47f25384cdc3", + "configurator": "0x316f9708bB98af7dA9c68C1C3b5e79039cD336E3", + "rewards": "0x1B0e765F6224C21223AeA2af16c1C46E38885a40", + "bulker": "0xa397a8C2086C554B531c02E29f3291c9704B00c7", + "fxRoot": "0xfe5e5D361b2ad62c541bAb87C45a0B9B018389a2", + "arbitrumInbox": "0x4Dbd4fc535Ac27206064B68FfCf827b0A60BAB3f", + "arbitrumL1GatewayRouter": "0x72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef", + "CCTPTokenMessenger": "0xbd3fa81b58ba92a82136038b25adec7066af3155", + "CCTPMessageTransmitter": "0x0a992d191deec32afe36203ad87d7d289a738f81", + "baseL1CrossDomainMessenger": "0x866E82a600A1414e583f7F13623F1aC5d58b0Afa", + "baseL1StandardBridge": "0x3154Cf16ccdb4C6d922629664174b904d80F2C35", + "baseL1USDSBridge": "0xA5874756416Fa632257eEA380CAbd2E87cED352A", + "opL1CrossDomainMessenger": "0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1", + "opL1StandardBridge": "0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1", + "mantleL1CrossDomainMessenger": "0x676A795fe6E43C17c668de16730c3F690FEB7120", + "mantleL1StandardBridge": "0x95fC37A27a2f68e3A647CDc081F0A89bb47c3012", + "unichainL1CrossDomainMessenger": "0x9A3D64E386C18Cb1d6d5179a9596A4B5736e98A6", + "unichainL1StandardBridge": "0x81014F44b0a345033bB2b3B21C7a1A308B35fEeA", + "scrollMessenger": "0x6774Bcbd5ceCeF1336b5300fb5186a12DDD8b367", + "scrollL1USDCGateway": "0xf1AF3b23DE0A5Ca3CAb7261cb0061C0D779A5c7B", + "l1CCIPRouter": "0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D", + "lineaMessageService": "0xd19d4B5d358258f05D7B411E21A1460D11B0876F", + "lineaL1TokenBridge": "0x051F1D88f0aF5763fB888eC4378b4D8B29ea3319", + "lineaL1USDCBridge": "0x504A330327A089d8364C4ab3811Ee26976d388ce", + "roninl1CCIPOnRamp": "0xdC5b578ff3AFcC4A4a6E149892b9472390b50844", + "roninl1NativeBridge": "0x64192819Ac13Ef72bF6b5AE239AC672B43a9AF08" } \ No newline at end of file diff --git a/deployments/mainnet/weth/relations.ts b/deployments/mainnet/weth/relations.ts index 4211ead18..64977eee5 100644 --- a/deployments/mainnet/weth/relations.ts +++ b/deployments/mainnet/weth/relations.ts @@ -22,6 +22,22 @@ export default { } } }, + ERC1967Proxy: { + artifact: 'contracts/ERC20.sol:ERC20', + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, + WOETHProxy: { + artifact: 'contracts/ERC20.sol:ERC20', + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, 'TransparentUpgradeableProxy': { artifact: 'contracts/ERC20.sol:ERC20', delegates: { diff --git a/deployments/ronin/weth/roots.json b/deployments/ronin/weth/roots.json index 80de492d4..7756d849c 100644 --- a/deployments/ronin/weth/roots.json +++ b/deployments/ronin/weth/roots.json @@ -7,5 +7,6 @@ "l2CCIPRouter": "0x46527571D5D1B68eE7Eb60B18A32e6C60DcEAf99", "l2CCIPOffRamp": "0x320A10449556388503Fd71D74A16AB52e0BD1dEb", "roninl2NativeBridge": "0x0cf8ff40a508bdbc39fbe1bb679dcba64e65c7df", - "bulker": "0x840281FaD56DD88afba052B7F18Be2A65796Ecc6" + "bulker": "0x840281FaD56DD88afba052B7F18Be2A65796Ecc6", + "l2TokenAdminRegistry": "0x90e83d532A4aD13940139c8ACE0B93b0DdbD323a" } \ No newline at end of file diff --git a/hardhat.config.ts b/hardhat.config.ts index 3231e93a6..5d1eeb073 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -2,13 +2,14 @@ import 'dotenv/config'; import { HardhatUserConfig, task } from 'hardhat/config'; import '@compound-finance/hardhat-import'; -import '@nomiclabs/hardhat-ethers'; import '@nomiclabs/hardhat-etherscan'; +import '@tenderly/hardhat-tenderly'; +import '@nomiclabs/hardhat-ethers'; import '@typechain/hardhat'; import 'hardhat-chai-matchers'; import 'hardhat-change-network'; import 'hardhat-contract-sizer'; -import 'hardhat-cover'; +import 'solidity-coverage'; import 'hardhat-gas-reporter'; // Hardhat tasks @@ -46,6 +47,9 @@ import unichainWETHRelationConfigMap from './deployments/unichain/weth/relations import scrollRelationConfigMap from './deployments/scroll/usdc/relations'; import roninRelationConfigMap from './deployments/ronin/weth/relations'; import roninWronRelationConfigMap from './deployments/ronin/wron/relations'; +import lineaUsdcRelationConfigMap from './deployments/linea/usdc/relations'; +import lineaUsdtRelationConfigMap from './deployments/linea/usdt/relations'; +import lineaWethRelationConfigMap from './deployments/linea/weth/relations'; task('accounts', 'Prints the list of accounts', async (taskArgs, hre) => { for (const account of await hre.ethers.getSigners()) console.log(account.address); @@ -57,15 +61,16 @@ const { ETH_PK, ETHERSCAN_KEY, SNOWTRACE_KEY, - POLYGONSCAN_KEY, - ARBISCAN_KEY, - BASESCAN_KEY, - OPTIMISMSCAN_KEY, - MANTLESCAN_KEY, - SCROLLSCAN_KEY, + // POLYGONSCAN_KEY, + // ARBISCAN_KEY, + // BASESCAN_KEY, + // OPTIMISMSCAN_KEY, + // MANTLESCAN_KEY, + // SCROLLSCAN_KEY, ANKR_KEY, _TENDERLY_KEY_RONIN, - MNEMONIC = 'myth like bonus scare over problem client lizard pioneer submit female collect', + _TENDERLY_KEY_POLYGON, + MNEMONIC = 'myth like woof scare over problem client lizard pioneer submit female collect', REPORT_GAS = 'false', NETWORK_PROVIDER = '', GOV_NETWORK_PROVIDER = '', @@ -75,8 +80,10 @@ const { } = process.env; function* deriveAccounts(pk: string, n: number = 10) { - for (let i = 0; i < n; i++) - yield (BigInt('0x' + pk) + BigInt(i)).toString(16); + for (let i = 0; i < n; i++){ + if(!pk.startsWith('0x')) pk = '0x' + pk; + yield (BigInt(pk) + BigInt(i)).toString(16); + } } export function requireEnv(varName, msg?: string): string { @@ -93,13 +100,13 @@ export function requireEnv(varName, msg?: string): string { 'SNOWTRACE_KEY', 'INFURA_KEY', 'ANKR_KEY', - 'POLYGONSCAN_KEY', - 'ARBISCAN_KEY', - 'LINEASCAN_KEY', - 'OPTIMISMSCAN_KEY', - 'MANTLESCAN_KEY', + // 'POLYGONSCAN_KEY', + // 'ARBISCAN_KEY', + // 'LINEASCAN_KEY', + // 'OPTIMISMSCAN_KEY', + // 'MANTLESCAN_KEY', 'UNICHAIN_QUICKNODE_KEY', - 'SCROLLSCAN_KEY' + // 'SCROLLSCAN_KEY' ].map((v) => requireEnv(v)); // Networks @@ -111,11 +118,11 @@ interface NetworkConfig { gasPrice?: number | 'auto'; } -const networkConfigs: NetworkConfig[] = [ +export const networkConfigs: NetworkConfig[] = [ { network: 'mainnet', chainId: 1, - url: `https://rpc.ankr.com/eth/${ANKR_KEY}`, + url: `https://rpc.ankr.com/eth/${ANKR_KEY}` }, { network: 'sepolia', @@ -131,7 +138,8 @@ const networkConfigs: NetworkConfig[] = [ { network: 'polygon', chainId: 137, - url: `https://rpc.ankr.com/polygon/${ANKR_KEY}`, + url: `https://polygon.gateway.tenderly.co/${_TENDERLY_KEY_POLYGON}`, + // url: `https://rpc.ankr.com/polygon/${ANKR_KEY}`, }, { network: 'optimism', @@ -151,6 +159,11 @@ const networkConfigs: NetworkConfig[] = [ chainId: 130, url: `https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}`, }, + { + network: 'linea', + chainId: 59144, + url: `https://rpc.ankr.com/linea/${ANKR_KEY}`, + }, { network: 'base', chainId: 8453, @@ -175,7 +188,12 @@ const networkConfigs: NetworkConfig[] = [ network: 'scroll', chainId: 534352, url: 'https://rpc.scroll.io', - } + }, + { + network: 'linea', + chainId: 59144, + url: `https://rpc.ankr.com/linea/${ANKR_KEY}`, + }, ]; function getDefaultProviderURL(network: string) { @@ -187,7 +205,7 @@ function setupDefaultNetworkProviders(hardhatConfig: HardhatUserConfig) { hardhatConfig.networks[netConfig.network] = { chainId: netConfig.chainId, url: - (netConfig.network === GOV_NETWORK ? GOV_NETWORK_PROVIDER : undefined) || + (netConfig.network === GOV_NETWORK ? GOV_NETWORK_PROVIDER || undefined : undefined) || NETWORK_PROVIDER || netConfig.url || getDefaultProviderURL(netConfig.network), @@ -226,6 +244,18 @@ const config: HardhatUserConfig = { }, networks: { + optimismSepolia: { + url: 'https://sepolia.optimism.io', + chainId: 11155420 + }, + arbitrumSepolia: { + url: 'https://arbitrum-sepolia.blockpi.network/v1/rpc/public', + chainId: 421614 + }, + mainnetSepolia: { + url: 'https://ethereum-sepolia.blockpi.network/v1/rpc/public', + chainId: 11155111 + }, hardhat: { chainId: 1337, loggingEnabled: !!process.env['LOGGING'], @@ -240,6 +270,51 @@ const config: HardhatUserConfig = { //hardfork: 'london', chains: networkConfigs.reduce((acc, { chainId }) => { if (chainId === 1) return acc; + if (chainId === 59144) { + acc[chainId] = { + hardforkHistory: { + berlin: 1, + london: 2, + } + }; + return acc; + } + if (chainId === 42161) { + acc[chainId] = { + hardforkHistory: { + berlin: 1, + london: 2, + } + }; + return acc; + } + if (chainId === 5000) { + acc[chainId] = { + hardforkHistory: { + berlin: 1, + london: 2, + } + }; + return acc; + } + if (chainId === 137) { + acc[chainId] = { + hardforkHistory: { + berlin: 1, + london: 2, + } + }; + return acc; + } + if (chainId === 534352) { + acc[chainId] = { + hardforkHistory: { + berlin: 1, + london: 2, + } + }; + return acc; + } if (chainId === 2020) { acc[chainId] = { hardforkHistory: { @@ -272,20 +347,21 @@ const config: HardhatUserConfig = { avalanche: SNOWTRACE_KEY, avalancheFujiTestnet: SNOWTRACE_KEY, // Polygon - polygon: POLYGONSCAN_KEY, + polygon: ETHERSCAN_KEY, // Arbitrum - arbitrumOne: ARBISCAN_KEY, - arbitrumTestnet: ARBISCAN_KEY, - arbitrum: ARBISCAN_KEY, + arbitrumOne: ETHERSCAN_KEY, + arbitrumTestnet: ETHERSCAN_KEY, + arbitrum: ETHERSCAN_KEY, // Base - base: BASESCAN_KEY, + base: ETHERSCAN_KEY, // optimism: OPTIMISMSCAN_KEY, - optimisticEthereum: OPTIMISMSCAN_KEY, + optimisticEthereum: ETHERSCAN_KEY, // Mantle - mantle: MANTLESCAN_KEY, + mantle: ETHERSCAN_KEY, unichain: ETHERSCAN_KEY, // Scroll - 'scroll': SCROLLSCAN_KEY, + 'scroll': ETHERSCAN_KEY, + linea: ETHERSCAN_KEY, }, customChains: [ { @@ -335,6 +411,14 @@ const config: HardhatUserConfig = { // browserURL: 'https://mantlescan.xyz/' } }, + { + network: 'linea', + chainId: 59144, + urls: { + apiURL: 'https://api.lineascan.build/api', + browserURL: 'https://lineascan.build/' + } + }, { network: 'ronin', chainId: 2020, @@ -401,7 +485,12 @@ const config: HardhatUserConfig = { 'ronin': { weth: roninRelationConfigMap, wron: roninWronRelationConfigMap - } + }, + 'linea': { + usdc: lineaUsdcRelationConfigMap, + usdt: lineaUsdtRelationConfigMap, + weth: lineaWethRelationConfigMap + }, }, }, @@ -566,6 +655,24 @@ const config: HardhatUserConfig = { deployment: 'usdc', auxiliaryBase: 'mainnet' }, + { + name: 'linea-usdc', + network: 'linea', + deployment: 'usdc', + auxiliaryBase: 'mainnet' + }, + { + name: 'linea-usdt', + network: 'linea', + deployment: 'usdt', + auxiliaryBase: 'mainnet' + }, + { + name: 'linea-weth', + network: 'linea', + deployment: 'weth', + auxiliaryBase: 'mainnet' + }, { name: 'ronin-weth', network: 'ronin', @@ -581,6 +688,13 @@ const config: HardhatUserConfig = { ], }, + tenderly: { + project: 'comet', + username: process.env.TENDERLY_USERNAME || '', + accessKey: process.env.TENDERLY_ACCESS_KEY || '', + privateVerification: false, + }, + mocha: { reporter: 'mocha-multi-reporters', reporterOptions: { diff --git a/package.json b/package.json index 88a98ec0f..bfc6c6e8d 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "scripts": { "build": "hardhat compile", "clean": "hardhat clean && rm -rf build/ cache/ coverage* dist/", - "cover": "hardhat cover && npx istanbul report --include coverage.json html lcov", + "cover": "hardhat coverage && npx istanbul report --include coverage.json html lcov", "gas": "REPORT_GAS=true yarn test", "lint": "eslint 'plugins/**/*' 'scenario/**/*' 'scripts/**/*' 'src/**/*' 'tasks/**/*' 'test/**/*' hardhat.config.ts", "lint-contracts": "solhint 'contracts/**/*.sol'", @@ -37,7 +37,7 @@ "scenario": "hardhat scenario", "spider": "hardhat spider", "test": "hardhat test ./test/*.ts ./test/**/*.ts ./plugins/deployment_manager/test/*.ts ", - "test:coverage": "hardhat cover --no-compile", + "test:coverage": "NODE_OPTIONS='--max-old-space-size=8192' hardhat coverage --no-compile", "audit:liquidator": "vendoza contracts/liquidator/vendor/manifest.json", "audit:vendor": "vendoza contracts/vendor/manifest.json", "slither:fn-clashes": "slither-check-upgradeability contracts/Configurator.sol Configurator --proxy-filename contracts/ConfiguratorProxy.sol --proxy-name ConfiguratorProxy", @@ -48,10 +48,13 @@ "license": "UNLICENSED", "dependencies": { "@flashbots/ethers-provider-bundle": "^0.5.0", + "@tenderly/api-client": "^1.1.0", + "@tenderly/sdk": "^0.3.1", "chai": "^4.3.4", "chai-as-promised": "^7.1.1", "deep-object-diff": "^1.1.9", "jest-diff": "^27.4.2", + "solidity-coverage": "^0.8.16", "undici": "^5.21.2" }, "devDependencies": { @@ -76,11 +79,10 @@ "eslint": "^8.12.0", "ethers": "^5.7.2", "fast-glob": "^3.2.7", - "hardhat": "2.22.14", + "hardhat": "^2.22.17", "hardhat-chai-matchers": "https://github.com/jflatow/hardhat/releases/download/viaIR/nomicfoundation-hardhat-chai-matchers-v1.0.4.tgz", "hardhat-change-network": "^0.0.7", "hardhat-contract-sizer": "^2.10.0", - "hardhat-cover": "compound-finance/hardhat-cover", "hardhat-gas-reporter": "^1.0.7", "mocha-junit-reporter": "^2.0.2", "mocha-multi-reporters": "hayesgm/mocha-multi-reporters#hayesgm/reporter-options-to-option", @@ -90,10 +92,17 @@ "ts-node": "^10.4.0", "typechain": "^6.0.2", "typescript": "^4.4.4", - "vendoza": "0.0.4" + "vendoza": "0.0.4", + "@tenderly/hardhat-tenderly": "^2.5.2" }, "repository": "git@github.com:compound-finance/comet.git", "resolutions": { - "mocha": "^9.1.3" - } -} \ No newline at end of file + "minimatch": "^3.1.2", + "mocha": "^9.1.3", + "cbor": "8.1.0", + "micro-eth-signer":"0.14.0", + "@tenderly/hardhat-tenderly/ethers": "^6.7.0", + "@tenderly/hardhat-tenderly/@nomicfoundation/hardhat-ethers": "3.0.9" + }, + "packageManager": "yarn@1.22.22" +} diff --git a/plugins/deployment_manager/Deploy.ts b/plugins/deployment_manager/Deploy.ts index 01bf459de..e8601ef34 100644 --- a/plugins/deployment_manager/Deploy.ts +++ b/plugins/deployment_manager/Deploy.ts @@ -47,11 +47,14 @@ async function doDeploy( factory: ContractFactory, args: any[], opts: DeployOpts, - src: string + src: string, + gasPrice?: bigint ): Promise { const trace = opts.trace ?? debug; trace(`Deploying ${name} with args ${stringifyJson(args)} via ${src}`); - const contract = await factory.deploy(...args); + const contract = await factory.deploy(...args, { + gasPrice, + }); await contract.deployed(); trace(contract.deployTransaction, `Deployed ${name} @ ${contract.address}`); return contract as C; @@ -114,7 +117,8 @@ export async function deploy( factory = factory.connect(deployOpts.connect); } - const contract = await doDeploy(contractName, factory, deployArgs, deployOpts, 'artifact'); + const gasPrice = await hre.ethers.provider.getGasPrice(); + const contract = await doDeploy(contractName, factory, deployArgs, deployOpts, 'artifact', gasPrice.toBigInt() * 12n / 10n); const buildFile = await getBuildFileFromArtifacts(contractFile, contractFileName); if (!buildFile.contract) { // This is just to make it clear which contract was deployed, when reading the build file diff --git a/plugins/deployment_manager/DeploymentManager.ts b/plugins/deployment_manager/DeploymentManager.ts index 5057cf0b2..afe2cbd8b 100644 --- a/plugins/deployment_manager/DeploymentManager.ts +++ b/plugins/deployment_manager/DeploymentManager.ts @@ -17,6 +17,8 @@ import { ExtendedNonceManager } from './NonceManager'; import { asyncCallWithTimeout, debug, getEthersContract, mergeIntoProxyContract, txCost } from './Utils'; import { deleteVerifyArgs, getVerifyArgs } from './VerifyArgs'; import { verifyContract, VerifyArgs, VerificationStrategy } from './Verify'; +import path from 'path'; +import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'fs'; interface DeploymentDelta { old: { start: Date, count: number, spider: Spider }; @@ -29,6 +31,7 @@ interface DeploymentManagerConfig { importRetryDelay?: number; writeCacheToDisk?: boolean; verificationStrategy?: VerificationStrategy; + saveBytecode?: boolean; } export type Deployed = { [alias: Alias]: Contract }; @@ -61,7 +64,6 @@ export class DeploymentManager { this.config = config; this.counter = 0; this.spent = 0; - this.cache = new Cache( this.network, this.deployment, @@ -178,7 +180,7 @@ export class DeploymentManager { contractFile: string, deployArgs: DeployArgs, force?: boolean, - retries?: number + retries?: number, ): Promise { const maybeExisting: C = await this.contract(alias); if (!maybeExisting || force) { @@ -242,14 +244,108 @@ export class DeploymentManager { /* Deploys a contract from Hardhat artifacts */ async _deploy(contractFile: string, deployArgs: any[], retries?: number): Promise { + if(this.config.saveBytecode) { + const contractFileName = contractFile.split('/').reverse()[0].split('.')[0]; + const artifact = this.hre.artifacts.readArtifactSync(contractFileName); + const iface = new this.hre.ethers.utils.Interface( + artifact.abi + ); + + const bytecodeWithArgs = + artifact.bytecode + + iface.encodeDeploy(deployArgs).slice(2); + + this.stashBytecode(bytecodeWithArgs); + } const contract = await this.retry( - async () => deploy(contractFile, deployArgs, this.hre, await this.deployOpts()), + async () => { + const signer = await this.getSigner(); + + // check tx in pending state + const pendingTx = await signer.provider.getTransactionCount(signer.address, 'pending'); + console.log(`Pending transactions for ${contractFile} deployment: ${pendingTx}`); + + return deploy(contractFile, deployArgs, this.hre, await this.deployOpts()); + }, retries ); this.counter++; return contract; } + + async cleanCache() { + const files = [ + path.resolve(__dirname, '../../cache/relay.json'), + path.resolve(__dirname, '../../cache/currentProposal.json'), + path.resolve(__dirname, '../../cache/bytecodes.json'), + ]; + for (const file of files) { + if (existsSync(file)) { + unlinkSync(file); + } + } + } + + stashRelayMessage(messanger: string, callData: string, signer: string) { + try { + const cacheDir = path.resolve(__dirname, '../..', 'cache'); + mkdirSync(cacheDir, { recursive: true }); + const file = path.join(cacheDir, 'relay.json'); + let data: any[] = []; + + if (existsSync(file)) { + try { + const raw = readFileSync(file, 'utf8').trim(); + if (raw) { + const parsed = JSON.parse(raw); + data = Array.isArray(parsed) ? parsed : [parsed]; + } + } catch (err) { + console.warn('Invalid cache, recreating:', err); + } + } + + const newEntry = { messanger, callData, signer }; + if (!data.some(entry => JSON.stringify(entry) === JSON.stringify(newEntry))) { + data.push(newEntry); + writeFileSync(file, JSON.stringify(data, null, 2), 'utf8'); + } else { + console.log('Entry already exists in cache, not rewriting.'); + } + } catch (e) { + console.warn('Failed to cache proposal:', e); + } + } + + stashBytecode(bytecodeWithArgs: string) { + try { + const cacheDir = path.resolve(__dirname, '../..', 'cache'); + mkdirSync(cacheDir, { recursive: true }); + + const file = path.join(cacheDir, 'bytecodes.json'); + + let data: string[] = []; + if (existsSync(file)) { + try { + const raw = readFileSync(file, 'utf8').trim(); + if (raw) { + const parsed = JSON.parse(raw); + data = Array.isArray(parsed) ? parsed : [parsed]; + } + } catch (err) { + console.warn('Invalid cache, recreating:', err); + } + } + + data.push(bytecodeWithArgs); + writeFileSync(file, JSON.stringify(data, null, 2), 'utf8'); + console.log(`Proposal cached ${file}`); + } catch (e) { + console.warn('Failed to cache proposal:', e); + } + } + /* Deploys a contract from a build file, e.g. an one imported contract */ async _deployBuild(buildFile: BuildFile, deployArgs: any[], retries?: number): Promise { const contract = await this.retry( diff --git a/plugins/deployment_manager/Migration.ts b/plugins/deployment_manager/Migration.ts index b9d89eb1c..293f7c9e1 100644 --- a/plugins/deployment_manager/Migration.ts +++ b/plugins/deployment_manager/Migration.ts @@ -28,7 +28,13 @@ export async function loadMigration(path: string): Promise> { export async function loadMigrations(paths: string[]): Promise[]> { const migrations = []; for (const path of paths) { - migrations.push(await loadMigration(path)); + const enacted = (await loadMigration(path)).actions?.enacted; + if(!enacted){ + migrations.push(await loadMigration(path)); + continue; + } + if(!await enacted(undefined, undefined)) + migrations.push(await loadMigration(path)); } return migrations; } diff --git a/plugins/deployment_manager/Spider.ts b/plugins/deployment_manager/Spider.ts index a4c2ffffe..83c54c4cd 100644 --- a/plugins/deployment_manager/Spider.ts +++ b/plugins/deployment_manager/Spider.ts @@ -252,12 +252,13 @@ export async function spider( const contracts = new Map(); for (const [alias, address] of roots) { + const node = { aliasRender: { template: alias, i: 0 }, address, path: [] }; await crawl( cache, network, hre, relations, - { aliasRender: { template: alias, i: 0 }, address, path: [] }, + node, context, aliases, contracts, diff --git a/plugins/import/etherscan.ts b/plugins/import/etherscan.ts index 6c5c2f10a..f0fc8401b 100644 --- a/plugins/import/etherscan.ts +++ b/plugins/import/etherscan.ts @@ -1,4 +1,5 @@ import axios from 'axios'; +import { networkConfigs } from '../../hardhat.config'; export interface Result { status: string; @@ -6,28 +7,41 @@ export interface Result { result: string; } +// Updated because of Etherscan V2 update. Not tested and could lead to issues export function getEtherscanApiUrl(network: string): string { - let host = { - rinkeby: 'api-rinkeby.etherscan.io', - ropsten: 'api-ropsten.etherscan.io', - sepolia: 'api-sepolia.etherscan.io', - mainnet: 'api.etherscan.io', - fuji: 'api-testnet.snowtrace.io', - avalanche: 'api.snowtrace.io', - polygon: 'api.polygonscan.com', - arbitrum: 'api.arbiscan.io', - base: 'api.basescan.org', - optimism: 'api-optimistic.etherscan.io', - mantle: 'api.mantlescan.xyz', - 'ronin': 'explorer-kintsugi.roninchain.com/v2/2020', - scroll: 'api.scrollscan.com' - }[network]; + // let host = { + // rinkeby: 'api-rinkeby.etherscan.io', + // ropsten: 'api-ropsten.etherscan.io', + // sepolia: 'api-sepolia.etherscan.io', + // mainnet: 'api.etherscan.io', + // fuji: 'api-testnet.snowtrace.io', + // avalanche: 'api.snowtrace.io', + // polygon: 'api.polygonscan.com', + // arbitrum: 'api.arbiscan.io', + // base: 'api.basescan.org', + // optimism: 'api-optimistic.etherscan.io', + // mantle: 'api.mantlescan.xyz', + // 'ronin': 'explorer-kintsugi.roninchain.com/v2/2020', + // scroll: 'api.scrollscan.com' + // }[network]; - if (!host) { + // if (!host) { + // throw new Error(`Unknown etherscan API host for network ${network}`); + // } + + const chainId = networkConfigs.find(config => config.network.toLowerCase() === network.toLowerCase())?.chainId; + + if (!chainId) { throw new Error(`Unknown etherscan API host for network ${network}`); } - return `https://${host}/api`; + if (network === 'avalanche') { + return `https://api.snowtrace.io/api`; + } else if (network === 'fuji') { + return `https://api-testnet.snowtrace.io/api`; + } + + return `https://api.etherscan.io/v2/api?chainid=${chainId}`; } export function getEtherscanUrl(network: string): string { @@ -43,6 +57,7 @@ export function getEtherscanUrl(network: string): string { base: 'basescan.org', optimism: 'optimistic.etherscan.io', mantle: 'mantlescan.xyz', + linea: 'lineascan.build', 'ronin': 'explorer-kintsugi.roninchain.com/v2/2020', scroll: 'scrollscan.com' }[network]; @@ -62,12 +77,13 @@ export function getEtherscanApiKey(network: string): string { mainnet: process.env.ETHERSCAN_KEY, fuji: process.env.SNOWTRACE_KEY, avalanche: process.env.SNOWTRACE_KEY, - polygon: process.env.POLYGONSCAN_KEY, - arbitrum: process.env.ARBISCAN_KEY, - base: process.env.BASESCAN_KEY, - optimism: process.env.OPTIMISMSCAN_KEY, - mantle: process.env.MANTLESCAN_KEY, - scroll: process.env.SCROLLSCAN_KEY + polygon: process.env.ETHERSCAN_KEY, + arbitrum: process.env.ETHERSCAN_KEY, + base: process.env.ETHERSCAN_KEY, + optimism: process.env.ETHERSCAN_KEY, + mantle: process.env.ETHERSCAN_KEY, + scroll: process.env.ETHERSCAN_KEY, + linea: process.env.ETHERSCAN_KEY, }[network]; if (!apiKey) { diff --git a/plugins/import/import.ts b/plugins/import/import.ts index cffce451a..925c0a9f7 100644 --- a/plugins/import/import.ts +++ b/plugins/import/import.ts @@ -256,8 +256,13 @@ async function getEtherscanApiData(network: string, address: string, apiKey: str let s = (result.result[0]); + // check if this is a contract and not a wallet + if (!s.SourceCode || !s.ABI || !s.ContractName) { + throw new Error(`No source code found for address ${address} on network ${network}.`); + } + if (s.ABI === 'Contract source code not verified') { - throw new Error('Contract source code not verified'); + throw new Error(`Contract source code not verified for address ${address} on network ${network}.`); } return { @@ -278,8 +283,8 @@ async function scrapeContractCreationCodeFromEtherscanApi(network: string, addre address, apikey: getEtherscanApiKey(network) }; - const url = `${getEtherscanApiUrl(network)}?${paramString(params)}`; - const debugUrl = `${getEtherscanApiUrl(network)}?${paramString({ ...params, ...{ apikey: '[API_KEY]' } })}`; + const url = `${getEtherscanApiUrl(network)}&${paramString(params)}`; + const debugUrl = `${getEtherscanApiUrl(network)}&${paramString({ ...params, ...{ apikey: '[API_KEY]' } })}`; debug(`Attempting to pull Contract Creation code from API at ${debugUrl}`); const result = await get(url, {}); @@ -328,8 +333,8 @@ async function pullFirstTransactionForContractFromEtherscan(network: string, add sort: 'asc', apikey: getEtherscanApiKey(network) }; - const url = `${getEtherscanApiUrl(network)}?${paramString(params)}`; - const debugUrl = `${getEtherscanApiUrl(network)}?${paramString({ ...params, ...{ apikey: '[API_KEY]' } })}`; + const url = `${getEtherscanApiUrl(network)}&${paramString(params)}`; + const debugUrl = `${getEtherscanApiUrl(network)}&${paramString({ ...params, ...{ apikey: '[API_KEY]' } })}`; debug(`Attempting to pull Contract Creation code from first tx at ${debugUrl}`); const result = await get(url, {}); diff --git a/plugins/scenario/utils/TokenSourcer.ts b/plugins/scenario/utils/TokenSourcer.ts index cf3a5852a..bb0328fee 100644 --- a/plugins/scenario/utils/TokenSourcer.ts +++ b/plugins/scenario/utils/TokenSourcer.ts @@ -12,6 +12,7 @@ interface SourceTokenParameters { asset: string; address: string; blacklist: string[]; + blockNumber?: number; } export async function fetchQuery( @@ -55,6 +56,7 @@ export async function sourceTokens({ asset, address, blacklist, + blockNumber, }: SourceTokenParameters) { let amount = BigNumber.from(amount_); if (amount.isZero()) { @@ -62,7 +64,7 @@ export async function sourceTokens({ } else if (amount.isNegative()) { await removeTokens(dm, amount.abs(), asset, address); } else { - await addTokens(dm, amount, asset, address, [address].concat(blacklist)); + await addTokens(dm, amount, asset, address, [address].concat(blacklist), blockNumber); } } diff --git a/plugins/scenario/utils/hreForBase.ts b/plugins/scenario/utils/hreForBase.ts index 0446a7463..03665c3d4 100644 --- a/plugins/scenario/utils/hreForBase.ts +++ b/plugins/scenario/utils/hreForBase.ts @@ -64,6 +64,8 @@ export async function nonForkedHreForBase(base: ForkSpec): Promise scenario( 'Comet#bulker > (non-WETH base) all non-reward actions in one txn for single asset', { - filter: async (ctx) => await isBulkerSupported(ctx) && (!matchesDeployment(ctx, [{ deployment: 'weth' }, { deployment: 'wsteth' }, { network: 'ronin', deployment: 'wron'}])), + filter: async (ctx) => await isBulkerSupported(ctx) && matchesDeployment(ctx, [{ network: 'ronin', deployment: 'wron'}]), supplyCaps: async (ctx) => ( { $asset0: getConfigForScenario(ctx).bulkerAsset, - $asset1: getConfigForScenario(ctx).bulkerAsset1, } ), tokenBalances: async (ctx) => ( @@ -34,7 +33,6 @@ scenario( albert: { $base: '== 0', $asset0: getConfigForScenario(ctx).bulkerAsset, - $asset1: getConfigForScenario(ctx).bulkerAsset1 }, $comet: { $base: getConfigForScenario(ctx).bulkerComet }, } @@ -291,11 +289,10 @@ scenario( scenario( 'Comet#bulker > (non-WETH base) all actions in one txn for single asset', { - filter: async (ctx) => await isBulkerSupported(ctx) && await isRewardSupported(ctx) && (!matchesDeployment(ctx, [{ deployment: 'weth' }, { deployment: 'wsteth' }, { network: 'ronin', deployment: 'wron'}])), + filter: async (ctx) => await isBulkerSupported(ctx) && await isRewardSupported(ctx) && matchesDeployment(ctx, [{ network: 'ronin', deployment: 'wron'}]), supplyCaps: async (ctx) => ( { $asset0: getConfigForScenario(ctx).bulkerAsset, - $asset1: getConfigForScenario(ctx).bulkerAsset1, } ), tokenBalances: async (ctx) => ( @@ -303,7 +300,6 @@ scenario( albert: { $base: `== ${getConfigForScenario(ctx).bulkerBase}`, $asset0: getConfigForScenario(ctx).bulkerAsset, - $asset1: getConfigForScenario(ctx).bulkerAsset1 }, $comet: { $base: getConfigForScenario(ctx).bulkerComet }, } @@ -513,7 +509,7 @@ scenario( scenario( 'Comet#bulker > (wstETH base) all actions in one txn', { - filter: async (ctx) => await isBulkerSupported(ctx) && await isRewardSupported(ctx) && !matchesDeployment(ctx, [{ deployment: 'wsteth' }]), + filter: async (ctx) => await isBulkerSupported(ctx) && await isRewardSupported(ctx) && matchesDeployment(ctx, [{ deployment: 'wsteth' }]), supplyCaps: async (ctx) => ( { $asset0: getConfigForScenario(ctx).bulkerAsset, diff --git a/scenario/LiquidationScenario.ts b/scenario/LiquidationScenario.ts index 6eae1af10..0bce55b74 100644 --- a/scenario/LiquidationScenario.ts +++ b/scenario/LiquidationScenario.ts @@ -31,7 +31,7 @@ scenario( }) ); - await betty.withdrawAsset({ asset: baseToken, amount: 1000n * baseScale.toBigInt() }); // force accrue + await betty.withdrawAsset({ asset: baseToken, amount: BigInt(getConfigForScenario(context).liquidationBase) / 100n * baseScale.toBigInt() }); // force accrue expect(await comet.isLiquidatable(albert.address)).to.be.true; } diff --git a/scenario/SupplyScenario.ts b/scenario/SupplyScenario.ts index b0892897d..dac9eae66 100644 --- a/scenario/SupplyScenario.ts +++ b/scenario/SupplyScenario.ts @@ -15,7 +15,7 @@ async function testSupplyCollateral(context: CometContext, assetNum: number): Pr const { asset: assetAddress, scale: scaleBN, supplyCap } = await comet.getAssetInfo(assetNum); const collateralAsset = context.getAssetByAddress(assetAddress); const scale = scaleBN.toBigInt(); - const toSupply = 100n * scale; + const toSupply = BigInt(getConfigForScenario(context).supplyCollateral) * scale; expect(await collateralAsset.balanceOf(albert.address)).to.be.equal(toSupply); @@ -26,7 +26,7 @@ async function testSupplyCollateral(context: CometContext, assetNum: number): Pr await expectRevertCustom( albert.supplyAsset({ asset: collateralAsset.address, - amount: 100n * scale, + amount: BigInt(getConfigForScenario(context).supplyCollateral) * scale, }), 'SupplyCapExceeded()' ); @@ -46,7 +46,7 @@ async function testSupplyFromCollateral(context: CometContext, assetNum: number) const { asset: assetAddress, scale: scaleBN, supplyCap } = await comet.getAssetInfo(assetNum); const collateralAsset = context.getAssetByAddress(assetAddress); const scale = scaleBN.toBigInt(); - const toSupply = 100n * scale; + const toSupply = BigInt(getConfigForScenario(context).supplyCollateral) * scale; expect(await collateralAsset.balanceOf(albert.address)).to.be.equal(toSupply); expect(await comet.collateralBalanceOf(betty.address, collateralAsset.address)).to.be.equal(0n); @@ -85,9 +85,11 @@ for (let i = 0; i < MAX_ASSETS; i++) { // hypothetical assets added during the migration/proposal constraint because those assets don't exist // yet filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, amountToSupply), - tokenBalances: { - albert: { [`$asset${i}`]: amountToSupply }, - }, + tokenBalances: async (ctx) => ( + { + albert: { [`$asset${i}`]: getConfigForScenario(ctx).supplyCollateral } + } + ), }, async (_properties, context) => { return await testSupplyCollateral(context, i); @@ -101,9 +103,11 @@ for (let i = 0; i < MAX_ASSETS; i++) { `Comet#supplyFrom > collateral asset ${i}`, { filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, amountToSupply), - tokenBalances: { - albert: { [`$asset${i}`]: amountToSupply }, - }, + tokenBalances: async (ctx) => ( + { + albert: { [`$asset${i}`]: getConfigForScenario(ctx).supplyCollateral } + } + ), }, async (_properties, context) => { return await testSupplyFromCollateral(context, i); diff --git a/scenario/TransferScenario.ts b/scenario/TransferScenario.ts index 636eae4cb..028ee93ad 100644 --- a/scenario/TransferScenario.ts +++ b/scenario/TransferScenario.ts @@ -11,11 +11,11 @@ async function testTransferCollateral(context: CometContext, assetNum: number): const collateralAsset = context.getAssetByAddress(assetAddress); // Albert transfers 50 units of collateral to Betty - const toTransfer = scale.toBigInt() * 50n; + const toTransfer = scale.toBigInt() * BigInt(getConfigForScenario(context).supplyCollateral) / 2n; const txn = await albert.transferAsset({ dst: betty.address, asset: collateralAsset.address, amount: toTransfer }); - expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(scale.mul(50)); - expect(await comet.collateralBalanceOf(betty.address, collateralAsset.address)).to.be.equal(scale.mul(50)); + expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(scale.mul(BigInt(getConfigForScenario(context).supplyCollateral) / 2n)); + expect(await comet.collateralBalanceOf(betty.address, collateralAsset.address)).to.be.equal(scale.mul(BigInt(getConfigForScenario(context).supplyCollateral) / 2n)); return txn; // return txn to measure gas } @@ -29,11 +29,11 @@ async function testTransferFromCollateral(context: CometContext, assetNum: numbe await albert.allow(charles, true); // Charles transfers 50 units of collateral from Albert to Betty - const toTransfer = scale.toBigInt() * 50n; + const toTransfer = scale.toBigInt() * BigInt(getConfigForScenario(context).supplyCollateral) / 2n; const txn = await charles.transferAssetFrom({ src: albert.address, dst: betty.address, asset: collateralAsset.address, amount: toTransfer }); - expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(scale.mul(50)); - expect(await comet.collateralBalanceOf(betty.address, collateralAsset.address)).to.be.equal(scale.mul(50)); + expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(scale.mul(BigInt(getConfigForScenario(context).supplyCollateral) / 2n)); + expect(await comet.collateralBalanceOf(betty.address, collateralAsset.address)).to.be.equal(scale.mul(BigInt(getConfigForScenario(context).supplyCollateral) / 2n)); return txn; // return txn to measure gas } @@ -44,9 +44,11 @@ for (let i = 0; i < MAX_ASSETS; i++) { `Comet#transfer > collateral asset ${i}, enough balance`, { filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, amountToTransfer), - cometBalances: { - albert: { [`$asset${i}`]: amountToTransfer }, - }, + cometBalances: async (ctx) => ( + { + albert: { [`$asset${i}`]: getConfigForScenario(ctx).transferCollateral } + } + ), }, async (_properties, context) => { return await testTransferCollateral(context, i); @@ -60,9 +62,11 @@ for (let i = 0; i < MAX_ASSETS; i++) { `Comet#transferFrom > collateral asset ${i}, enough balance`, { filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, amountToTransfer), - cometBalances: { - albert: { [`$asset${i}`]: amountToTransfer }, - }, + cometBalances: async (ctx) => ( + { + albert: { [`$asset${i}`]: getConfigForScenario(ctx).transferCollateral } + } + ), }, async (_properties, context) => { return await testTransferFromCollateral(context, i); diff --git a/scenario/WithdrawScenario.ts b/scenario/WithdrawScenario.ts index d304557bc..e6ee2f8d5 100644 --- a/scenario/WithdrawScenario.ts +++ b/scenario/WithdrawScenario.ts @@ -12,12 +12,12 @@ async function testWithdrawCollateral(context: CometContext, assetNum: number): const scale = scaleBN.toBigInt(); expect(await collateralAsset.balanceOf(albert.address)).to.be.equal(0n); - expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(100n * scale); + expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(BigInt(getConfigForScenario(context).supplyCollateral) * scale); // Albert withdraws 100 units of collateral from Comet - const txn = await albert.withdrawAsset({ asset: collateralAsset.address, amount: 100n * scale }); + const txn = await albert.withdrawAsset({ asset: collateralAsset.address, amount: BigInt(getConfigForScenario(context).supplyCollateral) * scale }); - expect(await collateralAsset.balanceOf(albert.address)).to.be.equal(100n * scale); + expect(await collateralAsset.balanceOf(albert.address)).to.be.equal(BigInt(getConfigForScenario(context).supplyCollateral) * scale); expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(0n); return txn; // return txn to measure gas @@ -31,14 +31,14 @@ async function testWithdrawFromCollateral(context: CometContext, assetNum: numbe const scale = scaleBN.toBigInt(); expect(await collateralAsset.balanceOf(betty.address)).to.be.equal(0n); - expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(100n * scale); + expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(BigInt(getConfigForScenario(context).supplyCollateral) * scale); await albert.allow(betty, true); // Betty withdraws 1000 units of collateral from Albert - const txn = await betty.withdrawAssetFrom({ src: albert.address, dst: betty.address, asset: collateralAsset.address, amount: 100n * scale }); + const txn = await betty.withdrawAssetFrom({ src: albert.address, dst: betty.address, asset: collateralAsset.address, amount: BigInt(getConfigForScenario(context).supplyCollateral) * scale }); - expect(await collateralAsset.balanceOf(betty.address)).to.be.equal(100n * scale); + expect(await collateralAsset.balanceOf(betty.address)).to.be.equal(BigInt(getConfigForScenario(context).supplyCollateral) * scale); expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(0n); return txn; // return txn to measure gas @@ -50,9 +50,11 @@ for (let i = 0; i < MAX_ASSETS; i++) { `Comet#withdraw > collateral asset ${i}`, { filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, amountToWithdraw), - cometBalances: { - albert: { [`$asset${i}`]: amountToWithdraw }, - }, + cometBalances: async (ctx) => ( + { + albert: { [`$asset${i}`]: getConfigForScenario(ctx).withdrawCollateral } + } + ), }, async (_properties, context) => { return await testWithdrawCollateral(context, i); @@ -66,9 +68,11 @@ for (let i = 0; i < MAX_ASSETS; i++) { `Comet#withdrawFrom > collateral asset ${i}`, { filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, amountToWithdraw), - cometBalances: { - albert: { [`$asset${i}`]: amountToWithdraw }, - }, + cometBalances: async (ctx) => ( + { + albert: { [`$asset${i}`]: getConfigForScenario(ctx).withdrawCollateral } + } + ), }, async (_properties, context) => { return await testWithdrawFromCollateral(context, i); diff --git a/scenario/constraints/MigrationConstraint.ts b/scenario/constraints/MigrationConstraint.ts index a0c2b16a2..41ecb1b16 100644 --- a/scenario/constraints/MigrationConstraint.ts +++ b/scenario/constraints/MigrationConstraint.ts @@ -1,7 +1,7 @@ import { StaticConstraint, Solution, World, debug } from '../../plugins/scenario'; import { CometContext, MigrationData } from '../context/CometContext'; import { Migration, loadMigrations, Actions } from '../../plugins/deployment_manager/Migration'; -import { modifiedPaths, subsets } from '../utils'; +import { modifiedPaths } from '../utils'; import { DeploymentManager } from '../../plugins/deployment_manager'; import { impersonateAddress } from '../../plugins/scenario/utils'; import { exp } from '../../test/helpers'; @@ -22,7 +22,7 @@ export class MigrationConstraint implements StaticConstr async solve(world: World) { const label = `[${world.base.name}] {MigrationConstraint}`; const solutions: Solution[] = []; - const migrationPaths = [...subsets(await getMigrations(world))]; + const migrationPaths = [await getMigrations(world)]; for (const migrationList of migrationPaths) { if (migrationList.length == 0 && migrationPaths.length > 1) { diff --git a/scenario/utils/hreUtils.ts b/scenario/utils/hreUtils.ts index 59932cc82..9c81f6934 100644 --- a/scenario/utils/hreUtils.ts +++ b/scenario/utils/hreUtils.ts @@ -5,7 +5,9 @@ export async function setNextBaseFeeToZero(dm: DeploymentManager) { } export async function mineBlocks(dm: DeploymentManager, blocks: number) { - await dm.hre.network.provider.send('hardhat_mine', [`0x${blocks.toString(16)}`]); + const hex = `0x${blocks.toString(16)}`; + + await dm.hre.network.provider.send('hardhat_mine', [hex]); } export async function setNextBlockTimestamp(dm: DeploymentManager, timestamp: number) { diff --git a/scenario/utils/index.ts b/scenario/utils/index.ts index a9578f724..2d5e8e861 100644 --- a/scenario/utils/index.ts +++ b/scenario/utils/index.ts @@ -1,6 +1,16 @@ import { expect } from 'chai'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; -import { BigNumber, BigNumberish, Contract, ContractReceipt, ContractTransaction, Event, EventFilter, constants, utils } from 'ethers'; +import { + BigNumber, + BigNumberish, + Contract, + ContractReceipt, + ContractTransaction, + Event, + EventFilter, + constants, + utils, +} from 'ethers'; import { execSync } from 'child_process'; import { existsSync } from 'fs'; import { CometContext } from '../context/CometContext'; @@ -12,12 +22,19 @@ import { ProposalState, OpenProposal } from '../context/Gov'; import { debug } from '../../plugins/deployment_manager/Utils'; import { COMP_WHALES } from '../../src/deploy'; import relayMessage from './relayMessage'; -import { mineBlocks, setNextBaseFeeToZero, setNextBlockTimestamp } from './hreUtils'; +import { + mineBlocks, + setNextBaseFeeToZero, + setNextBlockTimestamp, +} from './hreUtils'; import { BaseBridgeReceiver, CometInterface } from '../../build/types'; import CometActor from './../context/CometActor'; import { isBridgeProposal } from './isBridgeProposal'; - +import { Interface } from 'ethers/lib/utils'; +import axios from 'axios'; export { mineBlocks, setNextBaseFeeToZero, setNextBlockTimestamp }; +import { readFileSync } from 'fs'; +import path from 'path'; export const MAX_ASSETS = 24; export const UINT256_MAX = 2n ** 256n - 1n; @@ -32,49 +49,74 @@ export enum ComparisonOp { GT, LTE, LT, - EQ + EQ, } -export const max = (...args) => args.reduce((m, e) => e > m ? e : m); -export const min = (...args) => args.reduce((m, e) => e < m ? e : m); +export const max = (...args) => args.reduce((m, e) => (e > m ? e : m)); +export const min = (...args) => args.reduce((m, e) => (e < m ? e : m)); export function abs(x: bigint): bigint { return x < 0n ? -x : x; } -export function expectApproximately(expected: bigint, actual: bigint, precision = 0n) { - expect(BigNumber.from(abs(expected - actual))).to.be.lte(BigNumber.from(precision)); +export function expectApproximately( + expected: bigint, + actual: bigint, + precision = 0n +) { + expect(BigNumber.from(abs(expected - actual))).to.be.lte( + BigNumber.from(precision) + ); } export function expectBase(expected: bigint, actual: bigint, precision = 2n) { expectApproximately(expected, actual, precision); } -export function expectRevertCustom(tx: Promise, custom: string) { +export function expectRevertCustom( + tx: Promise, + custom: string +) { return tx - .then(_ => { throw new Error('Expected transaction to be reverted'); }) - .catch(e => { - const selector = utils.keccak256(custom.split('').reduce((a, s) => a + s.charCodeAt(0).toString(16), '0x')).slice(2, 2 + 8); + .then((_) => { + throw new Error('Expected transaction to be reverted'); + }) + .catch((e) => { + const selector = utils + .keccak256( + custom + .split('') + .reduce((a, s) => a + s.charCodeAt(0).toString(16), '0x') + ) + .slice(2, 2 + 8); const patterns = [ new RegExp(`custom error '${custom.replace(/[()]/g, '\\$&')}'`), new RegExp(`unrecognized custom error with selector ${selector}`), - new RegExp(`unrecognized custom error \\(return data: 0x${selector}\\)`) + new RegExp( + `unrecognized custom error \\(return data: 0x${selector}\\)` + ), ]; for (const pattern of patterns) - if (pattern.test(e.message) || pattern.test(e.reason)) - return; - throw new Error(`Expected revert message in one of [${patterns}], but reverted with: ${e.message}`); + if (pattern.test(e.message) || pattern.test(e.reason)) return; + throw new Error( + `Expected revert message in one of [${patterns}], but reverted with: ${e.message}` + ); }); } -export function expectRevertMatches(tx: Promise, patterns: RegExp[]) { +export function expectRevertMatches( + tx: Promise, + patterns: RegExp[] +) { return tx - .then(_ => { throw new Error('Expected transaction to be reverted'); }) - .catch(e => { - for (const pattern of patterns) - if (pattern.test(e.message)) - return; - throw new Error(`Expected revert message in one of ${patterns}, but reverted with: ${e.message}`); + .then((_) => { + throw new Error('Expected transaction to be reverted'); + }) + .catch((e) => { + for (const pattern of patterns) if (pattern.test(e.message)) return; + throw new Error( + `Expected revert message in one of ${patterns}, but reverted with: ${e.message}` + ); }); } @@ -133,22 +175,29 @@ export function* subsets(array: T[], offset = 0): Generator { yield []; } -export function getExpectedBaseBalance(balance: bigint, baseIndexScale: bigint, borrowOrSupplyIndex: bigint): bigint { - const principalValue = balance * baseIndexScale / borrowOrSupplyIndex; - const baseBalanceOf = principalValue * borrowOrSupplyIndex / baseIndexScale; +export function getExpectedBaseBalance( + balance: bigint, + baseIndexScale: bigint, + borrowOrSupplyIndex: bigint +): bigint { + const principalValue = (balance * baseIndexScale) / borrowOrSupplyIndex; + const baseBalanceOf = (principalValue * borrowOrSupplyIndex) / baseIndexScale; return baseBalanceOf; } export function getInterest(balance: bigint, rate: bigint, seconds: bigint) { - return balance * rate * seconds / (10n ** 18n); + return (balance * rate * seconds) / 10n ** 18n; } -export async function getActorAddressFromName(name: string, context: CometContext): Promise { +export async function getActorAddressFromName( + name: string, + context: CometContext +): Promise { if (name.startsWith('$')) { const cometRegex = /comet/; let actorAddress: string; if (cometRegex.test(name)) { - // If name matches regex, e.g. "$comet" + // If name matches regex, e.g. '$comet' actorAddress = (await context.getComet()).address; } else { throw new Error(`Invalid actor name: ${name}`); @@ -159,18 +208,21 @@ export async function getActorAddressFromName(name: string, context: CometContex } } -export async function getAssetFromName(name: string, context: CometContext): Promise { +export async function getAssetFromName( + name: string, + context: CometContext +): Promise { let comet = await context.getComet(); // TODO: can optimize by taking this as an arg instead if (name.startsWith('$')) { const collateralAssetRegex = /asset[0-9]+/; const baseAssetRegex = /base/; let asset: string; if (collateralAssetRegex.test(name)) { - // If name matches regex, e.g. "$asset10" + // If name matches regex, e.g. '$asset10' const assetIndex = name.match(/[0-9]+/g)![0]; ({ asset } = await comet.getAssetInfo(assetIndex)); } else if (baseAssetRegex.test(name)) { - // If name matches "base" + // If name matches 'base' asset = await comet.baseToken(); } else { throw new Error(`Invalid asset name: ${name}`); @@ -183,7 +235,11 @@ export async function getAssetFromName(name: string, context: CometContext): Pro } // Returns the amount that needs to be transferred to satisfy a constraint -export function getToTransferAmount(amount: ComparativeAmount, existingBalance: bigint, decimals: number): bigint { +export function getToTransferAmount( + amount: ComparativeAmount, + existingBalance: bigint, + decimals: number +): bigint { let toTransfer = 0n; switch (amount.op) { case ComparisonOp.EQ: @@ -213,16 +269,20 @@ export function getToTransferAmount(amount: ComparativeAmount, existingBalance: export function parseAmount(amount): ComparativeAmount { switch (typeof amount) { case 'bigint': - return amount >= 0n ? { val: Number(amount), op: ComparisonOp.GTE } : { val: Number(amount), op: ComparisonOp.LTE }; + return amount >= 0n + ? { val: Number(amount), op: ComparisonOp.GTE } + : { val: Number(amount), op: ComparisonOp.LTE }; case 'number': - return amount >= 0 ? { val: amount, op: ComparisonOp.GTE } : { val: amount, op: ComparisonOp.LTE }; + return amount >= 0 + ? { val: amount, op: ComparisonOp.GTE } + : { val: amount, op: ComparisonOp.LTE }; case 'string': return matchGroup(amount, { - 'GTE': />=\s*(-?\d+)/, - 'GT': />\s*(-?\d+)/, - 'LTE': /<=\s*(-?\d+)/, - 'LT': /<\s*(-?\d+)/, - 'EQ': /==\s*(-?\d+)/, + GTE: />=\s*(-?\d+)/, + GT: />\s*(-?\d+)/, + LTE: /<=\s*(-?\d+)/, + LT: /<\s*(-?\d+)/, + EQ: /==\s*(-?\d+)/, }); case 'object': return amount; @@ -239,19 +299,34 @@ function matchGroup(str, patterns): ComparativeAmount { throw new Error(`No match for ${str} in ${patterns}`); } -export async function modifiedPaths(pattern: RegExp, against: string = 'origin/main'): Promise { - const output = execSync(`git diff --numstat $(git merge-base ${against} HEAD)`); - const paths = output.toString().split('\n').map(l => l.split(/\s+/)[2]); - const modified = paths.filter(p => pattern.test(p) && existsSync(p)); +export async function modifiedPaths( + pattern: RegExp, + against: string = 'origin/main' +): Promise { + const output = execSync( + `git diff --numstat $(git merge-base ${against} HEAD)` + ); + const paths = output + .toString() + .split('\n') + .map((l) => l.split(/\s+/)[2]); + const modified = paths.filter((p) => pattern.test(p) && existsSync(p)); return modified; } -export async function isValidAssetIndex(ctx: CometContext, assetNum: number): Promise { +export async function isValidAssetIndex( + ctx: CometContext, + assetNum: number +): Promise { const comet = await ctx.getComet(); - return assetNum < await comet.numAssets(); + return assetNum < (await comet.numAssets()); } -export async function isTriviallySourceable(ctx: CometContext, assetNum: number, amount: number): Promise { +export async function isTriviallySourceable( + ctx: CometContext, + assetNum: number, + amount: number +): Promise { const fauceteer = await ctx.getFauceteer(); // If fauceteer does not exist (e.g. mainnet), then token is likely sourceable from events if (fauceteer == null) return true; @@ -261,7 +336,7 @@ export async function isTriviallySourceable(ctx: CometContext, assetNum: number, const asset = ctx.getAssetByAddress(assetInfo.asset); const amountInWei = BigInt(amount) * assetInfo.scale.toBigInt(); // Fauceteer should have greater than the expected amount of the asset - return await asset.balanceOf(fauceteer.address) > amountInWei; + return (await asset.balanceOf(fauceteer.address)) > amountInWei; } export async function isBulkerSupported(ctx: CometContext): Promise { @@ -269,7 +344,9 @@ export async function isBulkerSupported(ctx: CometContext): Promise { return bulker == null ? false : true; } -export async function hasMinBorrowGreaterThanOne(ctx: CometContext): Promise { +export async function hasMinBorrowGreaterThanOne( + ctx: CometContext +): Promise { const comet = await ctx.getComet(); const minBorrow = (await comet.baseBorrowMin()).toBigInt(); return minBorrow > 1n; @@ -278,12 +355,15 @@ export async function hasMinBorrowGreaterThanOne(ctx: CometContext): Promise BLOCK_SPAN) { const midBlock = fromBlock + BLOCK_SPAN; const logs = await contract.queryFilter(filter, fromBlock, midBlock); - return logs.concat(await fetchLogs(contract, filter, midBlock + 1, toBlock)); + return logs.concat( + await fetchLogs(contract, filter, midBlock + 1, toBlock) + ); } else { return contract.queryFilter(filter, fromBlock, toBlock); } @@ -343,22 +425,32 @@ async function redeployRenzoOracle(dm: DeploymentManager) { dm.hre.ethers.provider ); - const admin = await impersonateAddress(dm, '0xD1e6626310fD54Eceb5b9a51dA2eC329D6D4B68A'); + const admin = await impersonateAddress( + dm, + '0xD1e6626310fD54Eceb5b9a51dA2eC329D6D4B68A' + ); // set balance await dm.hre.ethers.provider.send('hardhat_setBalance', [ admin.address, - dm.hre.ethers.utils.hexStripZeros(dm.hre.ethers.utils.parseUnits('100', 'ether').toHexString()), + dm.hre.ethers.utils.hexStripZeros( + dm.hre.ethers.utils.parseUnits('100', 'ether').toHexString() + ), ]); const newOracle = await dm.deploy( 'renzo:Oracle', 'test/MockRenzoOracle.sol', [ - '0x86392dC19c0b719886221c78AB11eb8Cf5c52812', // stETH / ETH oracle address + '0x86392dC19c0b719886221c78AB11eb8Cf5c52812', // stETH / ETH oracle address ] ); - await renzoOracle.connect(admin).setOracleAddress('0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84', newOracle.address); + await renzoOracle + .connect(admin) + .setOracleAddress( + '0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84', + newOracle.address + ); } } @@ -367,9 +459,7 @@ const tokens = new Map([ ['LINK', '0x514910771AF9Ca656af840dff83E8264EcF986CA'], ]); -const dest = new Map([ - ['ronin', '6916147374840168594'], -]); +const dest = new Map([['ronin', '6916147374840168594']]); async function updateCCIPStats(dm: DeploymentManager) { if (dm.network === 'mainnet') { @@ -378,116 +468,116 @@ async function updateCCIPStats(dm: DeploymentManager) { const priceRegistry = '0x8c9b2Efb7c64C394119270bfecE7f54763b958Ad'; const abi = [ { - 'inputs': [ + inputs: [ { - 'components': [ + components: [ { - 'components': [ + components: [ { - 'internalType': 'address', - 'name': 'sourceToken', - 'type': 'address' + internalType: 'address', + name: 'sourceToken', + type: 'address', }, { - 'internalType': 'uint224', - 'name': 'usdPerToken', - 'type': 'uint224' - } + internalType: 'uint224', + name: 'usdPerToken', + type: 'uint224', + }, ], - 'internalType': 'struct TokenPriceUpdate[]', - 'name': 'tokenPriceUpdates', - 'type': 'tuple[]' + internalType: 'struct TokenPriceUpdate[]', + name: 'tokenPriceUpdates', + type: 'tuple[]', }, { - 'components': [ + components: [ { - 'internalType': 'uint64', - 'name': 'destChainSelector', - 'type': 'uint64' + internalType: 'uint64', + name: 'destChainSelector', + type: 'uint64', }, { - 'internalType': 'uint224', - 'name': 'usdPerUnitGas', - 'type': 'uint224' - } + internalType: 'uint224', + name: 'usdPerUnitGas', + type: 'uint224', + }, ], - 'internalType': 'struct GasPriceUpdate[]', - 'name': 'gasPriceUpdates', - 'type': 'tuple[]' - } + internalType: 'struct GasPriceUpdate[]', + name: 'gasPriceUpdates', + type: 'tuple[]', + }, ], - 'internalType': 'struct PriceUpdates', - 'name': 'priceUpdates', - 'type': 'tuple' - } + internalType: 'struct PriceUpdates', + name: 'priceUpdates', + type: 'tuple', + }, ], - 'name': 'updatePrices', - 'outputs': [], - 'stateMutability': 'nonpayable', - 'type': 'function' + name: 'updatePrices', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', }, { - 'inputs': [ + inputs: [ { - 'internalType': 'uint64', - 'name': 'destChainSelector', - 'type': 'uint64' - } + internalType: 'uint64', + name: 'destChainSelector', + type: 'uint64', + }, ], - 'name': 'getDestinationChainGasPrice', - 'outputs': [ + name: 'getDestinationChainGasPrice', + outputs: [ { - 'components': [ + components: [ { - 'internalType': 'uint224', - 'name': 'value', - 'type': 'uint224' + internalType: 'uint224', + name: 'value', + type: 'uint224', }, { - 'internalType': 'uint32', - 'name': 'timestamp', - 'type': 'uint32' - } + internalType: 'uint32', + name: 'timestamp', + type: 'uint32', + }, ], - 'internalType': 'struct TimestampedPackedUint224', - 'name': '', - 'type': 'tuple' - } + internalType: 'struct TimestampedPackedUint224', + name: '', + type: 'tuple', + }, ], - 'stateMutability': 'view', - 'type': 'function' + stateMutability: 'view', + type: 'function', }, { - 'inputs': [ + inputs: [ { - 'internalType': 'address', - 'name': 'token', - 'type': 'address' - } + internalType: 'address', + name: 'token', + type: 'address', + }, ], - 'name': 'getTokenPrice', - 'outputs': [ + name: 'getTokenPrice', + outputs: [ { - 'components': [ + components: [ { - 'internalType': 'uint224', - 'name': 'value', - 'type': 'uint224' + internalType: 'uint224', + name: 'value', + type: 'uint224', }, { - 'internalType': 'uint32', - 'name': 'timestamp', - 'type': 'uint32' - } + internalType: 'uint32', + name: 'timestamp', + type: 'uint32', + }, ], - 'internalType': 'struct TimestampedPackedUint224', - 'name': '', - 'type': 'tuple' - } + internalType: 'struct TimestampedPackedUint224', + name: '', + type: 'tuple', + }, ], - 'stateMutability': 'view', - 'type': 'function' - } + stateMutability: 'view', + type: 'function', + }, ]; await dm.hre.network.provider.request({ @@ -501,7 +591,11 @@ async function updateCCIPStats(dm: DeploymentManager) { }); const commitStoreSigner = await dm.hre.ethers.getSigner(commitStore); - const registryContract = new Contract(priceRegistry, abi, dm.hre.ethers.provider); + const registryContract = new Contract( + priceRegistry, + abi, + dm.hre.ethers.provider + ); const tokenPrices = []; const gasPrices = []; @@ -516,14 +610,15 @@ async function updateCCIPStats(dm: DeploymentManager) { const tx0 = await commitStoreSigner.sendTransaction({ to: priceRegistry, - data: registryContract.interface.encodeFunctionData('updatePrices', [{ - tokenPriceUpdates: tokenPrices, - gasPriceUpdates: gasPrices - }]), + data: registryContract.interface.encodeFunctionData('updatePrices', [ + { + tokenPriceUpdates: tokenPrices, + gasPriceUpdates: gasPrices, + }, + ]), }); await tx0.wait(); - } } @@ -544,11 +639,19 @@ const REDSTONE_FEEDS = { ], }; -async function getProxyAdmin(dm: DeploymentManager, proxyAddress: string): Promise { +async function getProxyAdmin( + dm: DeploymentManager, + proxyAddress: string +): Promise { // Retrieve the proxy admin address - const admin = await dm.hre.ethers.provider.getStorageAt(proxyAddress, '0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103'); + const admin = await dm.hre.ethers.provider.getStorageAt( + proxyAddress, + '0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103' + ); // Convert the admin address to a checksum address - const adminAddress = dm.hre.ethers.utils.getAddress('0x' + admin.substring(26)); + const adminAddress = dm.hre.ethers.utils.getAddress( + '0x' + admin.substring(26) + ); return adminAddress; } @@ -561,8 +664,7 @@ async function mockAllRedstoneOracles(dm: DeploymentManager) { for (const feed of feeds) { try { await dm.fromDep(`MockRedstoneOracle:${feed}`, dm.network, dm.deployment); - } - catch (_) { + } catch (_) { await mockRedstoneOracle(dm, feed); } } @@ -590,7 +692,9 @@ async function mockRedstoneOracle(dm: DeploymentManager, feed: string) { // set balance await dm.hre.ethers.provider.send('hardhat_setBalance', [ owner.address, - dm.hre.ethers.utils.hexStripZeros(dm.hre.ethers.utils.parseUnits('100', 'ether').toHexString()), + dm.hre.ethers.utils.hexStripZeros( + dm.hre.ethers.utils.parseUnits('100', 'ether').toHexString() + ), ]); const price = (await feedContract.latestRoundData()).answer; const newImplementation = await dm.deploy( @@ -601,22 +705,267 @@ async function mockRedstoneOracle(dm: DeploymentManager, feed: string) { await proxyAdmin.connect(owner).upgrade(feed, newImplementation.address); } -export async function voteForOpenProposal(dm: DeploymentManager, { id, startBlock, endBlock }: OpenProposal) { +export async function tenderlyExecute( + gdm: DeploymentManager, + bdm: DeploymentManager, + governor: Contract, + timelock: Contract +): Promise { + const latest = await gdm.hre.ethers.provider.getBlock('latest'); + const B0 = BigInt(latest.number); + const T0 = BigInt(latest.timestamp); + + const blockStart = B0 + 1n; + const blockEnd = blockStart + 1n; + const blockCast = blockEnd; + const blockQueue = blockCast + 1n; + const blockExec = blockQueue + 3n; + + const tsShift = (t: bigint, dBlocks: bigint) => t + dBlocks * 12n; + const timestampCast = tsShift(T0, blockCast - B0); + const timestampQueue = tsShift(T0, blockQueue - B0); + const timestampExec = tsShift(T0, blockExec - B0); + + const proposalArgs = loadCachedProposal(); + proposalArgs.pop(); + const id = BigInt(await governor.proposalCount()); + const govIF = new Interface(governor.interface.fragments); + const signer = await gdm.getSigner(); + const fromAddr = await signer.getAddress(); + + const patchTL = { '0x2': '0x' + '00'.repeat(64) }; + + const packed = (1n << 48n) | 1n; + const rawGS = gdm.hre.ethers.utils.hexZeroPad( + gdm.hre.ethers.BigNumber.from(packed).toHexString(), + 32 + ); + const keyGS = + '0x00d7616c8fe29c6c2fbe1d0c5bc8f2faa4c35b43746e70b24b4d532752affd01'; + + const basePLQ = BigInt( + '0x042f525fd47e44d02e065dd7bb464f47b4f926fbd05b5e087891ebd756adf100' + ); + const slotVoteExt = '0x' + basePLQ.toString(16).padStart(64, '0'); + const slotMapRoot = '0x' + (basePLQ + 1n).toString(16).padStart(64, '0'); + const slotExtDead = gdm.hre.ethers.utils.keccak256( + gdm.hre.ethers.utils.defaultAbiCoder.encode( + ['uint256', 'bytes32'], + [id, slotMapRoot] + ) + ); + + const patchGov = { + [keyGS]: rawGS, + [slotVoteExt]: '0x' + '00'.repeat(64), + [slotExtDead]: '0x' + '00'.repeat(64), + }; + + const statePatch = { + [timelock.address]: { storage: patchTL }, + [governor.address]: { storage: patchGov }, + }; + + const whales = + gdm.network === 'mainnet' ? COMP_WHALES.mainnet : COMP_WHALES.testnet; + + const deployBytecodes = loadCachedBytecodes(); + const chainId1 = gdm.hre.ethers.provider.network.chainId; + + const simsL1 = [ + ...deployBytecodes.map((code) => ({ + network_id: chainId1, + from: fromAddr, + to: '', + block_number: Number(B0), + block_header: { timestamp: gdm.hre.ethers.utils.hexlify(T0) }, + input: gdm.hre.ethers.utils.hexlify(code), + state_objects: statePatch, + save: true, + gas_price: 0, + })), + { + network_id: chainId1.toString(), + from: fromAddr, + to: governor.address, + block_number: Number(B0), + block_header: { timestamp: gdm.hre.ethers.utils.hexlify(T0) }, + input: govIF.encodeFunctionData('propose', proposalArgs), + state_objects: statePatch, + save: true, + gas_price: 0, + }, + ...whales.map((w) => ({ + network_id: chainId1.toString(), + from: w, + to: governor.address, + block_number: Number(blockCast), + block_header: { timestamp: gdm.hre.ethers.utils.hexlify(timestampCast) }, + input: govIF.encodeFunctionData('castVote', [id, 1]), + state_objects: statePatch, + save: true, + save_if_fails: true, + gas_price: 0, + })), + { + network_id: chainId1.toString(), + from: fromAddr, + to: governor.address, + block_number: Number(blockQueue), + block_header: { timestamp: gdm.hre.ethers.utils.hexlify(timestampQueue) }, + input: govIF.encodeFunctionData('queue', [id]), + state_objects: statePatch, + save: true, + save_if_fails: true, + gas_price: 0, + }, + { + network_id: chainId1.toString(), + from: fromAddr, + to: governor.address, + block_number: Number(blockExec), + block_header: { timestamp: gdm.hre.ethers.utils.hexlify(timestampExec) }, + input: govIF.encodeFunctionData('execute', [id]), + state_objects: statePatch, + save: true, + save_if_fails: true, + gas_price: 0, + }, + ]; + + const chainId2 = bdm.hre.ethers.provider.network.chainId; + + + console.log(`\n========================== TENDERLY ==========================\n`); + + console.log(`\nExecuting Tenderly simulation for proposal ${id}...`); + const bundle = await simulateBundle(gdm, simsL1, Number(B0)); + console.log(`Tenderly simulation bundle size: ${bundle.length}`); + await shareSimulation(gdm, bundle[bundle.length - 1].simulation.id); + + const exec1 = bundle[bundle.length - 1].simulation; + + console.log(` >>> PROPOSAL EXECUTED ${id} \n`); + console.log(`Simulation ${exec1.id} done, status: ${exec1.status}`); + console.log(`Link: https://www.tdly.co/shared/simulation/${exec1.id}`); + let proposals; + if (chainId1 !== chainId2) { + proposals = await relayMessage(gdm, bdm, parseFloat(B0.toString()), bundle[bundle.length - 1].transaction.transaction_info.logs); + + debug(`Proposals relayed: ${proposals.length}`); + const timelockL2 = await bdm.getContractOrThrow('timelock'); + const delay = await timelockL2.delay(); + const relayMessages = loadCachedRelayMessages(); + const latestL2 = await bdm.hre.ethers.provider.getBlock('latest'); + const maxEta = Math.max(...proposals.map(p => Number(p.eta || 0))) + delay.toNumber(); + const T0L2 = BigInt(Math.max(latestL2.timestamp, maxEta + 1)); + const B0L2 = Number(latestL2.number) + 1; + const simsL2 = relayMessages.map((msg, i, arr) => { + const isLast = i === arr.length - 1; + + const timestamp = isLast + ? Number(T0L2) + : latestL2.timestamp; + + const block = isLast + ? B0L2 : latestL2.number; + + return { + network_id: chainId2.toString(), + from: msg.signer, + to: msg.messanger, + block_number: Number(block), + block_header: { + timestamp: gdm.hre.ethers.utils.hexlify(Number(timestamp)) + }, + input: msg.callData, + save: true, + save_if_fails: true, + gas_price: 0, + }; + }); + + + while (!simsL1[0]) { + simsL1.shift(); + if (simsL1.length == 0) { + break; + } + } + + if (simsL2.length > 0) { + const bundle2 = await simulateBundle(bdm, simsL2, Number(B0L2)); + console.log(` >>> PROPOSAL RELAYED ${id} \n`); + const sim = bundle2[bundle2.length - 1]; + await shareSimulation(bdm, sim.simulation.id); + console.log(`Simulation ${sim.simulation.id} done, status: ${sim.simulation.status}`); + console.log(`Link: https://www.tdly.co/shared/simulation/${sim.simulation.id}`); + } + } + + console.log(`\n================================================================\n`); +} + +async function simulateBundle( + dm: DeploymentManager, + simulations: any[], + blockNumber: number = 0 +): Promise { + const { username, project, accessKey } = (dm.hre.config as any).tenderly; + const body = { + simulations, + block_number: blockNumber, + simulation_type: 'full', + save: true, + }; + + const result = await axios.post( + `https://api.tenderly.co/api/v1/account/${username}/project/${project}/simulate-bundle`, + body, + { + headers: { + 'X-Access-Key': accessKey, + 'Content-Type': 'application/json', + }, + } + ); + return result.data.simulation_results; +} + +async function shareSimulation(dm: DeploymentManager, simulationId: string) { + const { username, project, accessKey } = (dm.hre.config as any).tenderly; + return axios.post( + `https://api.tenderly.co/api/v1/account/${username}/project/${project}/simulations/${simulationId}/share`, + {}, + { + headers: { + 'X-Access-Key': accessKey, + 'Content-Type': 'application/json', + }, + } + ); +} + +export async function voteForOpenProposal( + dm: DeploymentManager, + { id, startBlock, endBlock }: OpenProposal +) { const governor = await dm.getContractOrThrow('governor'); const blockNow = await dm.hre.ethers.provider.getBlockNumber(); const blocksUntilStart = startBlock.toNumber() - blockNow; - const blocksUntilEnd = endBlock.toNumber() - Math.max(startBlock.toNumber(), blockNow); + const blocksUntilEnd = + endBlock.toNumber() - Math.max(startBlock.toNumber(), blockNow); if (blocksUntilStart > 0) { - await mineBlocks(dm, blocksUntilStart); + await mineBlocks(dm, blocksUntilStart + 1); } - const compWhales = dm.network === 'mainnet' ? COMP_WHALES.mainnet : COMP_WHALES.testnet; + const compWhales = + dm.network === 'mainnet' ? COMP_WHALES.mainnet : COMP_WHALES.testnet; if (blocksUntilEnd > 0) { for (const whale of compWhales) { try { - // Voting can fail if voter has already voted const voter = await impersonateAddress(dm, whale); await setNextBaseFeeToZero(dm); await governor.connect(voter).castVote(id, 1, { gasPrice: 0 }); @@ -627,36 +976,79 @@ export async function voteForOpenProposal(dm: DeploymentManager, { id, startBloc } } +function loadCachedProposal() { + const file = path.resolve( + __dirname, + '../..', + 'cache', + 'currentProposal.json' + ); + const json = JSON.parse(readFileSync(file, 'utf8')); + + return json; +} + +function loadCachedRelayMessages() { + const file = path.resolve(__dirname, '../../cache/relay.json'); + if (!existsSync(file)) { + return []; + } + + const raw = readFileSync(file, 'utf8').trim(); + if (!raw) { + return []; + } + return JSON.parse(raw); +} + +function loadCachedBytecodes() { + const file = path.resolve(__dirname, '../../cache/bytecodes.json'); + if (!existsSync(file)) { + return []; + } + const raw = readFileSync(file, 'utf8').trim(); + if (!raw) { + return []; + } + return JSON.parse(raw); +} + export async function executeOpenProposal( dm: DeploymentManager, { id, startBlock, endBlock }: OpenProposal ) { const governor = await dm.getContractOrThrow('governor'); const blockNow = await dm.hre.ethers.provider.getBlockNumber(); - const blocksUntilEnd = endBlock.toNumber() - Math.max(startBlock.toNumber(), blockNow) + 1; + const blocksUntilEnd = + endBlock.toNumber() - Math.max(startBlock.toNumber(), blockNow) + 1; if (blocksUntilEnd > 0) { await mineBlocks(dm, blocksUntilEnd); } - // Queue proposal (maybe) - if (await governor.state(id) == ProposalState.Succeeded) { + if ((await governor.state(id)) == ProposalState.Succeeded) { await setNextBaseFeeToZero(dm); await governor.queue(id, { gasPrice: 0 }); } // Execute proposal (maybe, w/ gas limit so we see if exec reverts, not a gas estimation error) - if (await governor.state(id) == ProposalState.Queued) { + if ((await governor.state(id)) == ProposalState.Queued) { const block = await dm.hre.ethers.provider.getBlock('latest'); const eta = await governor.proposalEta(id); + await setNextBlockTimestamp( + dm, + Math.max(block.timestamp, eta.toNumber()) + 1 + ); - await setNextBlockTimestamp(dm, Math.max(block.timestamp, eta.toNumber()) + 1); await setNextBaseFeeToZero(dm); await updateCCIPStats(dm); + await governor.execute(id, { gasPrice: 0, gasLimit: 120000000 }); } + await redeployRenzoOracle(dm); await mockAllRedstoneOracles(dm); + // mine a block await dm.hre.ethers.provider.send('evm_mine', []); } @@ -673,20 +1065,17 @@ async function testnetPropose( ) { const governor = await dm.getContractOrThrow('governor'); const testnetGovernor = new Contract( - governor.address, [ + governor.address, + [ 'function propose(address[] memory targets, uint256[] memory values, string[] memory signatures, bytes[] memory calldatas, string memory description) external returns (uint256 proposalId)', - 'event ProposalCreated(uint256 proposalId, address proposer, address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, uint256 startBlock, uint256 endBlock, string description)' - ], governor.signer + 'event ProposalCreated(uint256 proposalId, address proposer, address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, uint256 startBlock, uint256 endBlock, string description)', + ], + governor.signer ); - return testnetGovernor.connect(proposer).propose( - targets, - values, - signatures, - calldatas, - description, - { gasPrice } - ); + return testnetGovernor + .connect(proposer) + .propose(targets, values, signatures, calldatas, description, { gasPrice }); } // Instantly executes some actions through the governance proposal process @@ -702,24 +1091,56 @@ export async function fastGovernanceExecute( await setNextBaseFeeToZero(dm); - const proposeTxn = dm.network === 'mainnet' ? await ( - await governor.connect(proposer).propose( - targets, - values, - calldatas.map((calldata, i) => { - return utils.id(signatures[i]).slice(0, 10) + calldata.slice(2); - }), - 'FastExecuteProposal', - { gasPrice: 0 } - ) - ).wait() : await ( - await testnetPropose(dm, proposer, targets, values, signatures, calldatas, 'FastExecuteProposal', 0) - ).wait(); - const proposeEvent = proposeTxn.events.find(event => event.event === 'ProposalCreated'); + const proposeTxn = + dm.network === 'mainnet' + ? await ( + await governor.connect(proposer).propose( + targets, + values, + calldatas.map((calldata, i) => { + return utils.id(signatures[i]).slice(0, 10) + calldata.slice(2); + }), + 'FastExecuteProposal', + { gasPrice: 0 } + ) + ).wait() + : await ( + await testnetPropose( + dm, + proposer, + targets, + values, + signatures, + calldatas, + 'FastExecuteProposal', + 0 + ) + ).wait(); + const proposeEvent = proposeTxn.events.find( + (event) => event.event === 'ProposalCreated' + ); const [id, , , , , , startBlock, endBlock] = proposeEvent.args; - await voteForOpenProposal(dm, { id, proposer: proposer.address, targets, values, signatures, calldatas, startBlock, endBlock }); - await executeOpenProposal(dm, { id, proposer: proposer.address, targets, values, signatures, calldatas, startBlock, endBlock }); + await voteForOpenProposal(dm, { + id, + proposer: proposer.address, + targets, + values, + signatures, + calldatas, + startBlock, + endBlock, + }); + await executeOpenProposal(dm, { + id, + proposer: proposer.address, + targets, + values, + signatures, + calldatas, + startBlock, + endBlock, + }); } export async function fastL2GovernanceExecute( @@ -731,7 +1152,8 @@ export async function fastL2GovernanceExecute( signatures: string[], calldatas: string[] ) { - const startingBlockNumber = await governanceDeploymentManager.hre.ethers.provider.getBlockNumber(); + const startingBlockNumber = + await governanceDeploymentManager.hre.ethers.provider.getBlockNumber(); await fastGovernanceExecute( governanceDeploymentManager, proposer, @@ -741,10 +1163,18 @@ export async function fastL2GovernanceExecute( calldatas ); - await relayMessage(governanceDeploymentManager, bridgeDeploymentManager, startingBlockNumber); + await relayMessage( + governanceDeploymentManager, + bridgeDeploymentManager, + startingBlockNumber + ); } -export async function createCrossChainProposal(context: CometContext, l2ProposalData: string, bridgeReceiver: BaseBridgeReceiver) { +export async function createCrossChainProposal( + context: CometContext, + l2ProposalData: string, + bridgeReceiver: BaseBridgeReceiver +) { const govDeploymentManager = context.world.auxiliaryDeploymentManager!; const bridgeDeploymentManager = context.world.deploymentManager!; const proposer = await context.getProposer(); @@ -757,26 +1187,37 @@ export async function createCrossChainProposal(context: CometContext, l2Proposal // Create the chain-specific wrapper around the L2 proposal data switch (bridgeNetwork) { case 'arbitrum': { - const inbox = await govDeploymentManager.getContractOrThrow('arbitrumInbox'); + const inbox = await govDeploymentManager.getContractOrThrow( + 'arbitrumInbox' + ); const refundAddress = constants.AddressZero; const createRetryableTicketCalldata = utils.defaultAbiCoder.encode( [ - 'address', 'uint256', 'uint256', 'address', 'address', 'uint256', 'uint256', 'bytes' + 'address', + 'uint256', + 'uint256', + 'address', + 'address', + 'uint256', + 'uint256', + 'bytes', ], [ bridgeReceiver.address, // address to, - 0, // uint256 l2CallValue, - 0, // uint256 maxSubmissionCost, - refundAddress, // address excessFeeRefundAddress, - refundAddress, // address callValueRefundAddress, - 0, // uint256 gasLimit, - 0, // uint256 maxFeePerGas, - l2ProposalData, // bytes calldata data + 0, // uint256 l2CallValue, + 0, // uint256 maxSubmissionCost, + refundAddress, // address excessFeeRefundAddress, + refundAddress, // address callValueRefundAddress, + 0, // uint256 gasLimit, + 0, // uint256 maxFeePerGas, + l2ProposalData, // bytes calldata data ] ); targets.push(inbox.address); values.push(0); - signatures.push('createRetryableTicket(address,uint256,uint256,address,address,uint256,uint256,bytes)'); + signatures.push( + 'createRetryableTicket(address,uint256,uint256,address,address,uint256,uint256,bytes)' + ); calldata.push(createRetryableTicketCalldata); break; } @@ -785,9 +1226,10 @@ export async function createCrossChainProposal(context: CometContext, l2Proposal ['address', 'bytes', 'uint32'], [bridgeReceiver.address, l2ProposalData, 1_000_000] // XXX find a reliable way to estimate the gasLimit ); - const baseL1CrossDomainMessenger = await govDeploymentManager.getContractOrThrow( - 'baseL1CrossDomainMessenger' - ); + const baseL1CrossDomainMessenger = + await govDeploymentManager.getContractOrThrow( + 'baseL1CrossDomainMessenger' + ); targets.push(baseL1CrossDomainMessenger.address); values.push(0); @@ -808,28 +1250,29 @@ export async function createCrossChainProposal(context: CometContext, l2Proposal calldata.push(sendMessageToChildCalldata); break; } - // case 'linea-goerli': { - // const sendMessageCalldata = utils.defaultAbiCoder.encode( - // ['address', 'uint256', 'bytes'], - // [bridgeReceiver.address, 0, l2ProposalData] - // ); - // const lineaMessageService = await govDeploymentManager.getContractOrThrow( - // 'lineaMessageService' - // ); - // targets.push(lineaMessageService.address); - // values.push(0); - // signatures.push('sendMessage(address,uint256,bytes)'); - // calldata.push(sendMessageCalldata); - // break; - // } + case 'linea': { + const sendMessageCalldata = utils.defaultAbiCoder.encode( + ['address', 'uint256', 'bytes'], + [bridgeReceiver.address, 0, l2ProposalData] + ); + const lineaMessageService = await govDeploymentManager.getContractOrThrow( + 'lineaMessageService' + ); + targets.push(lineaMessageService.address); + values.push(0); + signatures.push('sendMessage(address,uint256,bytes)'); + calldata.push(sendMessageCalldata); + break; + } case 'optimism': { const sendMessageCalldata = utils.defaultAbiCoder.encode( ['address', 'bytes', 'uint32'], [bridgeReceiver.address, l2ProposalData, 2_500_000] ); - const opL1CrossDomainMessenger = await govDeploymentManager.getContractOrThrow( - 'opL1CrossDomainMessenger' - ); + const opL1CrossDomainMessenger = + await govDeploymentManager.getContractOrThrow( + 'opL1CrossDomainMessenger' + ); targets.push(opL1CrossDomainMessenger.address); values.push(0); @@ -842,9 +1285,10 @@ export async function createCrossChainProposal(context: CometContext, l2Proposal ['address', 'bytes', 'uint256'], [bridgeReceiver.address, l2ProposalData, 2_500_000] ); - const mantleL1CrossDomainMessenger = await govDeploymentManager.getContractOrThrow( - 'mantleL1CrossDomainMessenger' - ); + const mantleL1CrossDomainMessenger = + await govDeploymentManager.getContractOrThrow( + 'mantleL1CrossDomainMessenger' + ); targets.push(mantleL1CrossDomainMessenger.address); values.push(0); signatures.push('sendMessage(address,bytes,uint32)'); @@ -856,9 +1300,10 @@ export async function createCrossChainProposal(context: CometContext, l2Proposal ['address', 'bytes', 'uint256'], [bridgeReceiver.address, l2ProposalData, 2_500_000] ); - const unichainL1CrossDomainMessenger = await govDeploymentManager.getContractOrThrow( - 'unichainL1CrossDomainMessenger' - ); + const unichainL1CrossDomainMessenger = + await govDeploymentManager.getContractOrThrow( + 'unichainL1CrossDomainMessenger' + ); targets.push(unichainL1CrossDomainMessenger.address); values.push(0); signatures.push('sendMessage(address,bytes,uint32)'); @@ -896,13 +1341,18 @@ export async function createCrossChainProposal(context: CometContext, l2Proposal l2ProposalData, [], constants.AddressZero, - '0x' - ] + '0x', + ], ]; - const data = utils.defaultAbiCoder.encode(['uint64', '(bytes,bytes,(address,uint256)[],address,bytes)'], args); + const data = utils.defaultAbiCoder.encode( + ['uint64', '(bytes,bytes,(address,uint256)[],address,bytes)'], + args + ); - signatures.push('ccipSend(uint64,(bytes,bytes,(address,uint256)[],address,bytes))'); + signatures.push( + 'ccipSend(uint64,(bytes,bytes,(address,uint256)[],address,bytes))' + ); calldata.push(data); break; } @@ -928,12 +1378,22 @@ export async function executeOpenProposalAndRelay( bridgeDeploymentManager: DeploymentManager, openProposal: OpenProposal ) { - const startingBlockNumber = await governanceDeploymentManager.hre.ethers.provider.getBlockNumber(); + const startingBlockNumber = + await governanceDeploymentManager.hre.ethers.provider.getBlockNumber(); await executeOpenProposal(governanceDeploymentManager, openProposal); await mockAllRedstoneOracles(bridgeDeploymentManager); - - if (await isBridgeProposal(governanceDeploymentManager, bridgeDeploymentManager, openProposal)) { - await relayMessage(governanceDeploymentManager, bridgeDeploymentManager, startingBlockNumber); + if ( + await isBridgeProposal( + governanceDeploymentManager, + bridgeDeploymentManager, + openProposal + ) + ) { + await relayMessage( + governanceDeploymentManager, + bridgeDeploymentManager, + startingBlockNumber + ); } else { console.log( `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Proposal ${openProposal.id} doesn't target bridge; not relaying` @@ -942,15 +1402,24 @@ export async function executeOpenProposalAndRelay( } } -async function getLiquidationMargin({ comet, actor, baseLiquidity, factorScale }): Promise { +async function getLiquidationMargin({ + comet, + actor, + baseLiquidity, + factorScale, +}): Promise { const numAssets = await comet.numAssets(); let liquidity = baseLiquidity; for (let i = 0; i < numAssets; i++) { - const { asset, priceFeed, scale, liquidateCollateralFactor } = await comet.getAssetInfo(i); - const collatBalance = (await comet.collateralBalanceOf(actor.address, asset)).toBigInt(); + const { asset, priceFeed, scale, liquidateCollateralFactor } = + await comet.getAssetInfo(i); + const collatBalance = ( + await comet.collateralBalanceOf(actor.address, asset) + ).toBigInt(); const collatPrice = (await comet.getPrice(priceFeed)).toBigInt(); - const collatValue = collatBalance * collatPrice / scale.toBigInt(); - liquidity += collatValue * liquidateCollateralFactor.toBigInt() / factorScale; + const collatValue = (collatBalance * collatPrice) / scale.toBigInt(); + liquidity += + (collatValue * liquidateCollateralFactor.toBigInt()) / factorScale; } return liquidity; @@ -963,20 +1432,38 @@ invariant: isolating for timeElapsed: timeElapsed = -liquidationMargin / (baseBalanceOf * price / baseScale) / (borrowRate / factorScale); */ -export async function timeUntilUnderwater({ comet, actor, fudgeFactor = 0n }: { comet: CometInterface, actor: CometActor, fudgeFactor?: bigint }): Promise { +export async function timeUntilUnderwater({ + comet, + actor, + fudgeFactor = 0n, +}: { + comet: CometInterface; + actor: CometActor; + fudgeFactor?: bigint; +}): Promise { const baseBalance = await actor.getCometBaseBalance(); const baseScale = (await comet.baseScale()).toBigInt(); - const basePrice = (await comet.getPrice(await comet.baseTokenPriceFeed())).toBigInt(); - const baseLiquidity = baseBalance * basePrice / baseScale; + const basePrice = ( + await comet.getPrice(await comet.baseTokenPriceFeed()) + ).toBigInt(); + const baseLiquidity = (baseBalance * basePrice) / baseScale; const utilization = await comet.getUtilization(); const borrowRate = (await comet.getBorrowRate(utilization)).toBigInt(); const factorScale = (await comet.factorScale()).toBigInt(); - const liquidationMargin = await getLiquidationMargin({ comet, actor, baseLiquidity, factorScale }); + const liquidationMargin = await getLiquidationMargin({ + comet, + actor, + baseLiquidity, + factorScale, + }); if (liquidationMargin < 0) { return 0; // already underwater } // XXX throw error if baseBalanceOf is positive and liquidationMargin is positive - return Number((-liquidationMargin * factorScale / baseLiquidity / borrowRate) + fudgeFactor); -} \ No newline at end of file + return Number( + (-liquidationMargin * factorScale) / baseLiquidity / borrowRate + + fudgeFactor + ); +} diff --git a/scenario/utils/isBridgeProposal.ts b/scenario/utils/isBridgeProposal.ts index 2438e3d76..fc7492286 100644 --- a/scenario/utils/isBridgeProposal.ts +++ b/scenario/utils/isBridgeProposal.ts @@ -39,6 +39,25 @@ export async function isBridgeProposal( ); const targets = openProposal.targets; const bridgeContracts = [baseL1CrossDomainMessenger.address, baseL1StandardBridge.address, baseL1USDSBridge.address]; + + return targets.some(t => bridgeContracts.includes(t)); + } + case 'linea': { + const lineaMessageService = await governanceDeploymentManager.getContractOrThrow( + 'lineaMessageService' + ); + const lineaL1USDCBridge = await governanceDeploymentManager.getContractOrThrow( + 'lineaL1USDCBridge' + ); + const lineaL1TokenBridge = await governanceDeploymentManager.getContractOrThrow( + 'lineaL1TokenBridge' + ); + const bridgeContracts = [ + lineaMessageService.address, + lineaL1USDCBridge.address, + lineaL1TokenBridge.address + ]; + const targets = openProposal.targets; return targets.some(t => bridgeContracts.includes(t)); } // case 'linea': { diff --git a/scenario/utils/relayArbitrumMessage.ts b/scenario/utils/relayArbitrumMessage.ts index 5bcaef035..857342aea 100644 --- a/scenario/utils/relayArbitrumMessage.ts +++ b/scenario/utils/relayArbitrumMessage.ts @@ -4,11 +4,17 @@ import { setNextBaseFeeToZero, setNextBlockTimestamp } from './hreUtils'; import { utils, BigNumber } from 'ethers'; import { Log } from '@ethersproject/abstract-provider'; import { sourceTokens } from '../../plugins/scenario/utils/TokenSourcer'; +import { OpenBridgedProposal } from '../context/Gov'; + +function isTenderlyLog(log: any): log is { raw: { topics: string[], data: string } } { + return !!log?.raw?.topics && !!log?.raw?.data; +} export async function relayArbitrumMessage( governanceDeploymentManager: DeploymentManager, bridgeDeploymentManager: DeploymentManager, - startingBlockNumber: number + startingBlockNumber: number, + tenderlyLogs?: any[] ) { // L1 contracts const inbox = await governanceDeploymentManager.getContractOrThrow('arbitrumInbox'); // Inbox -> Bridge @@ -17,14 +23,67 @@ export async function relayArbitrumMessage( // L2 contracts const bridgeReceiver = await bridgeDeploymentManager.getContractOrThrow('bridgeReceiver'); - const inboxMessageDeliveredEvents: Log[] = await governanceDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: startingBlockNumber, - toBlock: 'latest', - address: inbox.address, - topics: [utils.id('InboxMessageDelivered(uint256,bytes)')] - }); + let inboxMessageDeliveredEvents: Log[] = []; + let messageDeliveredEvents: Log[] = []; + const openBridgedProposals: OpenBridgedProposal[] = []; + + if (tenderlyLogs) { + const inboxTopic = utils.id('InboxMessageDelivered(uint256,bytes)'); + const bridgeTopic = utils.id('MessageDelivered(uint256,bytes32,address,uint8,address,bytes32,uint256,uint64)'); + + const tenderlyInboxEvents = tenderlyLogs.filter(log => + log.raw?.topics?.[0] === inboxTopic && + log.raw?.address?.toLowerCase() === inbox.address.toLowerCase() + ); + + const tenderlyBridgeEvents = tenderlyLogs.filter(log => + log.raw?.topics?.[0] === bridgeTopic && + log.raw?.address?.toLowerCase() === bridge.address.toLowerCase() + ); + + const realInboxEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: startingBlockNumber, + toBlock: 'latest', + address: inbox.address, + topics: [inboxTopic] + }); + + const realBridgeEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: startingBlockNumber, + toBlock: 'latest', + address: bridge.address, + topics: [bridgeTopic] + }); + + inboxMessageDeliveredEvents = [...realInboxEvents, ...tenderlyInboxEvents]; + messageDeliveredEvents = [...realBridgeEvents, ...tenderlyBridgeEvents]; + } else { + inboxMessageDeliveredEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: startingBlockNumber, + toBlock: 'latest', + address: inbox.address, + topics: [utils.id('InboxMessageDelivered(uint256,bytes)')] + }); + + messageDeliveredEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: startingBlockNumber, + toBlock: 'latest', + address: bridge.address, + topics: [utils.id('MessageDelivered(uint256,bytes32,address,uint8,address,bytes32,uint256,uint64)')] + }); + } + + const dataAndTargets = inboxMessageDeliveredEvents.map((event) => { + let data, topics; + + if (isTenderlyLog(event)) { + data = event.raw.data; + topics = event.raw.topics; + } else { + data = event.data; + topics = event.topics; + } - const dataAndTargets = inboxMessageDeliveredEvents.map(({ data, topics }) => { const header = '0x'; const headerLength = header.length; const wordLength = 2 * 32; @@ -45,14 +104,17 @@ export async function relayArbitrumMessage( }; }); - const messageDeliveredEvents: Log[] = await governanceDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: startingBlockNumber, - toBlock: 'latest', - address: bridge.address, - topics: [utils.id('MessageDelivered(uint256,bytes32,address,uint8,address,bytes32,uint256,uint64)')] - }); + const senders = messageDeliveredEvents.map((event) => { + let data, topics; + + if (isTenderlyLog(event)) { + data = event.raw.data; + topics = event.raw.topics; + } else { + data = event.data; + topics = event.topics; + } - const senders = messageDeliveredEvents.map(({ data, topics }) => { const decodedData = utils.defaultAbiCoder.decode( [ 'address inbox', @@ -97,6 +159,28 @@ export async function relayArbitrumMessage( ); // if token is mainnet ETH -> than source arbitrum weth if(token == '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'){ + if(tenderlyLogs) { + const callData = bridgeReceiver.interface.encodeFunctionData( + 'sourceTokens', + [ + { + dm: bridgeDeploymentManager, + amount: amount, + asset: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + address: to, + blacklist: [] + } + ] + ); + + bridgeDeploymentManager.stashRelayMessage( + bridgeReceiver.address, + callData, + arbitrumSigner.address + ); + } + + await sourceTokens({ dm: bridgeDeploymentManager, amount: amount, @@ -104,6 +188,7 @@ export async function relayArbitrumMessage( address: to, blacklist: [], }); + continue; } } @@ -119,6 +204,13 @@ export async function relayArbitrumMessage( const tx = await ( await arbitrumSigner.sendTransaction(transactionRequest) ).wait(); + if(tenderlyLogs) { + bridgeDeploymentManager.stashRelayMessage( + toAddress, + data, + sender + ); + } const proposalCreatedLog = tx.logs.find( event => event.address === bridgeReceiver.address @@ -133,32 +225,81 @@ export async function relayArbitrumMessage( // execute queued proposal await setNextBaseFeeToZero(bridgeDeploymentManager); - await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); + + if(tenderlyLogs) { + const signer = await bridgeDeploymentManager.getSigner(); + const callData = bridgeReceiver.interface.encodeFunctionData('executeProposal', [id]); + bridgeDeploymentManager.stashRelayMessage( + bridgeReceiver.address, + callData, + await signer.getAddress() + ); + } else { + await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); + } + openBridgedProposals.push({ + id: BigNumber.from(id), + eta: BigNumber.from(eta) + }); } } + + return openBridgedProposals; } export async function relayArbitrumCCTPMint( governanceDeploymentManager: DeploymentManager, bridgeDeploymentManager: DeploymentManager, - startingBlockNumber: number + startingBlockNumber: number, + tenderlyLogs?: any[] ){ + + if(tenderlyLogs) { + return; + } // CCTP relay // L1 contracts const L1MessageTransmitter = await governanceDeploymentManager.getContractOrThrow('CCTPMessageTransmitter'); // Arbitrum TokenMinter which is L2 contracts const TokenMinter = await bridgeDeploymentManager.existing('TokenMinter', '0xE7Ed1fa7f45D05C508232aa32649D89b73b8bA48', 'arbitrum'); + let depositForBurnEvents: Log[] = []; - const depositForBurnEvents: Log[] = await governanceDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: startingBlockNumber, - toBlock: 'latest', - address: L1MessageTransmitter.address, - topics: [utils.id('MessageSent(bytes)')] - }); + if (tenderlyLogs) { + const messageSentTopic = utils.id('MessageSent(bytes)'); + + const tenderlyEvents = tenderlyLogs.filter(log => + log.raw?.topics?.[0] === messageSentTopic && + log.raw?.address?.toLowerCase() === L1MessageTransmitter.address.toLowerCase() + ); + + const realEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: startingBlockNumber, + toBlock: 'latest', + address: L1MessageTransmitter.address, + topics: [messageSentTopic] + }); + + depositForBurnEvents = [...realEvents, ...tenderlyEvents]; + } else { + depositForBurnEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: startingBlockNumber, + toBlock: 'latest', + address: L1MessageTransmitter.address, + topics: [utils.id('MessageSent(bytes)')] + }); + } // Decode message body - const burnEvents = depositForBurnEvents.map(({ data }) => { + const burnEvents = depositForBurnEvents.map((event) => { + let data; + + if (isTenderlyLog(event)) { + data = event.raw.data; + } else { + data = event.data; + } + const dataBytes = utils.arrayify(data); // Since data is encodePacked, so can't simply decode via AbiCoder.decode const offset = 64; @@ -246,9 +387,17 @@ export async function relayArbitrumCCTPMint( }); await setNextBaseFeeToZero(bridgeDeploymentManager); - - await ( - await localTokenMessengerSigner.sendTransaction(transactionRequest) - ).wait(); + if (tenderlyLogs) { + const callData = TokenMinter.interface.encodeFunctionData('mint', [sourceDomain, burnToken, utils.getAddress(recipient), amount]); + bridgeDeploymentManager.stashRelayMessage( + TokenMinter.address, + callData, + localTokenMessengerSigner.address + ); + } else { + await ( + await localTokenMessengerSigner.sendTransaction(transactionRequest) + ).wait(); + } } -} +} \ No newline at end of file diff --git a/scenario/utils/relayBaseMessage.ts b/scenario/utils/relayBaseMessage.ts index 7a0cbeec6..955086e40 100644 --- a/scenario/utils/relayBaseMessage.ts +++ b/scenario/utils/relayBaseMessage.ts @@ -17,10 +17,15 @@ function applyL1ToL2Alias(address: string) { return `0x${(BigInt(address) + offset).toString(16)}`; } +function isTenderlyLog(log: any): log is { raw: { topics: string[], data: string } } { + return !!log?.raw?.topics && !!log?.raw?.data; +} + export default async function relayBaseMessage( governanceDeploymentManager: DeploymentManager, bridgeDeploymentManager: DeploymentManager, - startingBlockNumber: number + startingBlockNumber: number, + tenderlyLogs?: any[] ) { const baseL1CrossDomainMessenger = await governanceDeploymentManager.getContractOrThrow('baseL1CrossDomainMessenger'); const bridgeReceiver = await bridgeDeploymentManager.getContractOrThrow('bridgeReceiver'); @@ -32,31 +37,76 @@ export default async function relayBaseMessage( // Grab all events on the L1CrossDomainMessenger contract since the `startingBlockNumber` const filter = baseL1CrossDomainMessenger.filters.SentMessage(); - const sentMessageEvents: Log[] = await governanceDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: startingBlockNumber, - toBlock: 'latest', - address: baseL1CrossDomainMessenger.address, - topics: filter.topics! - }); + let sentMessageEvents: Log[] = []; + + if (tenderlyLogs) { + const sentMessageTopic = baseL1CrossDomainMessenger.interface.getEventTopic('SentMessage'); + + const tenderlySentMessageEvents = tenderlyLogs.filter(log => + log.raw?.topics?.[0] === sentMessageTopic && + log.raw?.address?.toLowerCase() === baseL1CrossDomainMessenger.address.toLowerCase() + ); + + const realSentMessageEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: startingBlockNumber, + toBlock: 'latest', + address: baseL1CrossDomainMessenger.address, + topics: filter.topics!, + }); + + sentMessageEvents = [...realSentMessageEvents, ...tenderlySentMessageEvents]; + } else { + sentMessageEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: startingBlockNumber, + toBlock: 'latest', + address: baseL1CrossDomainMessenger.address, + topics: filter.topics!, + }); + } for (let sentMessageEvent of sentMessageEvents) { - const { args: { target, sender, message, messageNonce, gasLimit } } = baseL1CrossDomainMessenger.interface.parseLog(sentMessageEvent); + let parsedLog; + + if (isTenderlyLog(sentMessageEvent)) { + parsedLog = baseL1CrossDomainMessenger.interface.parseLog({ + topics: sentMessageEvent.raw.topics, + data: sentMessageEvent.raw.data, + }); + } else { + parsedLog = baseL1CrossDomainMessenger.interface.parseLog(sentMessageEvent); + } + + const { + args: { target, sender, message, messageNonce, gasLimit }, + } = parsedLog; + const aliasedSigner = await impersonateAddress( bridgeDeploymentManager, applyL1ToL2Alias(baseL1CrossDomainMessenger.address) ); + let relayMessageTxn: { events: any[] }; await setNextBaseFeeToZero(bridgeDeploymentManager); - const relayMessageTxn = await ( - await l2CrossDomainMessenger.connect(aliasedSigner).relayMessage( - messageNonce, - sender, - target, - 0, - 0, - message, - { gasPrice: 0, gasLimit } - ) + + if (tenderlyLogs) { + const callData = l2CrossDomainMessenger.interface.encodeFunctionData( + 'relayMessage', + [messageNonce, sender, target, 0, 0, message] + ); + bridgeDeploymentManager.stashRelayMessage( + l2CrossDomainMessenger.address, + callData, + aliasedSigner.address + ); + } + + relayMessageTxn = await ( + await l2CrossDomainMessenger + .connect(aliasedSigner) + .relayMessage(messageNonce, sender, target, 0, 0, message, { + gasPrice: 0, + gasLimit, + }) ).wait(); // Try to decode the SentMessage data to determine what type of cross-chain activity this is. So far, @@ -69,10 +119,11 @@ export default async function relayBaseMessage( const messageWithoutSigHash = '0x' + messageWithoutPrefix.slice(8); try { // 1a. Bridging ERC20 token - const { _l2Token, l1Token, _from, to, amount, _data } = ethers.utils.defaultAbiCoder.decode( - ['address l2Token', 'address l1Token', 'address from', 'address to', 'uint256 amount', 'bytes data'], - messageWithoutSigHash - ); + const { _l2Token, l1Token, _from, to, amount, _data } = + ethers.utils.defaultAbiCoder.decode( + ['address l2Token', 'address l1Token', 'address from', 'address to', 'uint256 amount', 'bytes data'], + messageWithoutSigHash + ); console.log( `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Bridged over ${amount} of ${l1Token} to user ${to}` @@ -98,13 +149,40 @@ export default async function relayBaseMessage( } } else if (target === bridgeReceiver.address) { // Cross-chain message passing - const proposalCreatedEvent = relayMessageTxn.events.find(event => event.address === bridgeReceiver.address); - const { args: { id, eta } } = bridgeReceiver.interface.parseLog(proposalCreatedEvent); + if (!tenderlyLogs && relayMessageTxn) { + const proposalCreatedEvent = relayMessageTxn.events.find( + (event) => event.address === bridgeReceiver.address + ); + const { + args: { id, eta }, + } = bridgeReceiver.interface.parseLog(proposalCreatedEvent); - // Add the proposal to the list of open bridged proposals to be executed after all the messages have been relayed - openBridgedProposals.push({ id, eta }); + // Add the proposal to the list of open bridged proposals to be executed after all the messages have been relayed + openBridgedProposals.push({ id, eta }); + } } else { - throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); + throw new Error( + `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message` + ); + } + } + + // Handle proposal creation for tenderly + if (tenderlyLogs) { + // We need to check for ProposalCreated events since we don't get them in the loop above + const proposalFilter = bridgeReceiver.filters.ProposalCreated(); + const proposalEvents = await bridgeDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: 'latest', + toBlock: 'latest', + address: bridgeReceiver.address, + topics: proposalFilter.topics + }); + + for (let event of proposalEvents) { + const { + args: { id, eta }, + } = bridgeReceiver.interface.parseLog(event); + openBridgedProposals.push({ id, eta }); } } @@ -116,9 +194,24 @@ export default async function relayBaseMessage( // Execute queued proposal await setNextBaseFeeToZero(bridgeDeploymentManager); - await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); + if (tenderlyLogs) { + const callData = bridgeReceiver.interface.encodeFunctionData( + 'executeProposal', + [id] + ); + const signer = await bridgeDeploymentManager.getSigner(); + bridgeDeploymentManager.stashRelayMessage( + bridgeReceiver.address, + callData, + await signer.getAddress() + ); + } else { + await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); + } console.log( `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Executed bridged proposal ${id}` ); } + + return openBridgedProposals; } \ No newline at end of file diff --git a/scenario/utils/relayLineaMessage.ts b/scenario/utils/relayLineaMessage.ts index 14c6cd0b2..b807d2469 100644 --- a/scenario/utils/relayLineaMessage.ts +++ b/scenario/utils/relayLineaMessage.ts @@ -5,34 +5,118 @@ import { Log } from '@ethersproject/abstract-provider'; import { OpenBridgedProposal } from '../context/Gov'; import { impersonateAddress } from '../../plugins/scenario/utils'; -const LINEA_SETTER_ROLE_ACCOUNT = '0x0f2b2747d1861f8fc016bf5b60d95f1a511b7e08'; +const LINEA_SETTER_ROLE_ACCOUNT = '0xc1C6B09D1eB6fCA0fF3cA11027E5Bc4AeDb47F67'; + +function isTenderlyLog(log: any): log is { raw: { topics: string[], data: string } } { + return !!log?.raw?.topics && !!log?.raw?.data; +} export default async function relayLineaMessage( governanceDeploymentManager: DeploymentManager, bridgeDeploymentManager: DeploymentManager, - startingBlockNumber: number + startingBlockNumber: number, + tenderlyLogs?: any[] ) { + const lineaMessageService = await governanceDeploymentManager.getContractOrThrow( 'lineaMessageService' ); + const lineaL1USDCBridge = await governanceDeploymentManager.getContractOrThrow( + 'lineaL1USDCBridge' + ); + const timelock = await governanceDeploymentManager.getContractOrThrow( + 'timelock' + ); + const lineaL1TokenBridge = await governanceDeploymentManager.getContractOrThrow( + 'lineaL1TokenBridge' + ); const bridgeReceiver = await bridgeDeploymentManager.getContractOrThrow('bridgeReceiver'); + const l2USDCBridge = await bridgeDeploymentManager.getContractOrThrow('l2USDCBridge'); const l2MessageService = await bridgeDeploymentManager.getContractOrThrow('l2MessageService'); - const l2TokenBridge = await bridgeDeploymentManager.getContractOrThrow('l2TokenBridge'); - const l2usdcBridge = await bridgeDeploymentManager.getContractOrThrow('l2usdcBridge'); - + const l2StandardBridge = await bridgeDeploymentManager.getContractOrThrow('l2StandardBridge'); const openBridgedProposals: OpenBridgedProposal[] = []; // Grab all events on the L1CrossDomainMessenger contract since the `startingBlockNumber` const filter = lineaMessageService.filters.MessageSent(); - const messageSentEvents: Log[] = await governanceDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: startingBlockNumber, - toBlock: 'latest', - address: lineaMessageService.address, - topics: filter.topics! - }); - for (let messageSentEvent of messageSentEvents) { - const { - args: { _from, _to, _fee, _value, _nonce, _calldata, _messageHash } - } = lineaMessageService.interface.parseLog(messageSentEvent); + const filterRollingHash = lineaMessageService.filters.RollingHashUpdated(); + let messageSentEvents: Log[] = []; + let rollingHashUpdatedEvents: Log[] = []; + + if (tenderlyLogs) { + + const msgTopic = lineaMessageService.interface.getEventTopic('MessageSent'); + const hashTopic = lineaMessageService.interface.getEventTopic('RollingHashUpdated'); + + const tenderlyMsgEvents = tenderlyLogs.filter(log => + log.raw?.topics?.[0] === msgTopic && + log.raw?.address?.toLowerCase() === lineaMessageService.address.toLowerCase() + ); + + const tenderlyHashEvents = tenderlyLogs.filter(log => + log.raw?.topics?.[0] === hashTopic && + log.raw?.address?.toLowerCase() === lineaMessageService.address.toLowerCase() + ); + + // getLogs version: + const realMsgEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: (startingBlockNumber - 50000), + toBlock: 'latest', + address: lineaMessageService.address, + topics: filter.topics! + }); + + const realHashEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: (startingBlockNumber - 50000), + toBlock: 'latest', + address: lineaMessageService.address, + topics: filterRollingHash.topics! + }); + + messageSentEvents = [...realMsgEvents, ...tenderlyMsgEvents]; + rollingHashUpdatedEvents = [...realHashEvents, ...tenderlyHashEvents]; + } else { + messageSentEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: (startingBlockNumber - 50000), + toBlock: 'latest', + address: lineaMessageService.address, + topics: filter.topics! + }); + + rollingHashUpdatedEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: (startingBlockNumber - 50000), + toBlock: 'latest', + address: lineaMessageService.address, + topics: filterRollingHash.topics! + }); + } + + for (let i = 0; i < messageSentEvents.length; i++) { + const messageSentEvent = messageSentEvents[i]; + const rollingHashUpdatedEvent = rollingHashUpdatedEvents[i]; + + let parsedMessage, parsedRolling; + + if (isTenderlyLog(messageSentEvent)) { + parsedMessage = lineaMessageService.interface.parseLog({ + topics: messageSentEvent.raw.topics, + data: messageSentEvent.raw.data, + }); + } else { + parsedMessage = lineaMessageService.interface.parseLog(messageSentEvent); + } + + if (isTenderlyLog(rollingHashUpdatedEvent)) { + parsedRolling = lineaMessageService.interface.parseLog({ + topics: rollingHashUpdatedEvent.raw.topics, + data: rollingHashUpdatedEvent.raw.data, + }); + } else { + parsedRolling = lineaMessageService.interface.parseLog(rollingHashUpdatedEvent); + } + + const { _from, _to, _fee, _value, _nonce, _calldata, _messageHash } = parsedMessage.args; + const { messageNumber, rollingHash, messageHash } = parsedRolling.args; + + if((await l2MessageService.lastAnchoredL1MessageNumber()).gte(messageNumber)) continue; await setNextBaseFeeToZero(bridgeDeploymentManager); @@ -40,48 +124,110 @@ export default async function relayLineaMessage( bridgeDeploymentManager, LINEA_SETTER_ROLE_ACCOUNT ); + + + let callData; // First the message's hash has to be added by a specific account in the "contract's queue" - await l2MessageService.connect(aliasSetterRoleAccount).addL1L2MessageHashes([_messageHash]); - - const relayMessageTxn = await ( - await l2MessageService.claimMessage( - _from, - _to, - _fee, - _value, - constants.AddressZero, - _calldata, - _nonce, - { - gasPrice: 0, - gasLimit: 10000000 - } - ) - ).wait(); + if((await l2MessageService.lastAnchoredL1MessageNumber()).lte(messageNumber)){ + if(tenderlyLogs) { + callData = l2MessageService.interface.encodeFunctionData('anchorL1L2MessageHashes', [ + [messageHash], + messageNumber, + messageNumber, + rollingHash + ]); + + bridgeDeploymentManager.stashRelayMessage( + l2MessageService.address, + callData, + aliasSetterRoleAccount.address + ); + } + + await l2MessageService.connect(aliasSetterRoleAccount).anchorL1L2MessageHashes( + [messageHash], + messageNumber, + messageNumber, + rollingHash + ); + } + + + let relayMessageTxn: { events: any[] }; + + if( + _from.toLowerCase() === timelock.address.toLowerCase() + || _from.toLowerCase() === lineaL1TokenBridge.address.toLowerCase() + || _from.toLowerCase() === lineaL1USDCBridge.address.toLowerCase() + ){ + if(tenderlyLogs) { + callData = l2MessageService.interface.encodeFunctionData('claimMessage', [ + _from, + _to, + _fee, + _value, + constants.AddressZero, + _calldata, + _nonce + ]); + const signer = await bridgeDeploymentManager.getSigner(); + bridgeDeploymentManager.stashRelayMessage( + l2MessageService.address, + callData, + await signer.getAddress() + ); + } + + + relayMessageTxn = await ( + await l2MessageService.claimMessage( + _from, + _to, + _fee, + _value, + constants.AddressZero, + _calldata, + _nonce, + { + gasPrice: 0, + gasLimit: 10000000 + } + ) + ).wait(); + + } else continue; // Try to decode the SentMessage data to determine what type of cross-chain activity this is. So far, // there are two types: // 1. Bridging ERC20 token // 2. Cross-chain message passing - if (_to === l2TokenBridge.address) { + if (_to.toLowerCase() === l2StandardBridge.address.toLowerCase()) { // Bridging ERC20 token const messageWithoutPrefix = _calldata.slice(2); // strip out the 0x prefix const messageWithoutSigHash = '0x' + messageWithoutPrefix.slice(8); // Bridging ERC20 token - const { l1Token, amount, to, _data } = ethers.utils.defaultAbiCoder.decode( - ['address _nativeToken', 'address _amount', 'uint256 _recipient', 'bytes _tokenMetadata'], + const [ l1Token, amount, to ] = ethers.utils.defaultAbiCoder.decode( + ['address nativeToken', 'uint256 amount', 'address recipient'], messageWithoutSigHash ); console.log( `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Bridged over ${amount} of ${l1Token} to user ${to}` ); - } else if (_to === l2usdcBridge.address) { + } + else if (_to.toLowerCase() === l2USDCBridge.address.toLowerCase()){ + const messageWithoutPrefix = _calldata.slice(2); // strip out the 0x prefix + const messageWithoutSigHash = '0x' + messageWithoutPrefix.slice(8); + const [ to, amount ] = ethers.utils.defaultAbiCoder.decode( + ['address _recipient', 'uint256 _amount'], + messageWithoutSigHash + ); console.log( - `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Bridged USDC` + `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Bridged over ${amount} of USDC.e to user ${to}` ); - } else if (_to === bridgeReceiver.address) { + } + else if (_to.toLowerCase() === bridgeReceiver.address.toLowerCase()) { // Cross-chain message passing const proposalCreatedEvent = relayMessageTxn.events.find( event => event.address === bridgeReceiver.address @@ -107,9 +253,22 @@ export default async function relayLineaMessage( // Execute queued proposal await setNextBaseFeeToZero(bridgeDeploymentManager); - await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); + if(tenderlyLogs) { + const callData = bridgeReceiver.interface.encodeFunctionData('executeProposal', [id]); + const signer = await bridgeDeploymentManager.getSigner(); + + bridgeDeploymentManager.stashRelayMessage( + bridgeReceiver.address, + callData, + await signer.getAddress() + ); + }else{ + await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); + } + console.log( `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Executed bridged proposal ${id}` ); } + return openBridgedProposals; } diff --git a/scenario/utils/relayMantleMessage.ts b/scenario/utils/relayMantleMessage.ts index a4881415f..4c098796c 100644 --- a/scenario/utils/relayMantleMessage.ts +++ b/scenario/utils/relayMantleMessage.ts @@ -10,10 +10,15 @@ function applyL1ToL2Alias(address: string) { return `0x${(BigInt(address) + offset).toString(16)}`; } +function isTenderlyLog(log: any): log is { raw: { topics: string[], data: string } } { + return !!log?.raw?.topics && !!log?.raw?.data; +} + export default async function relayMantleMessage( governanceDeploymentManager: DeploymentManager, bridgeDeploymentManager: DeploymentManager, - startingBlockNumber: number + startingBlockNumber: number, + tenderlyLogs?: any[] ) { const mantleL1CrossDomainMessenger = await governanceDeploymentManager.getContractOrThrow('mantleL1CrossDomainMessenger'); const bridgeReceiver = await bridgeDeploymentManager.getContractOrThrow('bridgeReceiver'); @@ -22,31 +27,64 @@ export default async function relayMantleMessage( const openBridgedProposals: OpenBridgedProposal[] = []; - // Grab all events on the L1CrossDomainMessenger contract since the `startingBlockNumber` const filter = mantleL1CrossDomainMessenger.filters.SentMessage(); - const sentMessageEvents: Log[] = await governanceDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: startingBlockNumber, - toBlock: 'latest', - address: mantleL1CrossDomainMessenger.address, - topics: filter.topics! - }); + let sentMessageEvents: Log[] = []; + + if (tenderlyLogs) { + const topic = mantleL1CrossDomainMessenger.interface.getEventTopic('SentMessage'); + const tenderlyParsed = tenderlyLogs.filter(log => log.raw?.topics?.[0] === topic); + const realLogs = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: startingBlockNumber, + toBlock: 'latest', + address: mantleL1CrossDomainMessenger.address, + topics: filter.topics! + }); + sentMessageEvents = [...realLogs, ...tenderlyParsed]; + } else { + sentMessageEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: startingBlockNumber, + toBlock: 'latest', + address: mantleL1CrossDomainMessenger.address, + topics: filter.topics! + }); + } for (let sentMessageEvent of sentMessageEvents) { - const { args: { target, sender, message, messageNonce, gasLimit } } = mantleL1CrossDomainMessenger.interface.parseLog(sentMessageEvent); + const { args: { target, sender, message, messageNonce } } = isTenderlyLog(sentMessageEvent) + ? mantleL1CrossDomainMessenger.interface.parseLog({ + topics: sentMessageEvent.raw.topics, + data: sentMessageEvent.raw.data + }) + : mantleL1CrossDomainMessenger.interface.parseLog(sentMessageEvent); + const aliasedSigner = await impersonateAddress( bridgeDeploymentManager, applyL1ToL2Alias(mantleL1CrossDomainMessenger.address) ); await setNextBaseFeeToZero(bridgeDeploymentManager); - const relayMessageTxn = await ( + + let relayMessageTxn; + if (tenderlyLogs) { + const callData = l2CrossDomainMessenger.interface.encodeFunctionData( + 'relayMessage', + [messageNonce, sender, target, 0, 0, 0, message] + ); + bridgeDeploymentManager.stashRelayMessage( + l2CrossDomainMessenger.address, + callData, + aliasedSigner.address + ); + } + + relayMessageTxn = await ( await l2CrossDomainMessenger.connect(aliasedSigner).relayMessage( messageNonce, sender, target, 0, 0, - gasLimit, + 0, message, { gasPrice: 0, gasLimit: 7_500_000 } ) @@ -109,9 +147,24 @@ export default async function relayMantleMessage( // Execute queued proposal await setNextBaseFeeToZero(bridgeDeploymentManager); - await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); + + if (tenderlyLogs) { + const callData = bridgeReceiver.interface.encodeFunctionData( + 'executeProposal', + [id] + ); + const signer = await bridgeDeploymentManager.getSigner(); + bridgeDeploymentManager.stashRelayMessage( + bridgeReceiver.address, + callData, + signer.address + ); + } else { + await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); + } console.log( `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Executed bridged proposal ${id}` ); } + return openBridgedProposals; } \ No newline at end of file diff --git a/scenario/utils/relayMessage.ts b/scenario/utils/relayMessage.ts index 8fb7f04b2..c06593c58 100644 --- a/scenario/utils/relayMessage.ts +++ b/scenario/utils/relayMessage.ts @@ -12,83 +12,89 @@ import relayRoninMessage from './relayRoninMessage'; export default async function relayMessage( governanceDeploymentManager: DeploymentManager, bridgeDeploymentManager: DeploymentManager, - startingBlockNumber: number + startingBlockNumber: number, + tenderlyLogs?: any[] ) { const bridgeNetwork = bridgeDeploymentManager.network; + let proposal; switch (bridgeNetwork) { case 'base': - await relayBaseMessage( + return await relayBaseMessage( governanceDeploymentManager, bridgeDeploymentManager, - startingBlockNumber + startingBlockNumber, + tenderlyLogs ); - break; case 'optimism': - await relayOptimismMessage( + return await relayOptimismMessage( governanceDeploymentManager, bridgeDeploymentManager, - startingBlockNumber + startingBlockNumber, + tenderlyLogs ); - break; case 'mantle': - await relayMantleMessage( + return await relayMantleMessage( governanceDeploymentManager, bridgeDeploymentManager, - startingBlockNumber + startingBlockNumber, + tenderlyLogs ); - break; case 'unichain': - await relayUnichainMessage( + proposal = await relayUnichainMessage( governanceDeploymentManager, bridgeDeploymentManager, - startingBlockNumber + startingBlockNumber, + tenderlyLogs ); await relayUnichainCCTPMint( governanceDeploymentManager, bridgeDeploymentManager, - startingBlockNumber + startingBlockNumber, + tenderlyLogs ); - break; + return proposal; case 'polygon': - await relayPolygonMessage( + return await relayPolygonMessage( governanceDeploymentManager, bridgeDeploymentManager, - startingBlockNumber + startingBlockNumber, + tenderlyLogs ); - break; case 'arbitrum': - await relayArbitrumMessage( + proposal = await relayArbitrumMessage( governanceDeploymentManager, bridgeDeploymentManager, - startingBlockNumber + startingBlockNumber, + tenderlyLogs ); await relayArbitrumCCTPMint( governanceDeploymentManager, bridgeDeploymentManager, - startingBlockNumber + startingBlockNumber, + tenderlyLogs ); - break; + return proposal; case 'linea': - await relayLineaMessage( + return await relayLineaMessage( governanceDeploymentManager, bridgeDeploymentManager, - startingBlockNumber + startingBlockNumber, + tenderlyLogs ); - break; case 'scroll': - await relayScrollMessage( + return await relayScrollMessage( governanceDeploymentManager, bridgeDeploymentManager, - startingBlockNumber + startingBlockNumber, + tenderlyLogs ); - break; case 'ronin': - await relayRoninMessage( + return await relayRoninMessage( governanceDeploymentManager, bridgeDeploymentManager, - startingBlockNumber + startingBlockNumber, + tenderlyLogs ); - break; default: throw new Error( `No message relay implementation from ${bridgeNetwork} -> ${governanceDeploymentManager.network}` diff --git a/scenario/utils/relayOptimismMessage.ts b/scenario/utils/relayOptimismMessage.ts index 9261f09ca..f39c105ce 100644 --- a/scenario/utils/relayOptimismMessage.ts +++ b/scenario/utils/relayOptimismMessage.ts @@ -5,6 +5,10 @@ import { BigNumber, ethers } from 'ethers'; import { Log } from '@ethersproject/abstract-provider'; import { OpenBridgedProposal } from '../context/Gov'; +function isTenderlyLog(log: any): log is { raw: { topics: string[], data: string } } { + return !!log?.raw?.topics && !!log?.raw?.data; +} + function applyL1ToL2Alias(address: string) { const offset = BigInt('0x1111000000000000000000000000000000001111'); return `0x${(BigInt(address) + offset).toString(16)}`; @@ -13,7 +17,8 @@ function applyL1ToL2Alias(address: string) { export default async function relayOptimismMessage( governanceDeploymentManager: DeploymentManager, bridgeDeploymentManager: DeploymentManager, - startingBlockNumber: number + startingBlockNumber: number, + tenderlyLogs?: any[] ) { const opL1CrossDomainMessenger = await governanceDeploymentManager.getContractOrThrow('opL1CrossDomainMessenger'); const bridgeReceiver = await bridgeDeploymentManager.getContractOrThrow('bridgeReceiver'); @@ -22,24 +27,68 @@ export default async function relayOptimismMessage( const openBridgedProposals: OpenBridgedProposal[] = []; - // Grab all events on the L1CrossDomainMessenger contract since the `startingBlockNumber` const filter = opL1CrossDomainMessenger.filters.SentMessage(); - const sentMessageEvents: Log[] = await governanceDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: startingBlockNumber, - toBlock: 'latest', - address: opL1CrossDomainMessenger.address, - topics: filter.topics! - }); + let sentMessageEvents: Log[] = []; + + if (tenderlyLogs) { + const topic = opL1CrossDomainMessenger.interface.getEventTopic('SentMessage'); + const tenderlyEvents = tenderlyLogs.filter( + log => log.raw?.topics?.[0] === topic && log.raw?.address?.toLowerCase() === opL1CrossDomainMessenger.address.toLowerCase() + ); + const realEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: startingBlockNumber, + toBlock: 'latest', + address: opL1CrossDomainMessenger.address, + topics: filter.topics! + }); + sentMessageEvents = [...realEvents, ...tenderlyEvents]; + } else { + sentMessageEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: startingBlockNumber, + toBlock: 'latest', + address: opL1CrossDomainMessenger.address, + topics: filter.topics! + }); + } for (let sentMessageEvent of sentMessageEvents) { - const { args: { target, sender, message, messageNonce, gasLimit } } = opL1CrossDomainMessenger.interface.parseLog(sentMessageEvent); + let parsed; + if (isTenderlyLog(sentMessageEvent)) { + parsed = opL1CrossDomainMessenger.interface.parseLog({ + topics: sentMessageEvent.raw.topics, + data: sentMessageEvent.raw.data + }); + } else { + parsed = opL1CrossDomainMessenger.interface.parseLog(sentMessageEvent); + } + + const { target, sender, message, messageNonce, gasLimit } = parsed.args; + const aliasedSigner = await impersonateAddress( bridgeDeploymentManager, applyL1ToL2Alias(opL1CrossDomainMessenger.address) ); await setNextBaseFeeToZero(bridgeDeploymentManager); - const relayMessageTxn = await ( + + let relayMessageTxn; + if (tenderlyLogs) { + const callData = l2CrossDomainMessenger.interface.encodeFunctionData('relayMessage', [ + messageNonce, + sender, + target, + 0, + 0, + message + ]); + bridgeDeploymentManager.stashRelayMessage( + l2CrossDomainMessenger.address, + callData, + aliasedSigner.address + ); + } + + relayMessageTxn = await ( await l2CrossDomainMessenger.connect(aliasedSigner).relayMessage( messageNonce, sender, @@ -105,19 +154,33 @@ export default async function relayOptimismMessage( } else { throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); } - } - // Execute open bridged proposals now that all messages have been bridged - for (let proposal of openBridgedProposals) { - const { eta, id } = proposal; - // Fast forward l2 time - await setNextBlockTimestamp(bridgeDeploymentManager, eta.toNumber() + 1); + // Execute open bridged proposals now that all messages have been bridged + for (let proposal of openBridgedProposals) { + const { eta, id } = proposal; + // Fast forward l2 time + await setNextBlockTimestamp(bridgeDeploymentManager, eta.toNumber() + 1); - // Execute queued proposal - await setNextBaseFeeToZero(bridgeDeploymentManager); - await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); - console.log( - `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Executed bridged proposal ${id}` - ); + // Execute queued proposal + await setNextBaseFeeToZero(bridgeDeploymentManager); + + if (tenderlyLogs) { + const callData = bridgeReceiver.interface.encodeFunctionData('executeProposal', [id]); + const signer = await bridgeDeploymentManager.getSigner(); + + bridgeDeploymentManager.stashRelayMessage( + bridgeReceiver.address, + callData, + signer.address + ); + } else { + await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); + } + console.log( + `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Executed bridged proposal ${id}` + ); + } + + return openBridgedProposals; } -} \ No newline at end of file +} diff --git a/scenario/utils/relayPolygonMessage.ts b/scenario/utils/relayPolygonMessage.ts index deeea4a62..5d05ff2e4 100644 --- a/scenario/utils/relayPolygonMessage.ts +++ b/scenario/utils/relayPolygonMessage.ts @@ -4,8 +4,11 @@ import { executeBridgedProposal } from './bridgeProposal'; import { setNextBaseFeeToZero } from './hreUtils'; import { Contract, ethers } from 'ethers'; import { Log } from '@ethersproject/abstract-provider'; -import {OpenBridgedProposal} from '../context/Gov'; +import { OpenBridgedProposal } from '../context/Gov'; +function isTenderlyLog(log: any): log is { raw: { topics: string[], data: string } } { + return !!log?.raw?.topics && !!log?.raw?.data; +} type BridgeERC20Data = { syncData: string; @@ -39,7 +42,8 @@ function tryDecodeStateSyncedData(stateSyncedData: any): BridgeERC20Data | undef export default async function relayPolygonMessage( governanceDeploymentManager: DeploymentManager, bridgeDeploymentManager: DeploymentManager, - startingBlockNumber: number + startingBlockNumber: number, + tenderlyLogs?: any[] ) { const POLYGON_RECEIVER_ADDRESSS = '0x0000000000000000000000000000000000001001'; const childChainManagerProxyAddress = @@ -60,27 +64,52 @@ export default async function relayPolygonMessage( bridgeDeploymentManager.hre.ethers.provider ); - // grab all events on the StateSender contract since the `startingBlockNumber` + const openBridgedProposals: OpenBridgedProposal[] = []; + const filter = stateSender.filters.StateSynced(); - const stateSyncedEvents: Log[] = await governanceDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: startingBlockNumber, - toBlock: 'latest', - address: stateSender.address, - topics: filter.topics! - }); - - for (let stateSyncedEvent of stateSyncedEvents) { - const { - args: { data: stateSyncedData } - } = stateSender.interface.parseLog(stateSyncedEvent); + let stateSyncedEvents: Log[] = []; + + if (tenderlyLogs) { + const topic = stateSender.interface.getEventTopic('StateSynced'); + const tenderlyEvents = tenderlyLogs.filter( + log => log.raw?.topics?.[0] === topic && log.raw?.address?.toLowerCase() === stateSender.address.toLowerCase() + ); + const realEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: startingBlockNumber, + toBlock: 'latest', + address: stateSender.address, + topics: filter.topics! + }); + stateSyncedEvents = [...realEvents, ...tenderlyEvents]; + } else { + stateSyncedEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: startingBlockNumber, + toBlock: 'latest', + address: stateSender.address, + topics: filter.topics! + }); + } + for (const stateSyncedEvent of stateSyncedEvents) { + let parsed; + if (isTenderlyLog(stateSyncedEvent)) { + parsed = stateSender.interface.parseLog({ + topics: stateSyncedEvent.raw.topics, + data: stateSyncedEvent.raw.data + }); + } else { + parsed = stateSender.interface.parseLog(stateSyncedEvent); + } // Try to decode the StateSynced data to determine what type of cross-chain activity this is. So far, // there are two types: // 1. Bridging ERC20 token // 2. Cross-chain message passing + + const { data: stateSyncedData } = parsed.args; + const maybeBridgeERC20Data = tryDecodeStateSyncedData(stateSyncedData); + if (maybeBridgeERC20Data !== undefined) { - // Bridging ERC20 token const depositSyncType = await childChainManager.DEPOSIT(); const data = ethers.utils.defaultAbiCoder.encode( ['bytes32', 'bytes'], @@ -91,14 +120,24 @@ export default async function relayPolygonMessage( POLYGON_RECEIVER_ADDRESSS ); await setNextBaseFeeToZero(bridgeDeploymentManager); - await( - await childChainManager.connect(polygonReceiverSigner).onStateReceive( - 123, // stateId - data, // data - { gasPrice: 0 } - ) - ).wait(); + if (tenderlyLogs) { + const callData = childChainManager.interface.encodeFunctionData('onStateReceive', [123, data]); + const signer = await bridgeDeploymentManager.getSigner(); + bridgeDeploymentManager.stashRelayMessage( + childChainManager.address, + callData, + signer.address + ); + } else { + await( + await childChainManager.connect(polygonReceiverSigner).onStateReceive( + 123, // stateId + data, // data + { gasPrice: 0 } + ) + ).wait(); + } console.log( `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Bridged over ${maybeBridgeERC20Data.amount} of ${maybeBridgeERC20Data.rootToken} to user ${maybeBridgeERC20Data.user}` ); @@ -110,7 +149,16 @@ export default async function relayPolygonMessage( ); await setNextBaseFeeToZero(bridgeDeploymentManager); - const onStateReceiveTxn = await( + + if (tenderlyLogs) { + const callData = fxChild.interface.encodeFunctionData('onStateReceive', [123, stateSyncedData]); + bridgeDeploymentManager.stashRelayMessage( + fxChild.address, + callData, + polygonReceiverSigner.address + ); + } + const onStateReceiveTxn = await ( await fxChild.connect(polygonReceiverSigner).onStateReceive( 123, // stateId stateSyncedData, // _data @@ -121,12 +169,26 @@ export default async function relayPolygonMessage( const proposalCreatedEvent = onStateReceiveTxn.events.find( event => event.address === bridgeReceiver.address ); - const { args } = bridgeReceiver.interface.parseLog(proposalCreatedEvent); - const proposal = args as unknown as OpenBridgedProposal; - await executeBridgedProposal(bridgeDeploymentManager, proposal); + const { args: { id, eta } } = bridgeReceiver.interface.parseLog(proposalCreatedEvent); + + openBridgedProposals.push({ id, eta }); + if (tenderlyLogs) { + const signer = await bridgeDeploymentManager.getSigner(); + const callData = bridgeReceiver.interface.encodeFunctionData('executeProposal', [id]); + bridgeDeploymentManager.stashRelayMessage( + bridgeReceiver.address, + callData, + await signer.getAddress() + ); + } + else { + await executeBridgedProposal(bridgeDeploymentManager, { id, eta }); + } console.log( - `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Executed bridged proposal ${proposal.id}` + `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Executed bridged proposal ${id}` ); } } + + return openBridgedProposals; } \ No newline at end of file diff --git a/scenario/utils/relayRoninMessage.ts b/scenario/utils/relayRoninMessage.ts index 37c797d3d..2c61ea1ae 100644 --- a/scenario/utils/relayRoninMessage.ts +++ b/scenario/utils/relayRoninMessage.ts @@ -7,10 +7,15 @@ import { OpenBridgedProposal } from '../context/Gov'; const roninChainSelector = '6916147374840168594'; +function isTenderlyLog(log: any): log is { raw: { topics: string[], data: string } } { + return !!log?.raw?.topics && !!log?.raw?.data; +} + export default async function relayRoninMessage( governanceDeploymentManager: DeploymentManager, bridgeDeploymentManager: DeploymentManager, - _: number + startingBlockNumber: number, + tenderlyLogs?: any[] ) { const l1CCIPOnRamp = await governanceDeploymentManager.getContractOrThrow('roninl1CCIPOnRamp'); @@ -18,25 +23,61 @@ export default async function relayRoninMessage( const l2CCIPOffRamp = (await bridgeDeploymentManager.getContractOrThrow('l2CCIPOffRamp')); const bridgeReceiver = (await bridgeDeploymentManager.getContractOrThrow('bridgeReceiver')); const l1TokenAdminRegistry = await governanceDeploymentManager.getContractOrThrow('l1TokenAdminRegistry'); - const l2TokenAdminRegistry = await bridgeDeploymentManager.getContractOrThrow('l2TokenAdminRegistry'); + + const l2TokenAdminRegistry = await bridgeDeploymentManager.existing( + 'l2TokenAdminRegistry', + '0x90e83d532A4aD13940139c8ACE0B93b0DdbD323a', + 'ronin' + ); + const offRampSigner = await impersonateAddress(bridgeDeploymentManager, l2CCIPOffRamp.address); const openBridgedProposals: OpenBridgedProposal[] = []; const filterCCIP = l1CCIPOnRamp.filters.CCIPSendRequested(); - const latestBlock = (await governanceDeploymentManager.hre.ethers.provider.getBlock('latest')).number; - const logsCCIP: Log[] = await governanceDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: latestBlock - 500, - toBlock: 'latest', - address: l1CCIPOnRamp.address, - topics: filterCCIP.topics || [] - }); + let logsCCIP: Log[] = []; + + if (tenderlyLogs) { + const topic = l1CCIPOnRamp.interface.getEventTopic('CCIPSendRequested'); + const tenderlyEvents = tenderlyLogs.filter( + log => log.raw?.topics?.[0] === topic && log.raw?.address?.toLowerCase() === l1CCIPOnRamp.address.toLowerCase() + ); + const latestBlock = (await governanceDeploymentManager.hre.ethers.provider.getBlock('latest')).number; + const realEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: latestBlock - 500, + toBlock: 'latest', + address: l1CCIPOnRamp.address, + topics: filterCCIP.topics || [] + }); + logsCCIP = [...realEvents, ...tenderlyEvents]; + } else { + const latestBlock = (await governanceDeploymentManager.hre.ethers.provider.getBlock('latest')).number; + logsCCIP = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: latestBlock - 500, + toBlock: 'latest', + address: l1CCIPOnRamp.address, + topics: filterCCIP.topics || [] + }); + } let routeReceipt: { events: any[] }; - let routeTx: { wait: () => any }; + for (const log of logsCCIP) { - const parsedLog = l1CCIPOnRamp.interface.parseLog(log); + let parsedLog; + if (isTenderlyLog(log)) { + parsedLog = l1CCIPOnRamp.interface.parseLog({ + topics: log.raw.topics, + data: log.raw.data + }); + } else { + parsedLog = l1CCIPOnRamp.interface.parseLog(log); + } + const internalMsg = parsedLog.args.message; + if (internalMsg.receiver.toLowerCase() !== bridgeReceiver.address.toLowerCase()) { + console.log(`[CCIP L1->L2] Skipping message with receiver ${internalMsg.receiver} not matching bridgeReceiver ${bridgeReceiver.address}`); + continue; + } console.log(`[CCIP L1->L2] Found CCIPSendRequested with messageId=${internalMsg.messageId}`); @@ -57,7 +98,45 @@ export default async function relayRoninMessage( })), }; - routeTx = await l2Router.connect(offRampSigner).routeMessage( + if (tenderlyLogs) { + const callData = l2Router.interface.encodeFunctionData('routeMessage', [ + any2EVMMessage, + 25_000, + 2_000_000, + internalMsg.receiver, + ]); + bridgeDeploymentManager.stashRelayMessage( + l2Router.address, + callData, + offRampSigner.address + ); + + if (internalMsg.tokenAmounts.length) { + for (const tokenTransferData of internalMsg.tokenAmounts) { + const l1TokenPoolAddress = await l1TokenAdminRegistry.getPool(tokenTransferData.token); + const l1TokenPool = new ethers.Contract( + l1TokenPoolAddress, + ['function getRemoteToken(uint64) external view returns (bytes)'], + governanceDeploymentManager.hre.ethers.provider + ); + const l2Token64 = await l1TokenPool.getRemoteToken(roninChainSelector); + const l2TokenAddress = ethers.utils.defaultAbiCoder.decode(['address'], l2Token64)[0]; + const l2TokenPool = await l2TokenAdminRegistry.getPool(l2TokenAddress); + + const mintAmount = tokenTransferData.amount; + const mintCallData = new ethers.utils.Interface([ + 'function mint(address, uint256) external' + ]).encodeFunctionData('mint', [internalMsg.receiver, mintAmount]); + + bridgeDeploymentManager.stashRelayMessage( + l2TokenAddress, + mintCallData, + l2TokenPool + ); + } + } + } + const routeTx = await l2Router.connect(offRampSigner).routeMessage( any2EVMMessage, 25_000, 2_000_000, @@ -71,13 +150,10 @@ export default async function relayRoninMessage( const l1TokenPoolAddress = await l1TokenAdminRegistry.getPool(tokenTransferData.token); const l1TokenPool = new ethers.Contract( l1TokenPoolAddress, - [ - 'function getRemoteToken(uint64) external view returns (bytes)' - ], + ['function getRemoteToken(uint64) external view returns (bytes)'], governanceDeploymentManager.hre.ethers.provider ); const l2Token64 = await l1TokenPool.getRemoteToken(roninChainSelector); - // parse the address from the bytes const l2TokenAddress = ethers.utils.defaultAbiCoder.decode(['address'], l2Token64)[0]; const l2TokenPool = await l2TokenAdminRegistry.getPool(l2TokenAddress); const l2Token = new ethers.Contract( @@ -134,12 +210,41 @@ export default async function relayRoninMessage( } } + if (tenderlyLogs) { + const proposalFilter = bridgeReceiver.filters.ProposalCreated(); + const proposalEvents = await bridgeDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: 'latest', + toBlock: 'latest', + address: bridgeReceiver.address, + topics: proposalFilter.topics + }); + + for (let event of proposalEvents) { + const { + args: { id, eta }, + } = bridgeReceiver.interface.parseLog(event); + openBridgedProposals.push({ id, eta }); + } + } + for (const proposal of openBridgedProposals) { const { id, eta } = proposal; await setNextBlockTimestamp(bridgeDeploymentManager, eta.toNumber() + 1); await setNextBaseFeeToZero(bridgeDeploymentManager); - await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); + if (tenderlyLogs) { + const callData = bridgeReceiver.interface.encodeFunctionData('executeProposal', [id]); + const signer = await bridgeDeploymentManager.getSigner(); + bridgeDeploymentManager.stashRelayMessage( + bridgeReceiver.address, + callData, + await signer.getAddress() + ); + } else { + await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); + } console.log(`[CCIP L2] Executed bridged proposal ${id.toString()}`); } -} + + return openBridgedProposals; +} \ No newline at end of file diff --git a/scenario/utils/relayScrollMessage.ts b/scenario/utils/relayScrollMessage.ts index 4b7672778..d4555a765 100644 --- a/scenario/utils/relayScrollMessage.ts +++ b/scenario/utils/relayScrollMessage.ts @@ -16,10 +16,15 @@ function applyL1ToL2Alias(address: string) { return `0x${(BigInt(address) + offset).toString(16)}`; } +function isTenderlyLog(log: any): log is { raw: { topics: string[], data: string } } { + return !!log?.raw?.topics && !!log?.raw?.data; +} + export default async function relayScrollMessage( governanceDeploymentManager: DeploymentManager, bridgeDeploymentManager: DeploymentManager, - startingBlockNumber: number + startingBlockNumber: number, + tenderlyLogs?: any[] ) { const scrollMessenger = await governanceDeploymentManager.getContractOrThrow( 'scrollMessenger' @@ -35,16 +40,41 @@ export default async function relayScrollMessage( // Grab all events on the L1CrossDomainMessenger contract since the `startingBlockNumber` const filter = scrollMessenger.filters.SentMessage(); - const messageSentEvents: Log[] = await governanceDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: startingBlockNumber, - toBlock: 'latest', - address: scrollMessenger.address, - topics: filter.topics! - }); + let messageSentEvents: Log[] = []; + + if (tenderlyLogs) { + const topic = scrollMessenger.interface.getEventTopic('SentMessage'); + const tenderlyEvents = tenderlyLogs.filter( + log => log.raw?.topics?.[0] === topic && log.raw?.address?.toLowerCase() === scrollMessenger.address.toLowerCase() + ); + const realEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: startingBlockNumber, + toBlock: 'latest', + address: scrollMessenger.address, + topics: filter.topics! + }); + messageSentEvents = [...realEvents, ...tenderlyEvents]; + } else { + messageSentEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: startingBlockNumber, + toBlock: 'latest', + address: scrollMessenger.address, + topics: filter.topics! + }); + } + for (let messageSentEvent of messageSentEvents) { - const { - args: { sender, target, value, messageNonce, gasLimit, message } - } = scrollMessenger.interface.parseLog(messageSentEvent); + let parsed; + if (isTenderlyLog(messageSentEvent)) { + parsed = scrollMessenger.interface.parseLog({ + topics: messageSentEvent.raw.topics, + data: messageSentEvent.raw.data + }); + } else { + parsed = scrollMessenger.interface.parseLog(messageSentEvent); + } + + const { sender, target, value, messageNonce, gasLimit, message } = parsed.args; await setNextBaseFeeToZero(bridgeDeploymentManager); @@ -59,9 +89,18 @@ export default async function relayScrollMessage( bridgeDeploymentManager, applyL1ToL2Alias(scrollMessenger.address) ); - } + } - const relayMessageTxn = await ( + let relayMessageTxn; + if (tenderlyLogs) { + const callData = l2Messenger.interface.encodeFunctionData('relayMessage', [sender, target, value, messageNonce, message]); + bridgeDeploymentManager.stashRelayMessage( + l2Messenger.address, + callData, + aliasAccount.address + ); + } + relayMessageTxn = await ( await l2Messenger.connect(aliasAccount).relayMessage( sender, target, @@ -147,9 +186,21 @@ export default async function relayScrollMessage( // Execute queued proposal await setNextBaseFeeToZero(bridgeDeploymentManager); - await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); + if (tenderlyLogs) { + const callData = bridgeReceiver.interface.encodeFunctionData('executeProposal', [id]); + const signer = await bridgeDeploymentManager.getSigner(); + bridgeDeploymentManager.stashRelayMessage( + bridgeReceiver.address, + callData, + signer.address + ); + } else { + await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); + } console.log( `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Executed bridged proposal ${id}` ); } + + return openBridgedProposals; } diff --git a/scenario/utils/relayUnichainMessage.ts b/scenario/utils/relayUnichainMessage.ts index 88bb377a1..818f17f53 100644 --- a/scenario/utils/relayUnichainMessage.ts +++ b/scenario/utils/relayUnichainMessage.ts @@ -10,10 +10,15 @@ function applyL1ToL2Alias(address: string) { return `0x${(BigInt(address) + offset).toString(16)}`; } +function isTenderlyLog(log: any): log is { raw: { topics: string[], data: string } } { + return !!log?.raw?.topics && !!log?.raw?.data; +} + export async function relayUnichainMessage( governanceDeploymentManager: DeploymentManager, bridgeDeploymentManager: DeploymentManager, - startingBlockNumber: number + startingBlockNumber: number, + tenderlyLogs?: any[] ) { const unichainL1CrossDomainMessenger = await governanceDeploymentManager.getContractOrThrow('unichainL1CrossDomainMessenger'); const bridgeReceiver = await bridgeDeploymentManager.getContractOrThrow('bridgeReceiver'); @@ -24,22 +29,58 @@ export async function relayUnichainMessage( // Grab all events on the L1CrossDomainMessenger contract since the `startingBlockNumber` const filter = unichainL1CrossDomainMessenger.filters.SentMessage(); - const sentMessageEvents: Log[] = await governanceDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: startingBlockNumber, - toBlock: 'latest', - address: unichainL1CrossDomainMessenger.address, - topics: filter.topics! - }); + let sentMessageEvents: Log[] = []; + + if (tenderlyLogs) { + const topic = unichainL1CrossDomainMessenger.interface.getEventTopic('SentMessage'); + const tenderlyEvents = tenderlyLogs.filter( + log => log.raw?.topics?.[0] === topic && log.raw?.address?.toLowerCase() === unichainL1CrossDomainMessenger.address.toLowerCase() + ); + const realEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: startingBlockNumber, + toBlock: 'latest', + address: unichainL1CrossDomainMessenger.address, + topics: filter.topics! + }); + sentMessageEvents = [...realEvents, ...tenderlyEvents]; + } else { + sentMessageEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: startingBlockNumber, + toBlock: 'latest', + address: unichainL1CrossDomainMessenger.address, + topics: filter.topics! + }); + } for (let sentMessageEvent of sentMessageEvents) { - const { args: { target, sender, message, messageNonce, gasLimit } } = unichainL1CrossDomainMessenger.interface.parseLog(sentMessageEvent); + let parsed; + if (isTenderlyLog(sentMessageEvent)) { + parsed = unichainL1CrossDomainMessenger.interface.parseLog({ + topics: sentMessageEvent.raw.topics, + data: sentMessageEvent.raw.data + }); + } else { + parsed = unichainL1CrossDomainMessenger.interface.parseLog(sentMessageEvent); + } + + const { sender, target, message, messageNonce, gasLimit } = parsed.args; const aliasedSigner = await impersonateAddress( bridgeDeploymentManager, applyL1ToL2Alias(unichainL1CrossDomainMessenger.address) ); await setNextBaseFeeToZero(bridgeDeploymentManager); - const relayMessageTxn = await ( + + let relayMessageTxn: { events: any[] }; + if (tenderlyLogs) { + const callData = l2CrossDomainMessenger.interface.encodeFunctionData('relayMessage', [messageNonce, sender, target, 0, 0, message]); + bridgeDeploymentManager.stashRelayMessage( + l2CrossDomainMessenger.address, + callData, + aliasedSigner.address + ); + } + relayMessageTxn = await ( await l2CrossDomainMessenger.connect(aliasedSigner).relayMessage( messageNonce, sender, @@ -50,6 +91,7 @@ export async function relayUnichainMessage( { gasPrice: 0, gasLimit: 7_500_000 } ) ).wait(); + // Try to decode the SentMessage data to determine what type of cross-chain activity this is. So far, // there are two types: @@ -90,16 +132,37 @@ export async function relayUnichainMessage( } } else if (target === bridgeReceiver.address) { // Cross-chain message passing - const proposalCreatedEvent = relayMessageTxn.events.find(event => event.address === bridgeReceiver.address); - const { args: { id, eta } } = bridgeReceiver.interface.parseLog(proposalCreatedEvent); + if (!tenderlyLogs && relayMessageTxn) { + const proposalCreatedEvent = relayMessageTxn.events.find(event => event.address === bridgeReceiver.address); + const { args: { id, eta } } = bridgeReceiver.interface.parseLog(proposalCreatedEvent); - // Add the proposal to the list of open bridged proposals to be executed after all the messages have been relayed - openBridgedProposals.push({ id, eta }); + // Add the proposal to the list of open bridged proposals to be executed after all the messages have been relayed + openBridgedProposals.push({ id, eta }); + } } else { throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); } } + // Handle proposal creation for tenderly + if (tenderlyLogs) { + // We need to check for ProposalCreated events since we don't get them in the loop above + const proposalFilter = bridgeReceiver.filters.ProposalCreated(); + const proposalEvents = await bridgeDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: 'latest', + toBlock: 'latest', + address: bridgeReceiver.address, + topics: proposalFilter.topics + }); + + for (let event of proposalEvents) { + const { + args: { id, eta }, + } = bridgeReceiver.interface.parseLog(event); + openBridgedProposals.push({ id, eta }); + } + } + // Execute open bridged proposals now that all messages have been bridged for (let proposal of openBridgedProposals) { const { eta, id } = proposal; @@ -108,33 +171,77 @@ export async function relayUnichainMessage( // Execute queued proposal await setNextBaseFeeToZero(bridgeDeploymentManager); - await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); + if (tenderlyLogs) { + const signer = await bridgeDeploymentManager.getSigner(); + const callData = bridgeReceiver.interface.encodeFunctionData('executeProposal', [id]); + bridgeDeploymentManager.stashRelayMessage( + bridgeReceiver.address, + callData, + await signer.getAddress() + ); + } else { + await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); + } console.log( `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Executed bridged proposal ${id}` ); } + + return openBridgedProposals; } export async function relayUnichainCCTPMint( governanceDeploymentManager: DeploymentManager, bridgeDeploymentManager: DeploymentManager, - startingBlockNumber: number + startingBlockNumber: number, + tenderlyLogs?: any[] ){ + // CCTP relay // L1 contracts const L1MessageTransmitter = await governanceDeploymentManager.getContractOrThrow('CCTPMessageTransmitter'); // L2 TokenMinter const TokenMinter = await bridgeDeploymentManager.getContractOrThrow('TokenMinter'); - const depositForBurnEvents: Log[] = await governanceDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: startingBlockNumber, - toBlock: 'latest', - address: L1MessageTransmitter.address, - topics: [utils.id('MessageSent(bytes)')] - }); + let depositForBurnEvents: Log[] = []; + + if (tenderlyLogs) { + const messageSentTopic = utils.id('MessageSent(bytes)'); + + const tenderlyEvents = tenderlyLogs.filter(log => + log.raw?.topics?.[0] === messageSentTopic && + log.raw?.address?.toLowerCase() === L1MessageTransmitter.address.toLowerCase() + ); + + const realEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: startingBlockNumber, + toBlock: 'latest', + address: L1MessageTransmitter.address, + topics: [messageSentTopic] + }); + + depositForBurnEvents = [...realEvents, ...tenderlyEvents]; + } else { + depositForBurnEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: startingBlockNumber, + toBlock: 'latest', + address: L1MessageTransmitter.address, + topics: [utils.id('MessageSent(bytes)')] + }); + } // Decode message body - const burnEvents = depositForBurnEvents.map(({ data }) => { + console.log(`Found ${depositForBurnEvents.length} CCTP deposit for burn events`); + + const burnEvents = depositForBurnEvents.map((event) => { + let data; + + if (isTenderlyLog(event)) { + data = event.raw.data; + } else { + data = event.data; + } + const dataBytes = utils.arrayify(data); // Since data is encodePacked, so can't simply decode via AbiCoder.decode const offset = 64; @@ -224,9 +331,17 @@ export async function relayUnichainCCTPMint( }); await setNextBaseFeeToZero(bridgeDeploymentManager); - - await ( - await localTokenMessengerSigner.sendTransaction(transactionRequest) - ).wait(); + if( tenderlyLogs ) { + const callData = TokenMinter.interface.encodeFunctionData('mint', [sourceDomain, burnToken, utils.getAddress(recipient), amount]); + bridgeDeploymentManager.stashRelayMessage( + TokenMinter.address, + callData, + localTokenMessengerSigner.address + ); + } else { + await ( + await localTokenMessengerSigner.sendTransaction(transactionRequest) + ).wait(); + } } -} +} \ No newline at end of file diff --git a/scenario/utils/scenarioHelper.ts b/scenario/utils/scenarioHelper.ts index 5b05102f9..cc5d9fee4 100644 --- a/scenario/utils/scenarioHelper.ts +++ b/scenario/utils/scenarioHelper.ts @@ -25,7 +25,10 @@ const config = { withdrawBase: 1000, withdrawAsset: 3000, withdrawBase1: 1000, - withdrawAsset1: 1000, + withdrawAsset1: 3000, + withdrawCollateral: 100, + transferCollateral: 100, + supplyCollateral: 100 }; export function getConfigForScenario(ctx: CometContext) { @@ -59,6 +62,7 @@ export function getConfigForScenario(ctx: CometContext) { if (ctx.world.base.network === 'mainnet' && ctx.world.base.deployment === 'weth') { config.liquidationNumerator = 60; + config.liquidationBase = 10000; } if (ctx.world.base.network === 'mainnet' && ctx.world.base.deployment === 'usds') { @@ -96,8 +100,8 @@ export function getConfigForScenario(ctx: CometContext) { if (ctx.world.base.network === 'ronin' && ctx.world.base.deployment === 'weth') { config.transferBase = 10; - config.transferAsset = 100000; - config.transferAsset1 = 100000; + config.transferAsset = 200000; + config.transferAsset1 = 200000; config.rewardsAsset = 1000000; config.rewardsBase = 200; config.withdrawBase = 10; @@ -135,6 +139,32 @@ export function getConfigForScenario(ctx: CometContext) { config.bulkerAsset1 = 10; } + if (ctx.world.base.network === 'linea' && ctx.world.base.deployment === 'usdc') { + config.bulkerAsset = 500; + config.bulkerAsset1 = 500; + config.supplyCollateral = 10; + config.transferCollateral = 10; + config.withdrawCollateral = 10; + } + + if (ctx.world.base.network === 'linea' && ctx.world.base.deployment === 'usdt') { + config.bulkerBase = 10000; + config.bulkerAsset = 500; + config.bulkerAsset1 = 100; + config.supplyCollateral = 10; + config.transferCollateral = 10; + config.withdrawCollateral = 10; + } + + if (ctx.world.base.network === 'linea' && ctx.world.base.deployment === 'weth') { + config.liquidationBase = 1000; + config.rewardsAsset = 1000; + config.rewardsBase = 50; + config.supplyCollateral = 10; + config.transferCollateral = 10; + config.withdrawCollateral = 10; + } + if (ctx.world.base.network === 'unichain' && ctx.world.base.deployment === 'weth') { config.liquidationBase = 1000; config.liquidationBase1 = 350; diff --git a/scripts/clone-multisig.ts b/scripts/clone-multisig.ts index fc6c6c7e7..f0faeded8 100644 --- a/scripts/clone-multisig.ts +++ b/scripts/clone-multisig.ts @@ -32,7 +32,7 @@ async function main() { const wallet = new ethers.Wallet(process.env.ETH_PK!, hreDST.ethers.provider); const signer: SignerWithAddress = wallet as unknown as SignerWithAddress; - const ethAdapter = new EthersAdapter({ ethers: hreDST.ethers, signerOrProvider: signer }); + const ethAdapter = new EthersAdapter({ ethers: hreDST.ethers as any, signerOrProvider: signer }); const safeFactory = await SafeFactory.create({ ethAdapter: ethAdapter }); const safeSdk = await safeFactory.deploySafe({ safeAccountConfig }); console.log(safeSdk); diff --git a/src/deploy/Network.ts b/src/deploy/Network.ts index 2d4a80f14..e20e4c04a 100644 --- a/src/deploy/Network.ts +++ b/src/deploy/Network.ts @@ -27,7 +27,7 @@ export async function cloneGov( const COMP = await deploymentManager.clone('COMP', clone.comp, [admin.address]); - const governorImpl = await deploymentManager.clone('governor:implementation', clone.governorBravoImpl, []); + const governorImpl = await deploymentManager.clone('governor:implementation', clone.governorBravoImpl, [], 'mainnet', true); const governorProxy = await deploymentManager.clone('governor', clone.governorBravo, [ timelock.address, COMP.address, diff --git a/src/deploy/index.ts b/src/deploy/index.ts index b3875fea0..cf185678a 100644 --- a/src/deploy/index.ts +++ b/src/deploy/index.ts @@ -5,6 +5,9 @@ export { cloneGov, deployNetworkComet as deployComet, sameAddress } from './Netw export { getConfiguration, getConfigurationStruct } from './NetworkConfiguration'; export { exp, getBlock, wait } from '../../test/helpers'; export { debug } from '../../plugins/deployment_manager/Utils'; +import { writeFileSync, mkdirSync } from 'fs'; +import path from 'path'; + export interface ProtocolConfiguration { name?: string; @@ -61,7 +64,8 @@ export type Proposal = [ string[], // targets BigNumberish[], // values string[], // calldatas - string // description + string, // description + string[] // signatures ]; export type TestnetProposal = [ string[], // targets @@ -103,11 +107,15 @@ export const WHALES = { '0x3b3501f6778Bfc56526cF2aC33b78b2fDBE4bc73', // solvBTC.BBN whale '0x8bc93498b861fd98277c3b51d240e7E56E48F23c', // solvBTC.BBN whale '0xD5cf704dC17403343965b4F9cd4D7B5e9b20CC52', // solvBTC.BBN whale + '0x3154Cf16ccdb4C6d922629664174b904d80F2C35', // cbETH whale + '0x5f556Cc5C294D7D3EfFaFFeb0B1195256a7A19D7', // EIGEN whale + '0xdCa0A2341ed5438E06B9982243808A76B9ADD6d0', // woETH whale ], polygon: [ '0xF977814e90dA44bFA03b6295A0616a897441aceC', // USDT whale '0x2093b4281990a568c9d588b8bce3bfd7a1557ebd', // WETH whale '0xe50fA9b3c56FfB159cB0FCA61F5c9D750e8128c8', // WETH whale + '0x62ac55b745F9B08F1a81DCbbE630277095Cf4Be1', // WETH whale '0xd814b26554204245a30f8a42c289af582421bf04', // WBTC whale '0x167384319b41f7094e62f7506409eb38079abff8', // WMATIC whale '0x6d80113e533a2C0fe82EaBD35f1875DcEA89Ea97', // WMATIC whale @@ -139,6 +147,7 @@ export const WHALES = { '0x3bf93770f2d4a794c3d9EBEfBAeBAE2a8f09A5E5', // cbETH whale '0xcf3D55c10DB69f28fD1A75Bd73f3D8A2d9c595ad', // cbETH whale '0xb125E6687d4313864e53df431d5425969c15Eb2F', // cbETH whale + '0x1539A4611f16a139891c14365Cab86599F3A8AFC', // tBTC whale ], scroll: [ '0xaaaaAAAACB71BF2C8CaE522EA5fa455571A74106', // USDC whale @@ -167,6 +176,22 @@ export const WHALES = { '0x7Ae0911198AD568E1FE4af3cf81e36A29983778f', // wstETH whale '0x4B2cf5C94A88934870B523983B22e6d2dd1b6577', // wstETH whale ], + linea: [ + '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f', // ETH whale + '0x9be5e24F05bBAfC28Da814bD59284878b388a40f', // WBTC whale + '0xCeEd853798ff1c95cEB4dC48f68394eb7A86A782', // wstETH whale + '0x03dDD23943b3C698442C5f2841eae70058DbAb8B', // wstETH whale + '0x0180912F869065c7a44617Cd4c288bE6Bce5d192', // wstETH whale + '0x7160570BB153Edd0Ea1775EC2b2Ac9b65F1aB61B', // wstETH whale + '0x0684FC172a0B8e6A65cF4684eDb2082272fe9050', // ezETH whale + '0x3A0ee670EE34D889B52963bD20728dEcE4D9f8FE', // ezETH whale + '0x96d6cE4e83dB947fF6bD1Ab0B377F23cd5D9ec2D', // ezETH whale + '0x8a90D208666Deec08123444F67Bf5B1836074a67', // ezETH whale + '0x935EfCBeFc1dF0541aFc3fE145134f8c9a0beB89', // ezETH whale + '0x6a72F4F191720c411Cd1fF6A5EA8DeDEC3A64771', // USDT whale + '0x2c7118c4C88B9841FCF839074c26Ae8f035f2921', // COMP whale + '0x8D38A3d6B3c3B7d96D6536DA7Eef94A9d7dbC991', // wstETH whale + ], ronin: [ '0x41058bcc968f809e9dbb955f402de150a3e5d1b5', '0x68a57af44503da4223bb6f494de012410fda1ae0', @@ -179,7 +204,9 @@ export const WHALES = { '0x5b714f5ce0a09ab2fec8362dc1c254c7b7d6e6bd', '0x0cf8ff40a508bdbc39fbe1bb679dcba64e65c7df', '0x2ecb08f87f075b5769fe543d0e52e40140575ea7', - '0x05b0bb3c1c320b280501b86706c3551995bc8571' + '0x05b0bb3c1c320b280501b86706c3551995bc8571', + '0x392d372f2a51610e9ac5b741379d5631ca9a1c7f', // USDC whale + '0x245db945c485b68fdc429e4f7085a1761aa4d45d', // WETH whale ] }; @@ -213,23 +240,57 @@ export async function testnetProposal(actions: ProposalAction[], description: st } -export async function proposal(actions: ProposalAction[], description: string): Promise { - const targets = [], - values = [], - calldatas = []; +export async function proposal( + actions: ProposalAction[], + description: string +): Promise { + const targets = []; + const values = []; + const calldatas = []; + const signatures = []; + for (const action of actions) { - if (action['contract']) { + if ('contract' in action) { const { contract, value, signature, args } = action as ContractAction; targets.push(contract.address); values.push(value ?? 0); - calldatas.push(utils.id(signature).slice(0, 10) + (await calldata(contract.populateTransaction[signature](...args))).slice(2)); + calldatas.push( + utils + .id(signature) + .slice(0, 10) + + (await calldata(contract.populateTransaction[signature](...args))).slice(2) + ); + signatures.push(''); } else { - const { target, value, signature, calldata } = action as TargetAction; + const { target, value, signature, calldata: cd } = action as TargetAction; targets.push(target); values.push(value ?? 0); - calldatas.push(utils.id(signature).slice(0, 10) + calldata.slice(2)); + calldatas.push(utils.id(signature).slice(0, 10) + cd.slice(2)); + signatures.push(''); } } - return [targets, values, calldatas, description]; -} \ No newline at end of file + const fullProposal: Proposal = [targets, values, calldatas, description, signatures]; + + stashProposal(fullProposal); + fullProposal.pop(); + return fullProposal; +} + +function stashProposal(prop: Proposal) { + try { + const cacheDir = path.resolve(__dirname, '../../', 'cache'); + mkdirSync(cacheDir, { recursive: true }); + const file = path.join(cacheDir, 'currentProposal.json'); + + const safeJson = JSON.stringify(prop, (_key, value) => + typeof value === 'bigint' ? value.toString() : value, + 2 + ); + + writeFileSync(file, safeJson); + console.log(`Proposal cached ${file}`); + } catch (e) { + console.warn('Failed to cache proposal:', e); + } +} diff --git a/tasks/deployment_manager/task.ts b/tasks/deployment_manager/task.ts index 89446812c..7991cf905 100644 --- a/tasks/deployment_manager/task.ts +++ b/tasks/deployment_manager/task.ts @@ -10,7 +10,7 @@ import hreForBase from '../../plugins/scenario/utils/hreForBase'; async function getForkEnv(env: HardhatRuntimeEnvironment, deployment: string): Promise { const base = env.config.scenario.bases.find(b => b.network == env.network.name && b.deployment == deployment); if (!base) { - throw new Error(`No fork spec for ${env.network.name}`); + throw new Error(`No fork spec for ${env.network.name}-${deployment}`); } return await hreForBase(base); } @@ -29,8 +29,10 @@ async function runMigration( prepare: boolean, enact: boolean, migration: Migration, - overwrite: boolean + overwrite: boolean, + tenderly: boolean = false ) { + deploymentManager.cleanCache(); let artifact: T = await deploymentManager.readArtifact(migration); if (prepare) { if (artifact && !overwrite) { @@ -51,9 +53,24 @@ async function runMigration( } if (enact) { - console.log('Running enactment step with artifact...', artifact); - await migration.actions.enact(deploymentManager, govDeploymentManager, artifact); + + const { + governor, + timelock + } = await govDeploymentManager.getContracts(); + + await migration.actions.enact( + deploymentManager, + govDeploymentManager, + artifact + ); console.log('Enactment complete'); + + if (tenderly) { + const { tenderlyExecute } = await import('../../scenario/utils'); + await tenderlyExecute(govDeploymentManager, deploymentManager, governor, timelock); + } + await govDeploymentManager.cleanCache(); } } @@ -171,11 +188,29 @@ task('migrate', 'Runs migration') .addFlag('enact', 'enacts migration [implies prepare]') .addFlag('noEnacted', 'do not write enacted to the migration script') .addFlag('simulate', 'only simulates the blockchain effects') + .addFlag('tenderly', 'use tenderly to simulate the migration') .addFlag('overwrite', 'overwrites artifact if exists, fails otherwise') .setAction( - async ({ migration: migrationName, prepare, enact, noEnacted, simulate, overwrite, deployment, impersonate }, env) => { + async ( + { + migration: migrationName, + prepare, + enact, + noEnacted, + simulate, + tenderly, + overwrite, + deployment, + impersonate, + }, + env + ) => { + const origNetwork = env.network.name; + const maybeForkEnv = simulate ? await getForkEnv(env, deployment) : env; - const network = env.network.name; + + + const network = origNetwork; const dm = new DeploymentManager( network, deployment, @@ -183,8 +218,10 @@ task('migrate', 'Runs migration') { writeCacheToDisk: !simulate || overwrite, // Don't write to disk when simulating, unless overwrite is set verificationStrategy: 'eager', // We use eager here to verify contracts right after they are deployed - } + saveBytecode: tenderly, // Save bytecode to cache if tenderly is enabled + }, ); + await dm.spider(); let governanceDm: DeploymentManager; @@ -201,7 +238,8 @@ task('migrate', 'Runs migration') { writeCacheToDisk: !simulate || overwrite, // Don't write to disk when simulating, unless overwrite is set verificationStrategy: 'eager', // We use eager here to verify contracts right after they are deployed - } + saveBytecode: tenderly + }, ); await governanceDm.spider(); } else { @@ -222,6 +260,7 @@ task('migrate', 'Runs migration') } const migrationPath = `${__dirname}/../../deployments/${network}/${deployment}/migrations/${migrationName}.ts`; + console.log(`Loading migration from ${migrationPath}`); const [migration] = await loadMigrations([migrationPath]); if (!migration) { throw new Error(`Unknown migration for network ${network}/${deployment}: \`${migrationName}\`.`); @@ -230,7 +269,7 @@ task('migrate', 'Runs migration') prepare = true; } - await runMigration(dm, governanceDm, prepare, enact, migration, overwrite); + await runMigration(dm, governanceDm, prepare, enact, migration, overwrite, tenderly); if (enact && !noEnacted) { await writeEnacted(migration, dm, true); diff --git a/tsconfig.json b/tsconfig.json index 5fd29a124..c81b75946 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,15 +1,45 @@ -{ + { "compilerOptions": { "target": "es2021", "module": "commonjs", + "esModuleInterop": true, "outDir": "dist", + "moduleResolution": "node", - "declaration": true + "declaration": true, + "baseUrl": ".", + "paths": { + + "@nomicfoundation/hardhat-ethers": [ + "node_modules/@nomiclabs/hardhat-ethers" + ], + "@nomicfoundation/hardhat-ethers/*": [ + "node_modules/@nomiclabs/hardhat-ethers/*" + ], + "@nomicfoundation/hardhat-ethers/signers": [ + "node_modules/@nomiclabs/hardhat-ethers/signers" + ] + }, + "types": [ + "node", + "chai", + "mocha", + "hardhat/config", + "@nomiclabs/hardhat-ethers", + "@nomiclabs/hardhat-etherscan", + "./types/tenderly" + ], + "skipLibCheck": true }, - "include": ["./scripts", "./test", "./tasks", "./plugins", "./scenario"], - "files": [ - "./index.ts", - "./hardhat.config.ts", + + "include": [ + "hardhat.config.ts", + "scripts", + "tasks", + "plugins", + "scenario", + "test", + "types/**/*.d.ts" ] } diff --git a/types/tenderly.d.ts b/types/tenderly.d.ts new file mode 100644 index 000000000..ddae80c6d --- /dev/null +++ b/types/tenderly.d.ts @@ -0,0 +1,61 @@ +import 'hardhat/types/runtime'; +import 'hardhat/config'; +import 'hardhat/types/runtime'; + +declare module 'hardhat/types/runtime' { + interface HardhatRuntimeEnvironment { + tenderly?: any; + tenderlyNetwork?: any; + } +} + +declare module 'hardhat/config' { + interface TenderlyConfig { + project?: string; + username?: string; + accessKey?: string; + privateVerification?: boolean; + } + + interface ScenarioConfig { + bases: { + name: string; + network: string; + deployment: string; + allocation?: number; + auxiliaryBase?: string; + }[]; + } + + interface HardhatUserConfig { + tenderly?: TenderlyConfig; + scenario: ScenarioConfig; + } + interface HardhatConfig { + tenderly: TenderlyConfig; + scenario: ScenarioConfig; + } +} + +declare module '@nomicfoundation/hardhat-ethers/types' { + export interface Libraries { + [libraryName: string]: string; + } +} + + +declare module '@nomicfoundation/hardhat-ethers' { + export * from '@nomiclabs/hardhat-ethers'; +} + +declare module '@nomicfoundation/hardhat-ethers/signers' { + export * from '@nomiclabs/hardhat-ethers/signers'; +} + + +declare module 'hardhat/types/runtime' { + interface HardhatRuntimeEnvironment { + upgrades?: any; + defender?: any; + } +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 6f78aca3d..1a787af0b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,36 +2,494 @@ # yarn lockfile v1 +"@adraffy/ens-normalize@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" + integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== + "@arbitrum/sdk@^3.1.2": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@arbitrum/sdk/-/sdk-3.1.2.tgz#c1ded298778c141b6d8d0342a507a4f94af02757" - integrity sha512-QcS5t6GDCLyY+u0WaYPIjBd2U9hmDbzGc8gLMyiUxpP7w4bOWs6ZGBGUw2N6oLOMLI5IEq9ZbRZEC/Ejsy/URg== + version "3.7.3" + resolved "https://registry.yarnpkg.com/@arbitrum/sdk/-/sdk-3.7.3.tgz#329f07bd1006c36abc138979406a5dc465a5370d" + integrity sha512-7nyPm7032+RyjfIFpJf7EKN6EQTtjEzGGemz6NgFzEFLmKj1q+QMRVj9yYKVjIM2lPMKh7Qv+DX6emsxy/5FdQ== dependencies: "@ethersproject/address" "^5.0.8" "@ethersproject/bignumber" "^5.1.1" "@ethersproject/bytes" "^5.0.8" + async-mutex "^0.4.0" ethers "^5.1.0" -"@babel/code-frame@^7.0.0": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" - integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== +"@aws-crypto/crc32@5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/crc32/-/crc32-5.2.0.tgz#cfcc22570949c98c6689cfcbd2d693d36cdae2e1" + integrity sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg== + dependencies: + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + tslib "^2.6.2" + +"@aws-crypto/sha256-browser@5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz#153895ef1dba6f9fce38af550e0ef58988eb649e" + integrity sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw== + dependencies: + "@aws-crypto/sha256-js" "^5.2.0" + "@aws-crypto/supports-web-crypto" "^5.2.0" + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + "@aws-sdk/util-locate-window" "^3.0.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.6.2" + +"@aws-crypto/sha256-js@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-js/-/sha256-js-1.2.2.tgz#02acd1a1fda92896fc5a28ec7c6e164644ea32fc" + integrity sha512-Nr1QJIbW/afYYGzYvrF70LtaHrIRtd4TNAglX8BvlfxJLZ45SAmueIKYl5tWoNBPzp65ymXGFK0Bb1vZUpuc9g== + dependencies: + "@aws-crypto/util" "^1.2.2" + "@aws-sdk/types" "^3.1.0" + tslib "^1.11.1" + +"@aws-crypto/sha256-js@5.2.0", "@aws-crypto/sha256-js@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz#c4fdb773fdbed9a664fc1a95724e206cf3860042" + integrity sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA== + dependencies: + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + tslib "^2.6.2" + +"@aws-crypto/supports-web-crypto@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz#a1e399af29269be08e695109aa15da0a07b5b5fb" + integrity sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg== + dependencies: + tslib "^2.6.2" + +"@aws-crypto/util@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@aws-crypto/util/-/util-1.2.2.tgz#b28f7897730eb6538b21c18bd4de22d0ea09003c" + integrity sha512-H8PjG5WJ4wz0UXAFXeJjWCW1vkvIJ3qUUD+rGRwJ2/hj+xT58Qle2MTql/2MGzkU+1JLAFuR6aJpLAjHwhmwwg== dependencies: - "@babel/highlight" "^7.18.6" + "@aws-sdk/types" "^3.1.0" + "@aws-sdk/util-utf8-browser" "^3.0.0" + tslib "^1.11.1" -"@babel/helper-validator-identifier@^7.18.6": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" - integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== +"@aws-crypto/util@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/util/-/util-5.2.0.tgz#71284c9cffe7927ddadac793c14f14886d3876da" + integrity sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ== + dependencies: + "@aws-sdk/types" "^3.222.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.6.2" + +"@aws-sdk/client-lambda@^3.563.0": + version "3.839.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-lambda/-/client-lambda-3.839.0.tgz#81d10bcffc775807194d5735b72668b5e9d5eecb" + integrity sha512-i3umPgrz8WqGEzRXDIvbS+aANDSfNtDh1N6G5ESFmws2I2bFT9C748fJK91ALs35q7v+KcPRYVGObGekoZMV1A== + dependencies: + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/core" "3.839.0" + "@aws-sdk/credential-provider-node" "3.839.0" + "@aws-sdk/middleware-host-header" "3.821.0" + "@aws-sdk/middleware-logger" "3.821.0" + "@aws-sdk/middleware-recursion-detection" "3.821.0" + "@aws-sdk/middleware-user-agent" "3.839.0" + "@aws-sdk/region-config-resolver" "3.821.0" + "@aws-sdk/types" "3.821.0" + "@aws-sdk/util-endpoints" "3.828.0" + "@aws-sdk/util-user-agent-browser" "3.821.0" + "@aws-sdk/util-user-agent-node" "3.839.0" + "@smithy/config-resolver" "^4.1.4" + "@smithy/core" "^3.6.0" + "@smithy/eventstream-serde-browser" "^4.0.4" + "@smithy/eventstream-serde-config-resolver" "^4.1.2" + "@smithy/eventstream-serde-node" "^4.0.4" + "@smithy/fetch-http-handler" "^5.0.4" + "@smithy/hash-node" "^4.0.4" + "@smithy/invalid-dependency" "^4.0.4" + "@smithy/middleware-content-length" "^4.0.4" + "@smithy/middleware-endpoint" "^4.1.13" + "@smithy/middleware-retry" "^4.1.14" + "@smithy/middleware-serde" "^4.0.8" + "@smithy/middleware-stack" "^4.0.4" + "@smithy/node-config-provider" "^4.1.3" + "@smithy/node-http-handler" "^4.0.6" + "@smithy/protocol-http" "^5.1.2" + "@smithy/smithy-client" "^4.4.5" + "@smithy/types" "^4.3.1" + "@smithy/url-parser" "^4.0.4" + "@smithy/util-base64" "^4.0.0" + "@smithy/util-body-length-browser" "^4.0.0" + "@smithy/util-body-length-node" "^4.0.0" + "@smithy/util-defaults-mode-browser" "^4.0.21" + "@smithy/util-defaults-mode-node" "^4.0.21" + "@smithy/util-endpoints" "^3.0.6" + "@smithy/util-middleware" "^4.0.4" + "@smithy/util-retry" "^4.0.6" + "@smithy/util-stream" "^4.2.2" + "@smithy/util-utf8" "^4.0.0" + "@smithy/util-waiter" "^4.0.6" + tslib "^2.6.2" + +"@aws-sdk/client-sso@3.839.0": + version "3.839.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.839.0.tgz#d8bf4628a210b0e326c0f3e41218c8ffb01564b1" + integrity sha512-AZABysUhbfcwXVlMo97/vwHgsfJNF81wypCAowpqAJkSjP2KrqsqHpb71/RoR2w8JGmEnBBXRD4wIxDhnmifWg== + dependencies: + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/core" "3.839.0" + "@aws-sdk/middleware-host-header" "3.821.0" + "@aws-sdk/middleware-logger" "3.821.0" + "@aws-sdk/middleware-recursion-detection" "3.821.0" + "@aws-sdk/middleware-user-agent" "3.839.0" + "@aws-sdk/region-config-resolver" "3.821.0" + "@aws-sdk/types" "3.821.0" + "@aws-sdk/util-endpoints" "3.828.0" + "@aws-sdk/util-user-agent-browser" "3.821.0" + "@aws-sdk/util-user-agent-node" "3.839.0" + "@smithy/config-resolver" "^4.1.4" + "@smithy/core" "^3.6.0" + "@smithy/fetch-http-handler" "^5.0.4" + "@smithy/hash-node" "^4.0.4" + "@smithy/invalid-dependency" "^4.0.4" + "@smithy/middleware-content-length" "^4.0.4" + "@smithy/middleware-endpoint" "^4.1.13" + "@smithy/middleware-retry" "^4.1.14" + "@smithy/middleware-serde" "^4.0.8" + "@smithy/middleware-stack" "^4.0.4" + "@smithy/node-config-provider" "^4.1.3" + "@smithy/node-http-handler" "^4.0.6" + "@smithy/protocol-http" "^5.1.2" + "@smithy/smithy-client" "^4.4.5" + "@smithy/types" "^4.3.1" + "@smithy/url-parser" "^4.0.4" + "@smithy/util-base64" "^4.0.0" + "@smithy/util-body-length-browser" "^4.0.0" + "@smithy/util-body-length-node" "^4.0.0" + "@smithy/util-defaults-mode-browser" "^4.0.21" + "@smithy/util-defaults-mode-node" "^4.0.21" + "@smithy/util-endpoints" "^3.0.6" + "@smithy/util-middleware" "^4.0.4" + "@smithy/util-retry" "^4.0.6" + "@smithy/util-utf8" "^4.0.0" + tslib "^2.6.2" + +"@aws-sdk/core@3.839.0": + version "3.839.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/core/-/core-3.839.0.tgz#dd841b3c331ca99c6c1d096184ea50b8f168fec4" + integrity sha512-KdwL5RaK7eUIlOpdOoZ5u+2t4X1rdX/MTZgz3IV/aBzjVUoGsp+uUnbyqXomLQSUitPHp72EE/NHDsvWW/IHvQ== + dependencies: + "@aws-sdk/types" "3.821.0" + "@aws-sdk/xml-builder" "3.821.0" + "@smithy/core" "^3.6.0" + "@smithy/node-config-provider" "^4.1.3" + "@smithy/property-provider" "^4.0.4" + "@smithy/protocol-http" "^5.1.2" + "@smithy/signature-v4" "^5.1.2" + "@smithy/smithy-client" "^4.4.5" + "@smithy/types" "^4.3.1" + "@smithy/util-base64" "^4.0.0" + "@smithy/util-body-length-browser" "^4.0.0" + "@smithy/util-middleware" "^4.0.4" + "@smithy/util-utf8" "^4.0.0" + fast-xml-parser "4.4.1" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-env@3.839.0": + version "3.839.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.839.0.tgz#0102470388f1939206a80d8a7398047b380378bc" + integrity sha512-cWTadewPPz1OvObZJB+olrgh8VwcgIVcT293ZUT9V0CMF0UU7QaPwJP7uNXcNxltTh+sk1yhjH4UlcnJigZZbA== + dependencies: + "@aws-sdk/core" "3.839.0" + "@aws-sdk/types" "3.821.0" + "@smithy/property-provider" "^4.0.4" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-http@3.839.0": + version "3.839.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-http/-/credential-provider-http-3.839.0.tgz#fefd416af01bcb2429f7db7e47d5ceaf3c860673" + integrity sha512-fv0BZwrDhWDju4D1MCLT4I2aPjr0dVQ6P+MpqvcGNOA41Oa9UdRhYTV5iuy5NLXzIzoCmnS+XfSq5Kbsf6//xw== + dependencies: + "@aws-sdk/core" "3.839.0" + "@aws-sdk/types" "3.821.0" + "@smithy/fetch-http-handler" "^5.0.4" + "@smithy/node-http-handler" "^4.0.6" + "@smithy/property-provider" "^4.0.4" + "@smithy/protocol-http" "^5.1.2" + "@smithy/smithy-client" "^4.4.5" + "@smithy/types" "^4.3.1" + "@smithy/util-stream" "^4.2.2" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-ini@3.839.0": + version "3.839.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.839.0.tgz#34535d13382dabad2de084f3c7a94e587ce9a832" + integrity sha512-GHm0hF4CiDxIDR7TauMaA6iI55uuSqRxMBcqTAHaTPm6+h1A+MS+ysQMxZ+Jvwtoy8WmfTIGrJVxSCw0sK2hvA== + dependencies: + "@aws-sdk/core" "3.839.0" + "@aws-sdk/credential-provider-env" "3.839.0" + "@aws-sdk/credential-provider-http" "3.839.0" + "@aws-sdk/credential-provider-process" "3.839.0" + "@aws-sdk/credential-provider-sso" "3.839.0" + "@aws-sdk/credential-provider-web-identity" "3.839.0" + "@aws-sdk/nested-clients" "3.839.0" + "@aws-sdk/types" "3.821.0" + "@smithy/credential-provider-imds" "^4.0.6" + "@smithy/property-provider" "^4.0.4" + "@smithy/shared-ini-file-loader" "^4.0.4" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-node@3.839.0": + version "3.839.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.839.0.tgz#2e7cfa42caa76977c7734cfada0febca9f72570c" + integrity sha512-7bR+U2h+ft0V8chyeu9Bh/pvau4ZkQMeRt5f0dAULoepZQ77QQVRP4H04yJPTg9DCtqbVULQ3uf5YOp1/08vQw== + dependencies: + "@aws-sdk/credential-provider-env" "3.839.0" + "@aws-sdk/credential-provider-http" "3.839.0" + "@aws-sdk/credential-provider-ini" "3.839.0" + "@aws-sdk/credential-provider-process" "3.839.0" + "@aws-sdk/credential-provider-sso" "3.839.0" + "@aws-sdk/credential-provider-web-identity" "3.839.0" + "@aws-sdk/types" "3.821.0" + "@smithy/credential-provider-imds" "^4.0.6" + "@smithy/property-provider" "^4.0.4" + "@smithy/shared-ini-file-loader" "^4.0.4" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-process@3.839.0": + version "3.839.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.839.0.tgz#13be5dae462dbd368ce907bd79a00eaf672fa57f" + integrity sha512-qShpekjociUZ+isyQNa0P7jo+0q3N2+0eJDg8SGyP6K6hHTcGfiqxTDps+IKl6NreCPhZCBzyI9mWkP0xSDR6g== + dependencies: + "@aws-sdk/core" "3.839.0" + "@aws-sdk/types" "3.821.0" + "@smithy/property-provider" "^4.0.4" + "@smithy/shared-ini-file-loader" "^4.0.4" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-sso@3.839.0": + version "3.839.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.839.0.tgz#d64941981ca3160f32db87d099b130c36af55a62" + integrity sha512-w10zBLHhU8SBQcdrSPMI02haLoRGZg+gP7mH/Er8VhIXfHefbr7o4NirmB0hwdw/YAH8MLlC9jj7c2SJlsNhYA== + dependencies: + "@aws-sdk/client-sso" "3.839.0" + "@aws-sdk/core" "3.839.0" + "@aws-sdk/token-providers" "3.839.0" + "@aws-sdk/types" "3.821.0" + "@smithy/property-provider" "^4.0.4" + "@smithy/shared-ini-file-loader" "^4.0.4" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-web-identity@3.839.0": + version "3.839.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.839.0.tgz#b135421b562c9577e3d12fbb39b7adbb48c9ca00" + integrity sha512-EvqTc7J1kgmiuxknpCp1S60hyMQvmKxsI5uXzQtcogl/N55rxiXEqnCLI5q6p33q91PJegrcMCM5Q17Afhm5qA== + dependencies: + "@aws-sdk/core" "3.839.0" + "@aws-sdk/nested-clients" "3.839.0" + "@aws-sdk/types" "3.821.0" + "@smithy/property-provider" "^4.0.4" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@aws-sdk/middleware-host-header@3.821.0": + version "3.821.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.821.0.tgz#1dfda8da4e0f9499648dab9a989d10706e289cc7" + integrity sha512-xSMR+sopSeWGx5/4pAGhhfMvGBHioVBbqGvDs6pG64xfNwM5vq5s5v6D04e2i+uSTj4qGa71dLUs5I0UzAK3sw== + dependencies: + "@aws-sdk/types" "3.821.0" + "@smithy/protocol-http" "^5.1.2" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@aws-sdk/middleware-logger@3.821.0": + version "3.821.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.821.0.tgz#87067907a25cdc6c155d3a35fe32e399c1ef87e6" + integrity sha512-0cvI0ipf2tGx7fXYEEN5fBeZDz2RnHyb9xftSgUsEq7NBxjV0yTZfLJw6Za5rjE6snC80dRN8+bTNR1tuG89zA== + dependencies: + "@aws-sdk/types" "3.821.0" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@aws-sdk/middleware-recursion-detection@3.821.0": + version "3.821.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.821.0.tgz#bc34b08efc1e1af7b14a58023a79bfb75a0b64fa" + integrity sha512-efmaifbhBoqKG3bAoEfDdcM8hn1psF+4qa7ykWuYmfmah59JBeqHLfz5W9m9JoTwoKPkFcVLWZxnyZzAnVBOIg== + dependencies: + "@aws-sdk/types" "3.821.0" + "@smithy/protocol-http" "^5.1.2" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@aws-sdk/middleware-user-agent@3.839.0": + version "3.839.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.839.0.tgz#92c22d5a90bfcdbe8d757c4e388e53462d2d0883" + integrity sha512-2u74uRM1JWq6Sf7+3YpjejPM9YkomGt4kWhrmooIBEq1k5r2GTbkH7pNCxBQwBueXM21jAGVDxxeClpTx+5hig== + dependencies: + "@aws-sdk/core" "3.839.0" + "@aws-sdk/types" "3.821.0" + "@aws-sdk/util-endpoints" "3.828.0" + "@smithy/core" "^3.6.0" + "@smithy/protocol-http" "^5.1.2" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@aws-sdk/nested-clients@3.839.0": + version "3.839.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/nested-clients/-/nested-clients-3.839.0.tgz#f25df2be30bbbdf13b29ec5e8575190599b9b375" + integrity sha512-Glic0pg2THYP3aRhJORwJJBe1JLtJoEdWV/MFZNyzCklfMwEzpWtZAyxy+tQyFmMeW50uBAnh2R0jhMMcf257w== + dependencies: + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/core" "3.839.0" + "@aws-sdk/middleware-host-header" "3.821.0" + "@aws-sdk/middleware-logger" "3.821.0" + "@aws-sdk/middleware-recursion-detection" "3.821.0" + "@aws-sdk/middleware-user-agent" "3.839.0" + "@aws-sdk/region-config-resolver" "3.821.0" + "@aws-sdk/types" "3.821.0" + "@aws-sdk/util-endpoints" "3.828.0" + "@aws-sdk/util-user-agent-browser" "3.821.0" + "@aws-sdk/util-user-agent-node" "3.839.0" + "@smithy/config-resolver" "^4.1.4" + "@smithy/core" "^3.6.0" + "@smithy/fetch-http-handler" "^5.0.4" + "@smithy/hash-node" "^4.0.4" + "@smithy/invalid-dependency" "^4.0.4" + "@smithy/middleware-content-length" "^4.0.4" + "@smithy/middleware-endpoint" "^4.1.13" + "@smithy/middleware-retry" "^4.1.14" + "@smithy/middleware-serde" "^4.0.8" + "@smithy/middleware-stack" "^4.0.4" + "@smithy/node-config-provider" "^4.1.3" + "@smithy/node-http-handler" "^4.0.6" + "@smithy/protocol-http" "^5.1.2" + "@smithy/smithy-client" "^4.4.5" + "@smithy/types" "^4.3.1" + "@smithy/url-parser" "^4.0.4" + "@smithy/util-base64" "^4.0.0" + "@smithy/util-body-length-browser" "^4.0.0" + "@smithy/util-body-length-node" "^4.0.0" + "@smithy/util-defaults-mode-browser" "^4.0.21" + "@smithy/util-defaults-mode-node" "^4.0.21" + "@smithy/util-endpoints" "^3.0.6" + "@smithy/util-middleware" "^4.0.4" + "@smithy/util-retry" "^4.0.6" + "@smithy/util-utf8" "^4.0.0" + tslib "^2.6.2" + +"@aws-sdk/region-config-resolver@3.821.0": + version "3.821.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/region-config-resolver/-/region-config-resolver-3.821.0.tgz#2f1cd54ca140cbdc821a604d8b20444f9b0b77cf" + integrity sha512-t8og+lRCIIy5nlId0bScNpCkif8sc0LhmtaKsbm0ZPm3sCa/WhCbSZibjbZ28FNjVCV+p0D9RYZx0VDDbtWyjw== + dependencies: + "@aws-sdk/types" "3.821.0" + "@smithy/node-config-provider" "^4.1.3" + "@smithy/types" "^4.3.1" + "@smithy/util-config-provider" "^4.0.0" + "@smithy/util-middleware" "^4.0.4" + tslib "^2.6.2" + +"@aws-sdk/token-providers@3.839.0": + version "3.839.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.839.0.tgz#55be3491195d09d8425e57cabd5bd042d67eef8a" + integrity sha512-2nlafqdSbet/2WtYIoZ7KEGFowFonPBDYlTjrUvwU2yooE10VhvzhLSCTB2aKIVzo2Z2wL5WGFQsqAY5QwK6Bw== + dependencies: + "@aws-sdk/core" "3.839.0" + "@aws-sdk/nested-clients" "3.839.0" + "@aws-sdk/types" "3.821.0" + "@smithy/property-provider" "^4.0.4" + "@smithy/shared-ini-file-loader" "^4.0.4" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@aws-sdk/types@3.821.0", "@aws-sdk/types@^3.1.0", "@aws-sdk/types@^3.222.0": + version "3.821.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.821.0.tgz#edfd4595208e4e9f24f397fbc8cb82e3ec336649" + integrity sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA== + dependencies: + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@aws-sdk/util-endpoints@3.828.0": + version "3.828.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-endpoints/-/util-endpoints-3.828.0.tgz#a02f9c99d9749123fabad38d3b6cd51f4c8489db" + integrity sha512-RvKch111SblqdkPzg3oCIdlGxlQs+k+P7Etory9FmxPHyPDvsP1j1c74PmgYqtzzMWmoXTjd+c9naUHh9xG8xg== + dependencies: + "@aws-sdk/types" "3.821.0" + "@smithy/types" "^4.3.1" + "@smithy/util-endpoints" "^3.0.6" + tslib "^2.6.2" + +"@aws-sdk/util-locate-window@^3.0.0": + version "3.804.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-locate-window/-/util-locate-window-3.804.0.tgz#a2ee8dc5d9c98276986e8e1ba03c0c84d9afb0f5" + integrity sha512-zVoRfpmBVPodYlnMjgVjfGoEZagyRF5IPn3Uo6ZvOZp24chnW/FRstH7ESDHDDRga4z3V+ElUQHKpFDXWyBW5A== + dependencies: + tslib "^2.6.2" + +"@aws-sdk/util-user-agent-browser@3.821.0": + version "3.821.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.821.0.tgz#32962fd3ae20986da128944b88a231508e017f5b" + integrity sha512-irWZHyM0Jr1xhC+38OuZ7JB6OXMLPZlj48thElpsO1ZSLRkLZx5+I7VV6k3sp2yZ7BYbKz/G2ojSv4wdm7XTLw== + dependencies: + "@aws-sdk/types" "3.821.0" + "@smithy/types" "^4.3.1" + bowser "^2.11.0" + tslib "^2.6.2" + +"@aws-sdk/util-user-agent-node@3.839.0": + version "3.839.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.839.0.tgz#0c29e2d18e9d6ed1c6dffdf404adf8129f0f40e5" + integrity sha512-MuunkIG1bJVMtTH7MbjXOrhHleU5wjHz5eCAUc6vj7M9rwol71nqjj9b8RLnkO5gsJcKc29Qk8iV6xQuzKWNMw== + dependencies: + "@aws-sdk/middleware-user-agent" "3.839.0" + "@aws-sdk/types" "3.821.0" + "@smithy/node-config-provider" "^4.1.3" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@aws-sdk/util-utf8-browser@^3.0.0": + version "3.259.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz#3275a6f5eb334f96ca76635b961d3c50259fd9ff" + integrity sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw== + dependencies: + tslib "^2.3.1" + +"@aws-sdk/xml-builder@3.821.0": + version "3.821.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/xml-builder/-/xml-builder-3.821.0.tgz#ff89bf1276fca41276ed508b9c8ae21978d91177" + integrity sha512-DIIotRnefVL6DiaHtO6/21DhJ4JZnnIwdNbpwiAhdt/AVbttcE4yw925gsjur0OGv5BTYXQXU3YnANBYnZjuQA== + dependencies: + "@smithy/types" "^4.3.1" + tslib "^2.6.2" -"@babel/highlight@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" - integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== +"@babel/code-frame@^7.0.0": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" + integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== dependencies: - "@babel/helper-validator-identifier" "^7.18.6" - chalk "^2.0.0" + "@babel/helper-validator-identifier" "^7.27.1" js-tokens "^4.0.0" + picocolors "^1.1.1" + +"@babel/helper-validator-identifier@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8" + integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== + +"@bytecodealliance/preview2-shim@0.17.0": + version "0.17.0" + resolved "https://registry.yarnpkg.com/@bytecodealliance/preview2-shim/-/preview2-shim-0.17.0.tgz#9bc1cadbb9f86c446c6f579d3431c08a06a6672e" + integrity sha512-JorcEwe4ud0x5BS/Ar2aQWOQoFzjq/7jcnxYXCvSMh0oRm0dQXzOA+hqLDBnOMks1LLBA7dmiLLsEBl09Yd6iQ== "@colors/colors@1.5.0": version "1.5.0" @@ -56,22 +514,66 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" -"@eslint/eslintrc@^1.3.3": - version "1.3.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.3.tgz#2b044ab39fdfa75b4688184f9e573ce3c5b0ff95" - integrity sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg== +"@eslint-community/eslint-utils@^4.2.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz#607084630c6c033992a082de6e6fbc1a8b52175a" + integrity sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.4.0", "@eslint-community/regexpp@^4.6.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.4.0" - globals "^13.15.0" + espree "^9.6.0" + globals "^13.19.0" ignore "^5.2.0" import-fresh "^3.2.1" js-yaml "^4.1.0" minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.0.0-beta.146", "@ethersproject/abi@^5.1.2", "@ethersproject/abi@^5.7.0": +"@eslint/js@8.57.1": + version "8.57.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" + integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== + +"@ethereumjs/rlp@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@ethereumjs/rlp/-/rlp-4.0.1.tgz#626fabfd9081baab3d0a3074b0c7ecaf674aaa41" + integrity sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw== + +"@ethereumjs/rlp@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@ethereumjs/rlp/-/rlp-5.0.2.tgz#c89bd82f2f3bec248ab2d517ae25f5bbc4aac842" + integrity sha512-DziebCdg4JpGlEqEdGgXmjqcFoJi+JGulUXwEjsZGAscAQ7MyD/7LE/GVCP29vEQxKc7AAwjT3A2ywHp2xfoCA== + +"@ethereumjs/util@^8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/util/-/util-8.1.0.tgz#299df97fb6b034e0577ce9f94c7d9d1004409ed4" + integrity sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA== + dependencies: + "@ethereumjs/rlp" "^4.0.1" + ethereum-cryptography "^2.0.0" + micro-ftch "^0.3.1" + +"@ethereumjs/util@^9.1.0": + version "9.1.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/util/-/util-9.1.0.tgz#75e3898a3116d21c135fa9e29886565609129bce" + integrity sha512-XBEKsYqLGXLah9PNJbgdkigthkG7TAGvlD/sH12beMXEyHDyigfcbdvHhmLyDWgDyOJn4QwiQUaF7yeuhnjdog== + dependencies: + "@ethereumjs/rlp" "^5.0.2" + ethereum-cryptography "^2.2.1" + +"@ethersproject/abi@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== @@ -86,7 +588,22 @@ "@ethersproject/properties" "^5.7.0" "@ethersproject/strings" "^5.7.0" -"@ethersproject/abstract-provider@5.7.0", "@ethersproject/abstract-provider@^5.7.0": +"@ethersproject/abi@5.8.0", "@ethersproject/abi@^5.0.9", "@ethersproject/abi@^5.1.2", "@ethersproject/abi@^5.7.0", "@ethersproject/abi@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.8.0.tgz#e79bb51940ac35fe6f3262d7fe2cdb25ad5f07d9" + integrity sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q== + dependencies: + "@ethersproject/address" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/constants" "^5.8.0" + "@ethersproject/hash" "^5.8.0" + "@ethersproject/keccak256" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/strings" "^5.8.0" + +"@ethersproject/abstract-provider@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== @@ -99,7 +616,20 @@ "@ethersproject/transactions" "^5.7.0" "@ethersproject/web" "^5.7.0" -"@ethersproject/abstract-signer@5.7.0", "@ethersproject/abstract-signer@^5.7.0": +"@ethersproject/abstract-provider@5.8.0", "@ethersproject/abstract-provider@^5.7.0", "@ethersproject/abstract-provider@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.8.0.tgz#7581f9be601afa1d02b95d26b9d9840926a35b0c" + integrity sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg== + dependencies: + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/networks" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/transactions" "^5.8.0" + "@ethersproject/web" "^5.8.0" + +"@ethersproject/abstract-signer@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== @@ -110,7 +640,29 @@ "@ethersproject/logger" "^5.7.0" "@ethersproject/properties" "^5.7.0" -"@ethersproject/address@5.7.0", "@ethersproject/address@^5.0.2", "@ethersproject/address@^5.0.8", "@ethersproject/address@^5.5.0", "@ethersproject/address@^5.7.0": +"@ethersproject/abstract-signer@5.8.0", "@ethersproject/abstract-signer@^5.7.0", "@ethersproject/abstract-signer@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.8.0.tgz#8d7417e95e4094c1797a9762e6789c7356db0754" + integrity sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA== + dependencies: + "@ethersproject/abstract-provider" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + +"@ethersproject/address@5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.6.1.tgz#ab57818d9aefee919c5721d28cd31fd95eff413d" + integrity sha512-uOgF0kS5MJv9ZvCz7x6T2EXJSzotiybApn4XlOgoTX0xdtyVIJ7pF+6cGPxiEq/dpBiTfMiw7Yc81JcwhSYA0Q== + dependencies: + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/keccak256" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/rlp" "^5.6.1" + +"@ethersproject/address@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== @@ -121,14 +673,32 @@ "@ethersproject/logger" "^5.7.0" "@ethersproject/rlp" "^5.7.0" -"@ethersproject/base64@5.7.0", "@ethersproject/base64@^5.7.0": +"@ethersproject/address@5.8.0", "@ethersproject/address@^5.0.2", "@ethersproject/address@^5.0.8", "@ethersproject/address@^5.5.0", "@ethersproject/address@^5.7.0", "@ethersproject/address@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.8.0.tgz#3007a2c352eee566ad745dca1dbbebdb50a6a983" + integrity sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA== + dependencies: + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/keccak256" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/rlp" "^5.8.0" + +"@ethersproject/base64@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== dependencies: "@ethersproject/bytes" "^5.7.0" -"@ethersproject/basex@5.7.0", "@ethersproject/basex@^5.7.0": +"@ethersproject/base64@5.8.0", "@ethersproject/base64@^5.7.0", "@ethersproject/base64@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.8.0.tgz#61c669c648f6e6aad002c228465d52ac93ee83eb" + integrity sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ== + dependencies: + "@ethersproject/bytes" "^5.8.0" + +"@ethersproject/basex@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.7.0.tgz#97034dc7e8938a8ca943ab20f8a5e492ece4020b" integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== @@ -136,7 +706,15 @@ "@ethersproject/bytes" "^5.7.0" "@ethersproject/properties" "^5.7.0" -"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@^5.1.1", "@ethersproject/bignumber@^5.7.0": +"@ethersproject/basex@5.8.0", "@ethersproject/basex@^5.7.0", "@ethersproject/basex@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.8.0.tgz#1d279a90c4be84d1c1139114a1f844869e57d03a" + integrity sha512-PIgTszMlDRmNwW9nhS6iqtVfdTAKosA7llYXNmGPw4YAI1PUyMv28988wAb41/gHF/WqGdoLv0erHaRcHRKW2Q== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + +"@ethersproject/bignumber@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== @@ -145,21 +723,44 @@ "@ethersproject/logger" "^5.7.0" bn.js "^5.2.1" -"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@^5.0.8", "@ethersproject/bytes@^5.7.0": +"@ethersproject/bignumber@5.8.0", "@ethersproject/bignumber@^5.1.1", "@ethersproject/bignumber@^5.6.2", "@ethersproject/bignumber@^5.7.0", "@ethersproject/bignumber@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.8.0.tgz#c381d178f9eeb370923d389284efa19f69efa5d7" + integrity sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + bn.js "^5.2.1" + +"@ethersproject/bytes@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== dependencies: "@ethersproject/logger" "^5.7.0" -"@ethersproject/constants@5.7.0", "@ethersproject/constants@^5.7.0": +"@ethersproject/bytes@5.8.0", "@ethersproject/bytes@^5.0.8", "@ethersproject/bytes@^5.6.1", "@ethersproject/bytes@^5.7.0", "@ethersproject/bytes@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.8.0.tgz#9074820e1cac7507a34372cadeb035461463be34" + integrity sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A== + dependencies: + "@ethersproject/logger" "^5.8.0" + +"@ethersproject/constants@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== dependencies: "@ethersproject/bignumber" "^5.7.0" -"@ethersproject/contracts@5.7.0", "@ethersproject/contracts@^5.7.0": +"@ethersproject/constants@5.8.0", "@ethersproject/constants@^5.7.0", "@ethersproject/constants@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.8.0.tgz#12f31c2f4317b113a4c19de94e50933648c90704" + integrity sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg== + dependencies: + "@ethersproject/bignumber" "^5.8.0" + +"@ethersproject/contracts@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.7.0.tgz#c305e775abd07e48aa590e1a877ed5c316f8bd1e" integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== @@ -175,16 +776,32 @@ "@ethersproject/properties" "^5.7.0" "@ethersproject/transactions" "^5.7.0" +"@ethersproject/contracts@5.8.0", "@ethersproject/contracts@^5.7.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.8.0.tgz#243a38a2e4aa3e757215ea64e276f8a8c9d8ed73" + integrity sha512-0eFjGz9GtuAi6MZwhb4uvUM216F38xiuR0yYCjKJpNfSEy4HUM8hvqqBj9Jmm0IUz8l0xKEhWwLIhPgxNY0yvQ== + dependencies: + "@ethersproject/abi" "^5.8.0" + "@ethersproject/abstract-provider" "^5.8.0" + "@ethersproject/abstract-signer" "^5.8.0" + "@ethersproject/address" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/constants" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/transactions" "^5.8.0" + "@ethersproject/experimental@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/experimental/-/experimental-5.7.0.tgz#9759639434d37beaedfd8acab6f3af7db246b92d" - integrity sha512-DWvhuw7Dg8JPyhMbh/CNYOwsTLjXRx/HGkacIL5rBocG8jJC0kmixwoK/J3YblO4vtcyBLMa+sV74RJZK2iyHg== + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/experimental/-/experimental-5.8.0.tgz#85ba4344bc53d5bf5e85e34066a09e37edb43d12" + integrity sha512-Oa5LNrm0jk0xQwbwd///ptex4Y62VRYIBzLfRtPpS5CGE+4RbAvETWc7bp/I0cXHqvXjvdvPNcZNc40qB8B5Mw== dependencies: - "@ethersproject/web" "^5.7.0" - ethers "^5.7.0" + "@ethersproject/web" "^5.8.0" + ethers "^5.8.0" scrypt-js "3.0.1" -"@ethersproject/hash@5.7.0", "@ethersproject/hash@^5.7.0": +"@ethersproject/hash@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== @@ -199,7 +816,22 @@ "@ethersproject/properties" "^5.7.0" "@ethersproject/strings" "^5.7.0" -"@ethersproject/hdnode@5.7.0", "@ethersproject/hdnode@^5.7.0": +"@ethersproject/hash@5.8.0", "@ethersproject/hash@^5.7.0", "@ethersproject/hash@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.8.0.tgz#b8893d4629b7f8462a90102572f8cd65a0192b4c" + integrity sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA== + dependencies: + "@ethersproject/abstract-signer" "^5.8.0" + "@ethersproject/address" "^5.8.0" + "@ethersproject/base64" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/keccak256" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/strings" "^5.8.0" + +"@ethersproject/hdnode@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz#e627ddc6b466bc77aebf1a6b9e47405ca5aef9cf" integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== @@ -217,7 +849,25 @@ "@ethersproject/transactions" "^5.7.0" "@ethersproject/wordlists" "^5.7.0" -"@ethersproject/json-wallets@5.7.0", "@ethersproject/json-wallets@^5.7.0": +"@ethersproject/hdnode@5.8.0", "@ethersproject/hdnode@^5.7.0", "@ethersproject/hdnode@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.8.0.tgz#a51ae2a50bcd48ef6fd108c64cbae5e6ff34a761" + integrity sha512-4bK1VF6E83/3/Im0ERnnUeWOY3P1BZml4ZD3wcH8Ys0/d1h1xaFt6Zc+Dh9zXf9TapGro0T4wvO71UTCp3/uoA== + dependencies: + "@ethersproject/abstract-signer" "^5.8.0" + "@ethersproject/basex" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/pbkdf2" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/sha2" "^5.8.0" + "@ethersproject/signing-key" "^5.8.0" + "@ethersproject/strings" "^5.8.0" + "@ethersproject/transactions" "^5.8.0" + "@ethersproject/wordlists" "^5.8.0" + +"@ethersproject/json-wallets@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz#5e3355287b548c32b368d91014919ebebddd5360" integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== @@ -236,7 +886,26 @@ aes-js "3.0.0" scrypt-js "3.0.1" -"@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@^5.7.0": +"@ethersproject/json-wallets@5.8.0", "@ethersproject/json-wallets@^5.7.0", "@ethersproject/json-wallets@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.8.0.tgz#d18de0a4cf0f185f232eb3c17d5e0744d97eb8c9" + integrity sha512-HxblNck8FVUtNxS3VTEYJAcwiKYsBIF77W15HufqlBF9gGfhmYOJtYZp8fSDZtn9y5EaXTE87zDwzxRoTFk11w== + dependencies: + "@ethersproject/abstract-signer" "^5.8.0" + "@ethersproject/address" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/hdnode" "^5.8.0" + "@ethersproject/keccak256" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/pbkdf2" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/random" "^5.8.0" + "@ethersproject/strings" "^5.8.0" + "@ethersproject/transactions" "^5.8.0" + aes-js "3.0.0" + scrypt-js "3.0.1" + +"@ethersproject/keccak256@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== @@ -244,19 +913,39 @@ "@ethersproject/bytes" "^5.7.0" js-sha3 "0.8.0" -"@ethersproject/logger@5.7.0", "@ethersproject/logger@^5.7.0": +"@ethersproject/keccak256@5.8.0", "@ethersproject/keccak256@^5.6.1", "@ethersproject/keccak256@^5.7.0", "@ethersproject/keccak256@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.8.0.tgz#d2123a379567faf2d75d2aaea074ffd4df349e6a" + integrity sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng== + dependencies: + "@ethersproject/bytes" "^5.8.0" + js-sha3 "0.8.0" + +"@ethersproject/logger@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== -"@ethersproject/networks@5.7.1", "@ethersproject/networks@^5.7.0": +"@ethersproject/logger@5.8.0", "@ethersproject/logger@^5.6.0", "@ethersproject/logger@^5.7.0", "@ethersproject/logger@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.8.0.tgz#f0232968a4f87d29623a0481690a2732662713d6" + integrity sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA== + +"@ethersproject/networks@5.7.1": version "5.7.1" resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== dependencies: "@ethersproject/logger" "^5.7.0" -"@ethersproject/pbkdf2@5.7.0", "@ethersproject/pbkdf2@^5.7.0": +"@ethersproject/networks@5.8.0", "@ethersproject/networks@^5.7.0", "@ethersproject/networks@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.8.0.tgz#8b4517a3139380cba9fb00b63ffad0a979671fde" + integrity sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg== + dependencies: + "@ethersproject/logger" "^5.8.0" + +"@ethersproject/pbkdf2@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz#d2267d0a1f6e123f3771007338c47cccd83d3102" integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== @@ -264,38 +953,27 @@ "@ethersproject/bytes" "^5.7.0" "@ethersproject/sha2" "^5.7.0" -"@ethersproject/properties@5.7.0", "@ethersproject/properties@^5.7.0": +"@ethersproject/pbkdf2@5.8.0", "@ethersproject/pbkdf2@^5.7.0", "@ethersproject/pbkdf2@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.8.0.tgz#cd2621130e5dd51f6a0172e63a6e4a0c0a0ec37e" + integrity sha512-wuHiv97BrzCmfEaPbUFpMjlVg/IDkZThp9Ri88BpjRleg4iePJaj2SW8AIyE8cXn5V1tuAaMj6lzvsGJkGWskg== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/sha2" "^5.8.0" + +"@ethersproject/properties@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== dependencies: "@ethersproject/logger" "^5.7.0" -"@ethersproject/providers@5.7.1": - version "5.7.1" - resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.1.tgz#b0799b616d5579cd1067a8ebf1fc1ec74c1e122c" - integrity sha512-vZveG/DLyo+wk4Ga1yx6jSEHrLPgmTt+dFv0dv8URpVCRf0jVhalps1jq/emN/oXnMRsC7cQgAF32DcXLL7BPQ== +"@ethersproject/properties@5.8.0", "@ethersproject/properties@^5.7.0", "@ethersproject/properties@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.8.0.tgz#405a8affb6311a49a91dabd96aeeae24f477020e" + integrity sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw== dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/base64" "^5.7.0" - "@ethersproject/basex" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/networks" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/web" "^5.7.0" - bech32 "1.1.4" - ws "7.4.6" + "@ethersproject/logger" "^5.8.0" "@ethersproject/providers@5.7.2": version "5.7.2" @@ -323,7 +1001,33 @@ bech32 "1.1.4" ws "7.4.6" -"@ethersproject/random@5.7.0", "@ethersproject/random@^5.7.0": +"@ethersproject/providers@5.8.0", "@ethersproject/providers@^5.7.2": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.8.0.tgz#6c2ae354f7f96ee150439f7de06236928bc04cb4" + integrity sha512-3Il3oTzEx3o6kzcg9ZzbE+oCZYyY+3Zh83sKkn4s1DZfTUjIegHnN2Cm0kbn9YFy45FDVcuCLLONhU7ny0SsCw== + dependencies: + "@ethersproject/abstract-provider" "^5.8.0" + "@ethersproject/abstract-signer" "^5.8.0" + "@ethersproject/address" "^5.8.0" + "@ethersproject/base64" "^5.8.0" + "@ethersproject/basex" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/constants" "^5.8.0" + "@ethersproject/hash" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/networks" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/random" "^5.8.0" + "@ethersproject/rlp" "^5.8.0" + "@ethersproject/sha2" "^5.8.0" + "@ethersproject/strings" "^5.8.0" + "@ethersproject/transactions" "^5.8.0" + "@ethersproject/web" "^5.8.0" + bech32 "1.1.4" + ws "8.18.0" + +"@ethersproject/random@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.7.0.tgz#af19dcbc2484aae078bb03656ec05df66253280c" integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== @@ -331,7 +1035,15 @@ "@ethersproject/bytes" "^5.7.0" "@ethersproject/logger" "^5.7.0" -"@ethersproject/rlp@5.7.0", "@ethersproject/rlp@^5.7.0": +"@ethersproject/random@5.8.0", "@ethersproject/random@^5.7.0", "@ethersproject/random@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.8.0.tgz#1bced04d49449f37c6437c701735a1a022f0057a" + integrity sha512-E4I5TDl7SVqyg4/kkA/qTfuLWAQGXmSOgYyO01So8hLfwgKvYK5snIlzxJMk72IFdG/7oh8yuSqY2KX7MMwg+A== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + +"@ethersproject/rlp@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== @@ -339,7 +1051,15 @@ "@ethersproject/bytes" "^5.7.0" "@ethersproject/logger" "^5.7.0" -"@ethersproject/sha2@5.7.0", "@ethersproject/sha2@^5.7.0": +"@ethersproject/rlp@5.8.0", "@ethersproject/rlp@^5.6.1", "@ethersproject/rlp@^5.7.0", "@ethersproject/rlp@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.8.0.tgz#5a0d49f61bc53e051532a5179472779141451de5" + integrity sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + +"@ethersproject/sha2@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.7.0.tgz#9a5f7a7824ef784f7f7680984e593a800480c9fb" integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== @@ -348,7 +1068,16 @@ "@ethersproject/logger" "^5.7.0" hash.js "1.1.7" -"@ethersproject/signing-key@5.7.0", "@ethersproject/signing-key@^5.7.0": +"@ethersproject/sha2@5.8.0", "@ethersproject/sha2@^5.7.0", "@ethersproject/sha2@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.8.0.tgz#8954a613bb78dac9b46829c0a95de561ef74e5e1" + integrity sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + hash.js "1.1.7" + +"@ethersproject/signing-key@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== @@ -360,7 +1089,19 @@ elliptic "6.5.4" hash.js "1.1.7" -"@ethersproject/solidity@5.7.0", "@ethersproject/solidity@^5.7.0": +"@ethersproject/signing-key@5.8.0", "@ethersproject/signing-key@^5.7.0", "@ethersproject/signing-key@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.8.0.tgz#9797e02c717b68239c6349394ea85febf8893119" + integrity sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + bn.js "^5.2.1" + elliptic "6.6.1" + hash.js "1.1.7" + +"@ethersproject/solidity@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.7.0.tgz#5e9c911d8a2acce2a5ebb48a5e2e0af20b631cb8" integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== @@ -372,7 +1113,19 @@ "@ethersproject/sha2" "^5.7.0" "@ethersproject/strings" "^5.7.0" -"@ethersproject/strings@5.7.0", "@ethersproject/strings@^5.7.0": +"@ethersproject/solidity@5.8.0", "@ethersproject/solidity@^5.7.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.8.0.tgz#429bb9fcf5521307a9448d7358c26b93695379b9" + integrity sha512-4CxFeCgmIWamOHwYN9d+QWGxye9qQLilpgTU0XhYs1OahkclF+ewO+3V1U0mvpiuQxm5EHHmv8f7ClVII8EHsA== + dependencies: + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/keccak256" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/sha2" "^5.8.0" + "@ethersproject/strings" "^5.8.0" + +"@ethersproject/strings@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== @@ -381,7 +1134,16 @@ "@ethersproject/constants" "^5.7.0" "@ethersproject/logger" "^5.7.0" -"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.6.2", "@ethersproject/transactions@^5.7.0": +"@ethersproject/strings@5.8.0", "@ethersproject/strings@^5.7.0", "@ethersproject/strings@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.8.0.tgz#ad79fafbf0bd272d9765603215ac74fd7953908f" + integrity sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/constants" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + +"@ethersproject/transactions@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== @@ -396,6 +1158,21 @@ "@ethersproject/rlp" "^5.7.0" "@ethersproject/signing-key" "^5.7.0" +"@ethersproject/transactions@5.8.0", "@ethersproject/transactions@^5.6.2", "@ethersproject/transactions@^5.7.0", "@ethersproject/transactions@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.8.0.tgz#1e518822403abc99def5a043d1c6f6fe0007e46b" + integrity sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg== + dependencies: + "@ethersproject/address" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/constants" "^5.8.0" + "@ethersproject/keccak256" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/rlp" "^5.8.0" + "@ethersproject/signing-key" "^5.8.0" + "@ethersproject/units@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1" @@ -405,6 +1182,15 @@ "@ethersproject/constants" "^5.7.0" "@ethersproject/logger" "^5.7.0" +"@ethersproject/units@5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.8.0.tgz#c12f34ba7c3a2de0e9fa0ed0ee32f3e46c5c2c6a" + integrity sha512-lxq0CAnc5kMGIiWW4Mr041VT8IhNM+Pn5T3haO74XZWFulk7wH1Gv64HqE96hT4a7iiNMdOCFEBgaxWuk8ETKQ== + dependencies: + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/constants" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/wallet@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d" @@ -426,7 +1212,28 @@ "@ethersproject/transactions" "^5.7.0" "@ethersproject/wordlists" "^5.7.0" -"@ethersproject/web@5.7.1", "@ethersproject/web@^5.7.0": +"@ethersproject/wallet@5.8.0", "@ethersproject/wallet@^5.7.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.8.0.tgz#49c300d10872e6986d953e8310dc33d440da8127" + integrity sha512-G+jnzmgg6UxurVKRKvw27h0kvG75YKXZKdlLYmAHeF32TGUzHkOFd7Zn6QHOTYRFWnfjtSSFjBowKo7vfrXzPA== + dependencies: + "@ethersproject/abstract-provider" "^5.8.0" + "@ethersproject/abstract-signer" "^5.8.0" + "@ethersproject/address" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/hash" "^5.8.0" + "@ethersproject/hdnode" "^5.8.0" + "@ethersproject/json-wallets" "^5.8.0" + "@ethersproject/keccak256" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/random" "^5.8.0" + "@ethersproject/signing-key" "^5.8.0" + "@ethersproject/transactions" "^5.8.0" + "@ethersproject/wordlists" "^5.8.0" + +"@ethersproject/web@5.7.1": version "5.7.1" resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== @@ -437,7 +1244,18 @@ "@ethersproject/properties" "^5.7.0" "@ethersproject/strings" "^5.7.0" -"@ethersproject/wordlists@5.7.0", "@ethersproject/wordlists@^5.7.0": +"@ethersproject/web@5.8.0", "@ethersproject/web@^5.7.0", "@ethersproject/web@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.8.0.tgz#3e54badc0013b7a801463a7008a87988efce8a37" + integrity sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw== + dependencies: + "@ethersproject/base64" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/strings" "^5.8.0" + +"@ethersproject/wordlists@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz#8fb2c07185d68c3e09eb3bfd6e779ba2774627f5" integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== @@ -448,6 +1266,22 @@ "@ethersproject/properties" "^5.7.0" "@ethersproject/strings" "^5.7.0" +"@ethersproject/wordlists@5.8.0", "@ethersproject/wordlists@^5.7.0", "@ethersproject/wordlists@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.8.0.tgz#7a5654ee8d1bb1f4dbe43f91d217356d650ad821" + integrity sha512-2df9bbXicZws2Sb5S6ET493uJ0Z84Fjr3pC4tu/qlnZERibZCeUVuqdtt+7Tv9xxhUxHoIekIA7avrKUWHrezg== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/hash" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/strings" "^5.8.0" + +"@fastify/busboy@^2.0.0": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d" + integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA== + "@flashbots/ethers-provider-bundle@^0.5.0": version "0.5.0" resolved "https://registry.yarnpkg.com/@flashbots/ethers-provider-bundle/-/ethers-provider-bundle-0.5.0.tgz#068dd6a078066c50c36ac81b92d4726636768853" @@ -456,41 +1290,46 @@ ts-node "^9.1.0" typescript "^4.1.2" -"@gnosis.pm/safe-deployments@1.19.0": - version "1.19.0" - resolved "https://registry.yarnpkg.com/@gnosis.pm/safe-deployments/-/safe-deployments-1.19.0.tgz#f4ba8cf92cd6fdff4241ac50e410b4a6ff89babe" - integrity sha512-EvHR/LjMwJm0QKXyTscRXqR9vnJwCUDiMnRNKRyXe1akW+udiYXjJTAiGuleFS4DOUSqs6DpAjYlLnXMzUsVMw== - dependencies: - semver "^7.3.7" - -"@humanwhocodes/config-array@^0.10.5": - version "0.10.7" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.10.7.tgz#6d53769fd0c222767e6452e8ebda825c22e9f0dc" - integrity sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w== +"@humanwhocodes/config-array@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" + integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" - minimatch "^3.0.4" + "@humanwhocodes/object-schema" "^2.0.3" + debug "^4.3.1" + minimatch "^3.0.5" "@humanwhocodes/module-importer@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@humanwhocodes/object-schema@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" "@jridgewell/resolve-uri@^3.0.3": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" - integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== "@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.14" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" - integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== "@jridgewell/trace-mapping@0.3.9": version "0.3.9" @@ -500,31 +1339,73 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@metamask/eth-sig-util@^4.0.0": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz#3ad61f6ea9ad73ba5b19db780d40d9aae5157088" - integrity sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ== +"@noble/curves@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" + integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== dependencies: - ethereumjs-abi "^0.6.8" - ethereumjs-util "^6.2.1" - ethjs-util "^0.1.6" - tweetnacl "^1.0.3" - tweetnacl-util "^0.15.1" + "@noble/hashes" "1.3.2" -"@noble/hashes@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.2.tgz#e9e035b9b166ca0af657a7848eb2718f0f22f183" - integrity sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA== +"@noble/curves@1.4.2", "@noble/curves@~1.4.0": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.4.2.tgz#40309198c76ed71bc6dbf7ba24e81ceb4d0d1fe9" + integrity sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw== + dependencies: + "@noble/hashes" "1.4.0" -"@noble/hashes@~1.1.1": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.3.tgz#360afc77610e0a61f3417e497dcf36862e4f8111" - integrity sha512-CE0FCR57H2acVI5UOzIGSSIYxZ6v/HOhDR0Ro9VLyhnzLwx0o8W1mmgaqlEUx4049qJDlIBRztv5k+MM8vbO3A== +"@noble/curves@~1.8.1": + version "1.8.2" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.8.2.tgz#8f24c037795e22b90ae29e222a856294c1d9ffc7" + integrity sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g== + dependencies: + "@noble/hashes" "1.7.2" + +"@noble/curves@~1.9.2": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.4.tgz#a748c6837ee7854a558cc3b951aedd87a5e7d6a5" + integrity sha512-2bKONnuM53lINoDrSmK8qP8W271ms7pygDhZt4SiLOoLwBtoHqeCFi6RG42V8zd3mLHuJFhU/Bmaqo4nX0/kBw== + dependencies: + "@noble/hashes" "1.8.0" + +"@noble/hashes@1.2.0", "@noble/hashes@~1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" + integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== + +"@noble/hashes@1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" + integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== + +"@noble/hashes@1.4.0", "@noble/hashes@~1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" + integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== + +"@noble/hashes@1.7.2", "@noble/hashes@~1.7.1": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.2.tgz#d53c65a21658fb02f3303e7ee3ba89d6754c64b4" + integrity sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ== + +"@noble/hashes@1.8.0", "@noble/hashes@^1.4.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.8.0.tgz#cee43d801fcef9644b11b8194857695acd5f815a" + integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== -"@noble/secp256k1@1.6.3", "@noble/secp256k1@~1.6.0": - version "1.6.3" - resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.6.3.tgz#7eed12d9f4404b416999d0c87686836c4c5c9b94" - integrity sha512-T04e4iTurVy7I8Sw4+c5OSN9/RkPlo1uKxAomtxQNLq8j1uPAqnsqG1bqvY3Jv7c13gyr6dui0zmh/I3+f/JaQ== +"@noble/hashes@2.0.0-beta.1": + version "2.0.0-beta.1" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-2.0.0-beta.1.tgz#641fd2f13e25ae2acdc7d0b082289a5adeda13cf" + integrity sha512-xnnogJ6ccNZ55lLgWdjhBqKUdFoznjpFr3oy23n5Qm7h+ZMtt8v4zWvHg9zRW6jcETweplD5F4iUqb0SSPC+Dw== + +"@noble/secp256k1@1.7.1": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" + integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== + +"@noble/secp256k1@~1.7.0": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.2.tgz#c2c3343e2dce80e15a914d7442147507f8a98e7f" + integrity sha512-/qzwYl5eFLH8OWIecQWM31qld2g1NfjgylK+TNhqtaUKP37Nm+Y+z30Fjhw0Ct8p9yCQEm2N3W/AckdIb3SMcQ== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -539,7 +1420,7 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.walk@^1.2.3": +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== @@ -547,286 +1428,222 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@nomicfoundation/edr-darwin-arm64@0.6.5": - version "0.6.5" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.6.5.tgz#37a31565d7ef42bed9028ac44aed82144de30bd1" - integrity sha512-A9zCCbbNxBpLgjS1kEJSpqxIvGGAX4cYbpDYCU2f3jVqOwaZ/NU761y1SvuCRVpOwhoCXqByN9b7HPpHi0L4hw== - -"@nomicfoundation/edr-darwin-x64@0.6.5": - version "0.6.5" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.6.5.tgz#3252f6e86397af460b7a480bfe1b889464d75b89" - integrity sha512-x3zBY/v3R0modR5CzlL6qMfFMdgwd6oHrWpTkuuXnPFOX8SU31qq87/230f4szM+ukGK8Hi+mNq7Ro2VF4Fj+w== - -"@nomicfoundation/edr-linux-arm64-gnu@0.6.5": - version "0.6.5" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.6.5.tgz#e7dc2934920b6cfabeb5ee7a5e26c8fb0d4964ac" - integrity sha512-HGpB8f1h8ogqPHTyUpyPRKZxUk2lu061g97dOQ/W4CxevI0s/qiw5DB3U3smLvSnBHKOzYS1jkxlMeGN01ky7A== - -"@nomicfoundation/edr-linux-arm64-musl@0.6.5": - version "0.6.5" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.6.5.tgz#00459cd53e9fb7bd5b7e32128b508a6e89079d89" - integrity sha512-ESvJM5Y9XC03fZg9KaQg3Hl+mbx7dsSkTIAndoJS7X2SyakpL9KZpOSYrDk135o8s9P9lYJdPOyiq+Sh+XoCbQ== - -"@nomicfoundation/edr-linux-x64-gnu@0.6.5": - version "0.6.5" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.6.5.tgz#5c9e4e2655caba48e0196977cba395bbde6fe97d" - integrity sha512-HCM1usyAR1Ew6RYf5AkMYGvHBy64cPA5NMbaeY72r0mpKaH3txiMyydcHibByOGdQ8iFLWpyUdpl1egotw+Tgg== - -"@nomicfoundation/edr-linux-x64-musl@0.6.5": - version "0.6.5" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.6.5.tgz#9c220751b66452dc43a365f380e1e236a0a8c5a9" - integrity sha512-nB2uFRyczhAvWUH7NjCsIO6rHnQrof3xcCe6Mpmnzfl2PYcGyxN7iO4ZMmRcQS7R1Y670VH6+8ZBiRn8k43m7A== - -"@nomicfoundation/edr-win32-x64-msvc@0.6.5": - version "0.6.5" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.6.5.tgz#90d3ac2a6a8a687522bda5ff2e92dd97e68126ea" - integrity sha512-B9QD/4DSSCFtWicO8A3BrsnitO1FPv7axB62wq5Q+qeJ50yJlTmyeGY3cw62gWItdvy2mh3fRM6L1LpnHiB77A== - -"@nomicfoundation/edr@^0.6.4": - version "0.6.5" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.6.5.tgz#b3b1ebcdd0148cfe67cca128e7ebe8092e200359" - integrity sha512-tAqMslLP+/2b2sZP4qe9AuGxG3OkQ5gGgHE4isUuq6dUVjwCRPFhAOhpdFl+OjY5P3yEv3hmq9HjUGRa2VNjng== - dependencies: - "@nomicfoundation/edr-darwin-arm64" "0.6.5" - "@nomicfoundation/edr-darwin-x64" "0.6.5" - "@nomicfoundation/edr-linux-arm64-gnu" "0.6.5" - "@nomicfoundation/edr-linux-arm64-musl" "0.6.5" - "@nomicfoundation/edr-linux-x64-gnu" "0.6.5" - "@nomicfoundation/edr-linux-x64-musl" "0.6.5" - "@nomicfoundation/edr-win32-x64-msvc" "0.6.5" - -"@nomicfoundation/ethereumjs-block@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-4.0.0.tgz#fdd5c045e7baa5169abeed0e1202bf94e4481c49" - integrity sha512-bk8uP8VuexLgyIZAHExH1QEovqx0Lzhc9Ntm63nCRKLHXIZkobaFaeCVwTESV7YkPKUk7NiK11s8ryed4CS9yA== - dependencies: - "@nomicfoundation/ethereumjs-common" "^3.0.0" - "@nomicfoundation/ethereumjs-rlp" "^4.0.0" - "@nomicfoundation/ethereumjs-trie" "^5.0.0" - "@nomicfoundation/ethereumjs-tx" "^4.0.0" - "@nomicfoundation/ethereumjs-util" "^8.0.0" - ethereum-cryptography "0.1.3" - -"@nomicfoundation/ethereumjs-blockchain@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-6.0.0.tgz#1a8c243a46d4d3691631f139bfb3a4a157187b0c" - integrity sha512-pLFEoea6MWd81QQYSReLlLfH7N9v7lH66JC/NMPN848ySPPQA5renWnE7wPByfQFzNrPBuDDRFFULMDmj1C0xw== - dependencies: - "@nomicfoundation/ethereumjs-block" "^4.0.0" - "@nomicfoundation/ethereumjs-common" "^3.0.0" - "@nomicfoundation/ethereumjs-ethash" "^2.0.0" - "@nomicfoundation/ethereumjs-rlp" "^4.0.0" - "@nomicfoundation/ethereumjs-trie" "^5.0.0" - "@nomicfoundation/ethereumjs-util" "^8.0.0" - abstract-level "^1.0.3" - debug "^4.3.3" - ethereum-cryptography "0.1.3" - level "^8.0.0" - lru-cache "^5.1.1" - memory-level "^1.0.0" - -"@nomicfoundation/ethereumjs-common@4.0.4": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.4.tgz#9901f513af2d4802da87c66d6f255b510bef5acb" - integrity sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg== - dependencies: - "@nomicfoundation/ethereumjs-util" "9.0.4" - -"@nomicfoundation/ethereumjs-common@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-3.0.0.tgz#f6bcc7753994555e49ab3aa517fc8bcf89c280b9" - integrity sha512-WS7qSshQfxoZOpHG/XqlHEGRG1zmyjYrvmATvc4c62+gZXgre1ymYP8ZNgx/3FyZY0TWe9OjFlKOfLqmgOeYwA== - dependencies: - "@nomicfoundation/ethereumjs-util" "^8.0.0" - crc-32 "^1.2.0" - -"@nomicfoundation/ethereumjs-ethash@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-2.0.0.tgz#11539c32fe0990e1122ff987d1b84cfa34774e81" - integrity sha512-WpDvnRncfDUuXdsAXlI4lXbqUDOA+adYRQaEezIkxqDkc+LDyYDbd/xairmY98GnQzo1zIqsIL6GB5MoMSJDew== - dependencies: - "@nomicfoundation/ethereumjs-block" "^4.0.0" - "@nomicfoundation/ethereumjs-rlp" "^4.0.0" - "@nomicfoundation/ethereumjs-util" "^8.0.0" - abstract-level "^1.0.3" - bigint-crypto-utils "^3.0.23" - ethereum-cryptography "0.1.3" - -"@nomicfoundation/ethereumjs-evm@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-1.0.0.tgz#99cd173c03b59107c156a69c5e215409098a370b" - integrity sha512-hVS6qRo3V1PLKCO210UfcEQHvlG7GqR8iFzp0yyjTg2TmJQizcChKgWo8KFsdMw6AyoLgLhHGHw4HdlP8a4i+Q== - dependencies: - "@nomicfoundation/ethereumjs-common" "^3.0.0" - "@nomicfoundation/ethereumjs-util" "^8.0.0" - "@types/async-eventemitter" "^0.2.1" - async-eventemitter "^0.2.4" - debug "^4.3.3" - ethereum-cryptography "0.1.3" - mcl-wasm "^0.7.1" - rustbn.js "~0.2.0" - -"@nomicfoundation/ethereumjs-rlp@5.0.4", "@nomicfoundation/ethereumjs-rlp@^5.0.4": +"@nomicfoundation/edr-darwin-arm64@0.11.2": + version "0.11.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.11.2.tgz#0debc904abf5ad710b3e024b2537ca5ae7d3fbee" + integrity sha512-/QU0GHeoLFOJp28qK46kkTG849NN/5Qgq9ifKzhqBas1MCqwcdjrUI3raGkvE9SWJevljWd1HdW16fFpxUrzbA== + +"@nomicfoundation/edr-darwin-arm64@0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.11.3.tgz#d8e2609fc24cf20e75c3782e39cd5a95f7488075" + integrity sha512-w0tksbdtSxz9nuzHKsfx4c2mwaD0+l5qKL2R290QdnN9gi9AV62p9DHkOgfBdyg6/a6ZlnQqnISi7C9avk/6VA== + +"@nomicfoundation/edr-darwin-x64@0.11.2": + version "0.11.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.11.2.tgz#811b0c068e016c1b11611cde2de15e986b4d766d" + integrity sha512-Dam+k00vyYNXCkM7JZGQBm0McNaL6ilbfY8BuIdHU2mpIVO5hpAFk8IQnMnG3FRuXuPJ0JoSTkn1R495T8AKqw== + +"@nomicfoundation/edr-darwin-x64@0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.11.3.tgz#7a9e94cee330269a33c7f1dce267560c7e12dbd3" + integrity sha512-QR4jAFrPbOcrO7O2z2ESg+eUeIZPe2bPIlQYgiJ04ltbSGW27FblOzdd5+S3RoOD/dsZGKAvvy6dadBEl0NgoA== + +"@nomicfoundation/edr-linux-arm64-gnu@0.11.2": + version "0.11.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.11.2.tgz#6dc83499408ba053978062ad4371cc8becddfe73" + integrity sha512-6Z+hZ61c0v5EPVhCAc/rV36eN20GbPRfcmUeFJ3t+RjdY20EiUQzP85YU0q3AgCuwr410W27pazoBoL73cCPbg== + +"@nomicfoundation/edr-linux-arm64-gnu@0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.11.3.tgz#cd5ec90c7263045c3dfd0b109c73206e488edc27" + integrity sha512-Ktjv89RZZiUmOFPspuSBVJ61mBZQ2+HuLmV67InNlh9TSUec/iDjGIwAn59dx0bF/LOSrM7qg5od3KKac4LJDQ== + +"@nomicfoundation/edr-linux-arm64-musl@0.11.2": + version "0.11.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.11.2.tgz#1001dcaf33e6c8e00c0934a04aeaa6683cefa158" + integrity sha512-AqC4AI3pR4vSsEcFyW/6rI1q16wEjIRYIR25IJO/EdBmXdsuVZgxsf/kMUCWQhhTuy89RTgIGTbMAQA0+DfSvA== + +"@nomicfoundation/edr-linux-arm64-musl@0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.11.3.tgz#ed23df2d9844470f5661716da27d99a72a69e99e" + integrity sha512-B3sLJx1rL2E9pfdD4mApiwOZSrX0a/KQSBWdlq1uAhFKqkl00yZaY4LejgZndsJAa4iKGQJlGnw4HCGeVt0+jA== + +"@nomicfoundation/edr-linux-x64-gnu@0.11.2": + version "0.11.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.11.2.tgz#ddb68776b95d2666340817908a0e1bd470761d14" + integrity sha512-vz1uiof1ZIi6RnXfHZiAXRgkloLciuYGD1rNDrqm1Pp7Nf0pbxw+e4TBQLoMYKzZn0MYS4u4Fa0AV2S7NjfptQ== + +"@nomicfoundation/edr-linux-x64-gnu@0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.11.3.tgz#87a62496c2c4b808bc4a9ae96cca1642a21c2b51" + integrity sha512-D/4cFKDXH6UYyKPu6J3Y8TzW11UzeQI0+wS9QcJzjlrrfKj0ENW7g9VihD1O2FvXkdkTjcCZYb6ai8MMTCsaVw== + +"@nomicfoundation/edr-linux-x64-musl@0.11.2": + version "0.11.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.11.2.tgz#3ed4cd7f2d3879122e0b24b6433bf3d2eaadd349" + integrity sha512-ArAbcrWwn+8Ze8JAaA9349N2E7hfs9PYvxDgfhujEH9iVC9XI6L+OhMATPsS3wkOST/+ykxELAF1KT4YjSxcrA== + +"@nomicfoundation/edr-linux-x64-musl@0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.11.3.tgz#8cfe408c73bcb9ed5e263910c313866d442f4b48" + integrity sha512-ergXuIb4nIvmf+TqyiDX5tsE49311DrBky6+jNLgsGDTBaN1GS3OFwFS8I6Ri/GGn6xOaT8sKu3q7/m+WdlFzg== + +"@nomicfoundation/edr-win32-x64-msvc@0.11.2": + version "0.11.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.11.2.tgz#459a6af0e99a88f78cf2ac54fe32a7b702bdd2a7" + integrity sha512-GDXBhxy5wlmZYQrTXu9Oh9OPTsi4tCdmHy1z8O9XqdH9wsP674Frh6Fb43yjVoS2Ek1F9yX11nexIrFXSuNyJQ== + +"@nomicfoundation/edr-win32-x64-msvc@0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.11.3.tgz#fb208b94553c7eb22246d73a1ac4de5bfdb97d01" + integrity sha512-snvEf+WB3OV0wj2A7kQ+ZQqBquMcrozSLXcdnMdEl7Tmn+KDCbmFKBt3Tk0X3qOU4RKQpLPnTxdM07TJNVtung== + +"@nomicfoundation/edr@^0.11.1": + version "0.11.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.11.2.tgz#fd85fc404de656bc14228d88f7ada562cc10d522" + integrity sha512-JEFMTs5Tju+YiCsv6EO+657O/fvPaQ7bkUCkWqHFYFFbCKH1yh0PeRIaqj5h4z4O16ckxbVpAM676ZFTmvFUGQ== + dependencies: + "@nomicfoundation/edr-darwin-arm64" "0.11.2" + "@nomicfoundation/edr-darwin-x64" "0.11.2" + "@nomicfoundation/edr-linux-arm64-gnu" "0.11.2" + "@nomicfoundation/edr-linux-arm64-musl" "0.11.2" + "@nomicfoundation/edr-linux-x64-gnu" "0.11.2" + "@nomicfoundation/edr-linux-x64-musl" "0.11.2" + "@nomicfoundation/edr-win32-x64-msvc" "0.11.2" + +"@nomicfoundation/edr@^0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.11.3.tgz#e8b30b868788e45d7a2ee2359a021ef7dcb96952" + integrity sha512-kqILRkAd455Sd6v8mfP3C1/0tCOynJWY+Ir+k/9Boocu2kObCrsFgG+ZWB7fSBVdd9cPVSNrnhWS+V+PEo637g== + dependencies: + "@nomicfoundation/edr-darwin-arm64" "0.11.3" + "@nomicfoundation/edr-darwin-x64" "0.11.3" + "@nomicfoundation/edr-linux-arm64-gnu" "0.11.3" + "@nomicfoundation/edr-linux-arm64-musl" "0.11.3" + "@nomicfoundation/edr-linux-x64-gnu" "0.11.3" + "@nomicfoundation/edr-linux-x64-musl" "0.11.3" + "@nomicfoundation/edr-win32-x64-msvc" "0.11.3" + +"@nomicfoundation/ethereumjs-rlp@^5.0.4": version "5.0.4" resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.4.tgz#66c95256fc3c909f6fb18f6a586475fc9762fa30" integrity sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw== -"@nomicfoundation/ethereumjs-rlp@^4.0.0", "@nomicfoundation/ethereumjs-rlp@^4.0.0-beta.2": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-4.0.0.tgz#d9a9c5f0f10310c8849b6525101de455a53e771d" - integrity sha512-GaSOGk5QbUk4eBP5qFbpXoZoZUj/NrW7MRa0tKY4Ew4c2HAS0GXArEMAamtFrkazp0BO4K5p2ZCG3b2FmbShmw== - -"@nomicfoundation/ethereumjs-statemanager@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-1.0.0.tgz#14a9d4e1c828230368f7ab520c144c34d8721e4b" - integrity sha512-jCtqFjcd2QejtuAMjQzbil/4NHf5aAWxUc+CvS0JclQpl+7M0bxMofR2AJdtz+P3u0ke2euhYREDiE7iSO31vQ== - dependencies: - "@nomicfoundation/ethereumjs-common" "^3.0.0" - "@nomicfoundation/ethereumjs-rlp" "^4.0.0" - "@nomicfoundation/ethereumjs-trie" "^5.0.0" - "@nomicfoundation/ethereumjs-util" "^8.0.0" - debug "^4.3.3" - ethereum-cryptography "0.1.3" - functional-red-black-tree "^1.0.1" - -"@nomicfoundation/ethereumjs-trie@^5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-5.0.0.tgz#dcfbe3be53a94bc061c9767a396c16702bc2f5b7" - integrity sha512-LIj5XdE+s+t6WSuq/ttegJzZ1vliwg6wlb+Y9f4RlBpuK35B9K02bO7xU+E6Rgg9RGptkWd6TVLdedTI4eNc2A== - dependencies: - "@nomicfoundation/ethereumjs-rlp" "^4.0.0" - "@nomicfoundation/ethereumjs-util" "^8.0.0" - ethereum-cryptography "0.1.3" - readable-stream "^3.6.0" - -"@nomicfoundation/ethereumjs-tx@5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.4.tgz#b0ceb58c98cc34367d40a30d255d6315b2f456da" - integrity sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw== +"@nomicfoundation/hardhat-ethers@3.0.9", "@nomicfoundation/hardhat-ethers@^3.0.0": + version "3.0.9" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.9.tgz#a1fa5b123db39e4ee4ae86bee0e458e2b733ce02" + integrity sha512-xBJdRUiCwKpr0OYrOzPwAyNGtsVzoBx32HFPJVv6S+sFA9TmBIBDaqNlFPmBH58ZjgNnGhEr/4oBZvGr4q4TjQ== dependencies: - "@nomicfoundation/ethereumjs-common" "4.0.4" - "@nomicfoundation/ethereumjs-rlp" "5.0.4" - "@nomicfoundation/ethereumjs-util" "9.0.4" - ethereum-cryptography "0.1.3" + debug "^4.1.1" + lodash.isequal "^4.5.0" -"@nomicfoundation/ethereumjs-tx@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-4.0.0.tgz#59dc7452b0862b30342966f7052ab9a1f7802f52" - integrity sha512-Gg3Lir2lNUck43Kp/3x6TfBNwcWC9Z1wYue9Nz3v4xjdcv6oDW9QSMJxqsKw9QEGoBBZ+gqwpW7+F05/rs/g1w== +"@nomicfoundation/hardhat-ignition@^0.15.5": + version "0.15.12" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-ignition/-/hardhat-ignition-0.15.12.tgz#99dfbb69b9f930b6ef6b33a39f5bc9736fed75ed" + integrity sha512-T03bSjFy8vWeKGvFsR42vzl4PgmW06i1e/84m2oowZzdO3i9ax3XJhRiH4kC08QXzkdAdUPinx68hQea8Wh6Jw== dependencies: - "@nomicfoundation/ethereumjs-common" "^3.0.0" - "@nomicfoundation/ethereumjs-rlp" "^4.0.0" - "@nomicfoundation/ethereumjs-util" "^8.0.0" - ethereum-cryptography "0.1.3" + "@nomicfoundation/ignition-core" "^0.15.12" + "@nomicfoundation/ignition-ui" "^0.15.11" + chalk "^4.0.0" + debug "^4.3.2" + fs-extra "^10.0.0" + json5 "^2.2.3" + prompts "^2.4.2" -"@nomicfoundation/ethereumjs-util@9.0.4": - version "9.0.4" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.4.tgz#84c5274e82018b154244c877b76bc049a4ed7b38" - integrity sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q== +"@nomicfoundation/hardhat-verify@^2.0.8": + version "2.0.14" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.14.tgz#ba80918fac840f1165825f2a422a694486f82f6f" + integrity sha512-z3iVF1WYZHzcdMMUuureFpSAfcnlfJbJx3faOnGrOYg6PRTki1Ut9JAuRccnFzMHf1AmTEoSUpWcyvBCoxL5Rg== dependencies: - "@nomicfoundation/ethereumjs-rlp" "5.0.4" - ethereum-cryptography "0.1.3" + "@ethersproject/abi" "^5.1.2" + "@ethersproject/address" "^5.0.2" + cbor "^8.1.0" + debug "^4.1.1" + lodash.clonedeep "^4.5.0" + picocolors "^1.1.0" + semver "^6.3.0" + table "^6.8.0" + undici "^5.14.0" -"@nomicfoundation/ethereumjs-util@^8.0.0": - version "8.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-8.0.0.tgz#deb2b15d2c308a731e82977aefc4e61ca0ece6c5" - integrity sha512-2emi0NJ/HmTG+CGY58fa+DQuAoroFeSH9gKu9O6JnwTtlzJtgfTixuoOqLEgyyzZVvwfIpRueuePb8TonL1y+A== +"@nomicfoundation/ignition-core@^0.15.12": + version "0.15.12" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ignition-core/-/ignition-core-0.15.12.tgz#c09c5aa493e54d82bf1737fa3852428185905f90" + integrity sha512-JJdyoyfM5RXaUqv4c2V/8xpuui4uqJbMCvVnEhgo6FMOK6bqj8wGP6hM4gNE5TLug6ZUCdjIB8kFpofl21RycQ== dependencies: - "@nomicfoundation/ethereumjs-rlp" "^4.0.0-beta.2" - ethereum-cryptography "0.1.3" - -"@nomicfoundation/ethereumjs-vm@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-6.0.0.tgz#2bb50d332bf41790b01a3767ffec3987585d1de6" - integrity sha512-JMPxvPQ3fzD063Sg3Tp+UdwUkVxMoo1uML6KSzFhMH3hoQi/LMuXBoEHAoW83/vyNS9BxEe6jm6LmT5xdeEJ6w== - dependencies: - "@nomicfoundation/ethereumjs-block" "^4.0.0" - "@nomicfoundation/ethereumjs-blockchain" "^6.0.0" - "@nomicfoundation/ethereumjs-common" "^3.0.0" - "@nomicfoundation/ethereumjs-evm" "^1.0.0" - "@nomicfoundation/ethereumjs-rlp" "^4.0.0" - "@nomicfoundation/ethereumjs-statemanager" "^1.0.0" - "@nomicfoundation/ethereumjs-trie" "^5.0.0" - "@nomicfoundation/ethereumjs-tx" "^4.0.0" - "@nomicfoundation/ethereumjs-util" "^8.0.0" - "@types/async-eventemitter" "^0.2.1" - async-eventemitter "^0.2.4" - debug "^4.3.3" - ethereum-cryptography "0.1.3" - functional-red-black-tree "^1.0.1" - mcl-wasm "^0.7.1" - rustbn.js "~0.2.0" - -"@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.0.tgz#83a7367342bd053a76d04bbcf4f373fef07cf760" - integrity sha512-vEF3yKuuzfMHsZecHQcnkUrqm8mnTWfJeEVFHpg+cO+le96xQA4lAJYdUan8pXZohQxv1fSReQsn4QGNuBNuCw== + "@ethersproject/address" "5.6.1" + "@nomicfoundation/solidity-analyzer" "^0.1.1" + cbor "^9.0.0" + debug "^4.3.2" + ethers "^6.14.0" + fs-extra "^10.0.0" + immer "10.0.2" + lodash "4.17.21" + ndjson "2.0.0" -"@nomicfoundation/solidity-analyzer-darwin-x64@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.0.tgz#1225f7da647ae1ad25a87125664704ecc0af6ccc" - integrity sha512-dlHeIg0pTL4dB1l9JDwbi/JG6dHQaU1xpDK+ugYO8eJ1kxx9Dh2isEUtA4d02cQAl22cjOHTvifAk96A+ItEHA== +"@nomicfoundation/ignition-ui@^0.15.11": + version "0.15.11" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ignition-ui/-/ignition-ui-0.15.11.tgz#94969984dd6ca1671a21f2338af4735cf319c1b3" + integrity sha512-VPOVl5xqCKhYCyPOQlposx+stjCwqXQ+BCs5lnw/f2YUfgII+G5Ye0JfHiJOfCJGmqyS03WertBslcj9zQg50A== -"@nomicfoundation/solidity-analyzer-freebsd-x64@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-freebsd-x64/-/solidity-analyzer-freebsd-x64-0.1.0.tgz#dbc052dcdfd50ae50fd5ae1788b69b4e0fa40040" - integrity sha512-WFCZYMv86WowDA4GiJKnebMQRt3kCcFqHeIomW6NMyqiKqhK1kIZCxSLDYsxqlx396kKLPN1713Q1S8tu68GKg== +"@nomicfoundation/slang@^0.18.3": + version "0.18.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/slang/-/slang-0.18.3.tgz#976b6c3820081cebf050afbea434038aac9313cc" + integrity sha512-YqAWgckqbHM0/CZxi9Nlf4hjk9wUNLC9ngWCWBiqMxPIZmzsVKYuChdlrfeBPQyvQQBoOhbx+7C1005kLVQDZQ== + dependencies: + "@bytecodealliance/preview2-shim" "0.17.0" -"@nomicfoundation/solidity-analyzer-linux-arm64-gnu@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.0.tgz#e6b2eea633995b557e74e881d2a43eab4760903d" - integrity sha512-DTw6MNQWWlCgc71Pq7CEhEqkb7fZnS7oly13pujs4cMH1sR0JzNk90Mp1zpSCsCs4oKan2ClhMlLKtNat/XRKQ== +"@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.2.tgz#3a9c3b20d51360b20affb8f753e756d553d49557" + integrity sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw== -"@nomicfoundation/solidity-analyzer-linux-arm64-musl@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.0.tgz#af81107f5afa794f19988a368647727806e18dc4" - integrity sha512-wUpUnR/3GV5Da88MhrxXh/lhb9kxh9V3Jya2NpBEhKDIRCDmtXMSqPMXHZmOR9DfCwCvG6vLFPr/+YrPCnUN0w== +"@nomicfoundation/solidity-analyzer-darwin-x64@0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.2.tgz#74dcfabeb4ca373d95bd0d13692f44fcef133c28" + integrity sha512-fZNmVztrSXC03e9RONBT+CiksSeYcxI1wlzqyr0L7hsQlK1fzV+f04g2JtQ1c/Fe74ZwdV6aQBdd6Uwl1052sw== -"@nomicfoundation/solidity-analyzer-linux-x64-gnu@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.0.tgz#6877e1da1a06a9f08446070ab6e0a5347109f868" - integrity sha512-lR0AxK1x/MeKQ/3Pt923kPvwigmGX3OxeU5qNtQ9pj9iucgk4PzhbS3ruUeSpYhUxG50jN4RkIGwUMoev5lguw== +"@nomicfoundation/solidity-analyzer-linux-arm64-gnu@0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.2.tgz#4af5849a89e5a8f511acc04f28eb5d4460ba2b6a" + integrity sha512-3d54oc+9ZVBuB6nbp8wHylk4xh0N0Gc+bk+/uJae+rUgbOBwQSfuGIbAZt1wBXs5REkSmynEGcqx6DutoK0tPA== -"@nomicfoundation/solidity-analyzer-linux-x64-musl@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.0.tgz#bb6cd83a0c259eccef4183796b6329a66cf7ebd9" - integrity sha512-A1he/8gy/JeBD3FKvmI6WUJrGrI5uWJNr5Xb9WdV+DK0F8msuOqpEByLlnTdLkXMwW7nSl3awvLezOs9xBHJEg== +"@nomicfoundation/solidity-analyzer-linux-arm64-musl@0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.2.tgz#54036808a9a327b2ff84446c130a6687ee702a8e" + integrity sha512-iDJfR2qf55vgsg7BtJa7iPiFAsYf2d0Tv/0B+vhtnI16+wfQeTbP7teookbGvAo0eJo7aLLm0xfS/GTkvHIucA== -"@nomicfoundation/solidity-analyzer-win32-arm64-msvc@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.0.tgz#9d4bca1cc9a1333fde985675083b0b7d165f6076" - integrity sha512-7x5SXZ9R9H4SluJZZP8XPN+ju7Mx+XeUMWZw7ZAqkdhP5mK19I4vz3x0zIWygmfE8RT7uQ5xMap0/9NPsO+ykw== +"@nomicfoundation/solidity-analyzer-linux-x64-gnu@0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.2.tgz#466cda0d6e43691986c944b909fc6dbb8cfc594e" + integrity sha512-9dlHMAt5/2cpWyuJ9fQNOUXFB/vgSFORg1jpjX1Mh9hJ/MfZXlDdHQ+DpFCs32Zk5pxRBb07yGvSHk9/fezL+g== -"@nomicfoundation/solidity-analyzer-win32-ia32-msvc@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.0.tgz#0db5bfc6aa952bea4098d8d2c8947b4e5c4337ee" - integrity sha512-m7w3xf+hnE774YRXu+2mGV7RiF3QJtUoiYU61FascCkQhX3QMQavh7saH/vzb2jN5D24nT/jwvaHYX/MAM9zUw== +"@nomicfoundation/solidity-analyzer-linux-x64-musl@0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.2.tgz#2b35826987a6e94444140ac92310baa088ee7f94" + integrity sha512-GzzVeeJob3lfrSlDKQw2bRJ8rBf6mEYaWY+gW0JnTDHINA0s2gPR4km5RLIj1xeZZOYz4zRw+AEeYgLRqB2NXg== -"@nomicfoundation/solidity-analyzer-win32-x64-msvc@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.0.tgz#2e0f39a2924dcd77db6b419828595e984fabcb33" - integrity sha512-xCuybjY0sLJQnJhupiFAXaek2EqF0AP0eBjgzaalPXSNvCEN6ZYHvUzdA50ENDVeSYFXcUsYf3+FsD3XKaeptA== +"@nomicfoundation/solidity-analyzer-win32-x64-msvc@0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.2.tgz#e6363d13b8709ca66f330562337dbc01ce8bbbd9" + integrity sha512-Fdjli4DCcFHb4Zgsz0uEJXZ2K7VEO+w5KVv7HmT7WO10iODdU9csC2az4jrhEsRtiR9Gfd74FlG0NYlw1BMdyA== -"@nomicfoundation/solidity-analyzer@^0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.0.tgz#e5ddc43ad5c0aab96e5054520d8e16212e125f50" - integrity sha512-xGWAiVCGOycvGiP/qrlf9f9eOn7fpNbyJygcB0P21a1MDuVPlKt0Srp7rvtBEutYQ48ouYnRXm33zlRnlTOPHg== +"@nomicfoundation/solidity-analyzer@^0.1.0", "@nomicfoundation/solidity-analyzer@^0.1.1": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.2.tgz#8bcea7d300157bf3a770a851d9f5c5e2db34ac55" + integrity sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA== optionalDependencies: - "@nomicfoundation/solidity-analyzer-darwin-arm64" "0.1.0" - "@nomicfoundation/solidity-analyzer-darwin-x64" "0.1.0" - "@nomicfoundation/solidity-analyzer-freebsd-x64" "0.1.0" - "@nomicfoundation/solidity-analyzer-linux-arm64-gnu" "0.1.0" - "@nomicfoundation/solidity-analyzer-linux-arm64-musl" "0.1.0" - "@nomicfoundation/solidity-analyzer-linux-x64-gnu" "0.1.0" - "@nomicfoundation/solidity-analyzer-linux-x64-musl" "0.1.0" - "@nomicfoundation/solidity-analyzer-win32-arm64-msvc" "0.1.0" - "@nomicfoundation/solidity-analyzer-win32-ia32-msvc" "0.1.0" - "@nomicfoundation/solidity-analyzer-win32-x64-msvc" "0.1.0" + "@nomicfoundation/solidity-analyzer-darwin-arm64" "0.1.2" + "@nomicfoundation/solidity-analyzer-darwin-x64" "0.1.2" + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu" "0.1.2" + "@nomicfoundation/solidity-analyzer-linux-arm64-musl" "0.1.2" + "@nomicfoundation/solidity-analyzer-linux-x64-gnu" "0.1.2" + "@nomicfoundation/solidity-analyzer-linux-x64-musl" "0.1.2" + "@nomicfoundation/solidity-analyzer-win32-x64-msvc" "0.1.2" "@nomiclabs/hardhat-ethers@^2.0.4": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.2.0.tgz#f55ace2752d0effcf583e754960e9fa89fbe12cd" - integrity sha512-kKCW7xawuD/lw69Yr1yqUUrF0IKmnLNGf+pTVbJ/ctHaRcPrwKI0EPkO1RNXBHlOOZkv6v4DK2PPvq0lL2ykig== + version "2.2.3" + resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.2.3.tgz#b41053e360c31a32c2640c9a45ee981a7e603fe0" + integrity sha512-YhzPdzb612X591FOe68q+qXVXGG2ANZRvDo0RRUtimev85rCrAlv/TLMEZw5c+kq9AbzocLTVX/h2jVIFPL9Xg== "@nomiclabs/hardhat-etherscan@3.1.7": version "3.1.7" @@ -844,77 +1661,187 @@ table "^6.8.0" undici "^5.14.0" -"@safe-global/safe-core-sdk-types@^1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@safe-global/safe-core-sdk-types/-/safe-core-sdk-types-1.9.0.tgz#dba18f34ab905da6c1c03a3262aeb47cc0bead14" - integrity sha512-3VFhnggdLT9kWhnb35eqxEC9cVpW5Sl4E51TZo0RmH1cSzMwlNDbeGINb38PpUbw/wwXFJbCVFmeXELz2ZlCfw== +"@npmcli/agent@^2.0.0": + version "2.2.2" + resolved "https://registry.yarnpkg.com/@npmcli/agent/-/agent-2.2.2.tgz#967604918e62f620a648c7975461c9c9e74fc5d5" + integrity sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og== + dependencies: + agent-base "^7.1.0" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.1" + lru-cache "^10.0.1" + socks-proxy-agent "^8.0.3" + +"@npmcli/fs@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-3.1.1.tgz#59cdaa5adca95d135fc00f2bb53f5771575ce726" + integrity sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg== + dependencies: + semver "^7.3.5" + +"@npmcli/redact@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@npmcli/redact/-/redact-2.0.1.tgz#95432fd566e63b35c04494621767a4312c316762" + integrity sha512-YgsR5jCQZhVmTJvjduTOIHph0L73pK8xwMVaDY0PatySqVM9AZj93jpoXYSJqfHFxFkN9dmqTw6OiqExsS3LPw== + +"@openzeppelin/defender-sdk-base-client@^2.1.0", "@openzeppelin/defender-sdk-base-client@^2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-base-client/-/defender-sdk-base-client-2.6.0.tgz#8832267b4be5520360f1e336da36829a12f311b6" + integrity sha512-adwCU4kSZGIrqNYyhgHJ3A1ZE95TAjqkXEzD/4p5YYQ3Sfq9evxgJSplri4Ek2zazdoc8VpzAXY9/sKFhRJtjA== + dependencies: + "@aws-sdk/client-lambda" "^3.563.0" + amazon-cognito-identity-js "^6.3.6" + async-retry "^1.3.3" + +"@openzeppelin/defender-sdk-deploy-client@^2.1.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-deploy-client/-/defender-sdk-deploy-client-2.6.0.tgz#6f49c26d65eba9f3c02ed13704f212daafada9af" + integrity sha512-PoV+M5QS9Hh9PiLL+OURLczT83kO6vO6qcCquSEtmBm3zmlo1ZOepdiqKo+rcrn765QKW9u+FnC31HycicVJWw== + dependencies: + "@openzeppelin/defender-sdk-base-client" "^2.6.0" + axios "^1.7.4" + lodash "^4.17.21" + +"@openzeppelin/defender-sdk-network-client@^2.1.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-network-client/-/defender-sdk-network-client-2.6.0.tgz#42061b9fcdf77fadfe04ede80c4c13f257fcad2a" + integrity sha512-enVInisj9FsP6RClguiMEN9FSClBp54IRpMwKiopC/yVLjRxp/ZEGSWh8o8sc5Fob3Bb2JCbxSHtY9S6xuxxeQ== + dependencies: + "@openzeppelin/defender-sdk-base-client" "^2.6.0" + axios "^1.7.4" + lodash "^4.17.21" + +"@openzeppelin/hardhat-upgrades@^3.3.0": + version "3.9.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/hardhat-upgrades/-/hardhat-upgrades-3.9.0.tgz#3317292f5e338012d0263bfd0f8458466c3fb0a8" + integrity sha512-7YYBSxRnO/X+tsQkVgtz3/YbwZuQPjbjQ3m0A/8+vgQzdPfulR93NaFKgZfMonnrriXb5O/ULjIDPI+8nuqtyQ== + dependencies: + "@openzeppelin/defender-sdk-base-client" "^2.1.0" + "@openzeppelin/defender-sdk-deploy-client" "^2.1.0" + "@openzeppelin/defender-sdk-network-client" "^2.1.0" + "@openzeppelin/upgrades-core" "^1.41.0" + chalk "^4.1.0" + debug "^4.1.1" + ethereumjs-util "^7.1.5" + proper-lockfile "^4.1.1" + undici "^6.11.1" + +"@openzeppelin/upgrades-core@^1.32.2", "@openzeppelin/upgrades-core@^1.41.0": + version "1.44.1" + resolved "https://registry.yarnpkg.com/@openzeppelin/upgrades-core/-/upgrades-core-1.44.1.tgz#8c1876fef1e52c0d163fda33364b6c77cd4dc1c7" + integrity sha512-yqvDj7eC7m5kCDgqCxVFgk9sVo9SXP/fQFaExPousNfAJJbX+20l4fKZp17aXbNTpo1g+2205s6cR9VhFFOCaQ== + dependencies: + "@nomicfoundation/slang" "^0.18.3" + bignumber.js "^9.1.2" + cbor "^10.0.0" + chalk "^4.1.0" + compare-versions "^6.0.0" + debug "^4.1.1" + ethereumjs-util "^7.0.3" + minimatch "^9.0.5" + minimist "^1.2.7" + proper-lockfile "^4.1.1" + solidity-ast "^0.4.60" + +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@safe-global/safe-core-sdk-types@^1.9.2": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@safe-global/safe-core-sdk-types/-/safe-core-sdk-types-1.10.1.tgz#94331b982671d2f2b8cc23114c58baf63d460c81" + integrity sha512-BKvuYTLOlY16Rq6qCXglmnL6KxInDuXMFqZMaCzwDKiEh+uoHu3xCumG5tVtWOkCgBF4XEZXMqwZUiLcon7IsA== dependencies: "@ethersproject/bignumber" "^5.7.0" "@ethersproject/contracts" "^5.7.0" - "@gnosis.pm/safe-deployments" "1.19.0" + "@safe-global/safe-deployments" "^1.20.2" web3-core "^1.8.1" web3-utils "^1.8.1" -"@safe-global/safe-core-sdk-utils@^1.7.2": - version "1.7.2" - resolved "https://registry.yarnpkg.com/@safe-global/safe-core-sdk-utils/-/safe-core-sdk-utils-1.7.2.tgz#37df64d90060b986a54426a065473eb793c97dd7" - integrity sha512-nlS9/vtd6rj+2IK0tgt4xq6vqdGOAa+6MwAeiYCoP1ihcqFD38k6LBn7ZdXWjRF9VBvMXTgclkjvzp+PkLKtAw== +"@safe-global/safe-core-sdk-utils@^1.7.4": + version "1.7.4" + resolved "https://registry.yarnpkg.com/@safe-global/safe-core-sdk-utils/-/safe-core-sdk-utils-1.7.4.tgz#810d36cf9629129a28eb1b9c6e690b163834b572" + integrity sha512-ITocwSWlFUA1K9VMP/eJiMfgbP/I9qDxAaFz7ukj5N5NZD3ihVQZkmqML6hjse5UhrfjCnfIEcLkNZhtB2XC2Q== dependencies: - "@safe-global/safe-core-sdk-types" "^1.9.0" + "@safe-global/safe-core-sdk-types" "^1.9.2" semver "^7.3.8" web3-utils "^1.8.1" "@safe-global/safe-core-sdk@^3.3.2": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@safe-global/safe-core-sdk/-/safe-core-sdk-3.3.2.tgz#571e38eec152668bf2c04771f62f1b123161ec7c" - integrity sha512-IhAxGyYnnG+Zl2zWe1520l00l+FT1QTeMDQlTtnhKCeISs2krXZSEKuolj/sHltXzrswuntaGElAYJyruWEG/A== + version "3.3.5" + resolved "https://registry.yarnpkg.com/@safe-global/safe-core-sdk/-/safe-core-sdk-3.3.5.tgz#30884639d368a9f50aa5fc96f78de87261ebdab3" + integrity sha512-ul+WmpxZOXgDIXrZ6MIHptThYbm0CVV3/rypMQEn4tZLkudh/yXK7EuWBFnx9prR3MePuku51Zcz9fu1vi7sfQ== dependencies: "@ethersproject/solidity" "^5.7.0" - "@safe-global/safe-core-sdk-types" "^1.9.0" - "@safe-global/safe-core-sdk-utils" "^1.7.2" - "@safe-global/safe-deployments" "^1.20.2" + "@safe-global/safe-core-sdk-types" "^1.9.2" + "@safe-global/safe-core-sdk-utils" "^1.7.4" + "@safe-global/safe-deployments" "^1.25.0" ethereumjs-util "^7.1.5" semver "^7.3.8" web3-utils "^1.8.1" + zksync-web3 "^0.14.3" -"@safe-global/safe-deployments@^1.20.2": - version "1.21.1" - resolved "https://registry.yarnpkg.com/@safe-global/safe-deployments/-/safe-deployments-1.21.1.tgz#28849ab9441855eb10c50f3ae835f34ec69dede4" - integrity sha512-W5+EGdidRupGvMCHBaV3iNvcfqwzjOZcYWlMndCTo/JSHfe1az79AqOyKVSKK5AyEDt5iUlH8tTjmk8vTuQDwA== +"@safe-global/safe-deployments@^1.20.2", "@safe-global/safe-deployments@^1.25.0": + version "1.37.36" + resolved "https://registry.yarnpkg.com/@safe-global/safe-deployments/-/safe-deployments-1.37.36.tgz#1c463cc9000af600056f5e1874527b5679b62505" + integrity sha512-h9vuA659vvjJKf7wgoV5iPIHXWEQMoSkXAIZ2CJEoBteP9vP4LjyuPFp+wVQ6WyQSeHi22HjrlvGXxZD72Kqqw== dependencies: - semver "^7.3.7" + semver "^7.6.2" "@safe-global/safe-ethers-lib@^1.9.2": - version "1.9.2" - resolved "https://registry.yarnpkg.com/@safe-global/safe-ethers-lib/-/safe-ethers-lib-1.9.2.tgz#e99e565d832e5b588c661b59936caa78aa1e3952" - integrity sha512-x8Lq6ViRHW9UC+SAF+VOZ8Lt7jXMhbNS/+WYhSdAKhM+SHwkaaDi03pyZgm4FK0C3Zah7vryU3dSDR/CwEtqhQ== + version "1.9.4" + resolved "https://registry.yarnpkg.com/@safe-global/safe-ethers-lib/-/safe-ethers-lib-1.9.4.tgz#049989a302c6f2010c574cf3a834b0cfb9cf67c5" + integrity sha512-WhzcmNun0s0VxeVQKRqaapV0vEpdm76zZBR2Du+S+58u1r57OjZkOSL2Gru0tdwkt3FIZZtE3OhDu09M70pVkA== dependencies: - "@safe-global/safe-core-sdk-types" "^1.9.0" - "@safe-global/safe-core-sdk-utils" "^1.7.2" + "@safe-global/safe-core-sdk-types" "^1.9.2" + "@safe-global/safe-core-sdk-utils" "^1.7.4" ethers "5.7.2" -"@scure/base@~1.1.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" - integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA== +"@scure/base@~1.1.0", "@scure/base@~1.1.6": + version "1.1.9" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.9.tgz#e5e142fbbfe251091f9c5f1dd4c834ac04c3dbd1" + integrity sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg== -"@scure/bip32@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.1.0.tgz#dea45875e7fbc720c2b4560325f1cf5d2246d95b" - integrity sha512-ftTW3kKX54YXLCxH6BB7oEEoJfoE2pIgw7MINKAs5PsS6nqKPuKk1haTF/EuHmYqG330t5GSrdmtRuHaY1a62Q== +"@scure/base@~1.2.5": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.2.6.tgz#ca917184b8231394dd8847509c67a0be522e59f6" + integrity sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg== + +"@scure/bip32@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.1.5.tgz#d2ccae16dcc2e75bc1d75f5ef3c66a338d1ba300" + integrity sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw== dependencies: - "@noble/hashes" "~1.1.1" - "@noble/secp256k1" "~1.6.0" + "@noble/hashes" "~1.2.0" + "@noble/secp256k1" "~1.7.0" "@scure/base" "~1.1.0" -"@scure/bip39@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.1.0.tgz#92f11d095bae025f166bef3defcc5bf4945d419a" - integrity sha512-pwrPOS16VeTKg98dYXQyIjJEcWfz7/1YJIwxUEPFfQPtc86Ym/1sVgQ2RLoD43AazMk2l/unK4ITySSpW2+82w== +"@scure/bip32@1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.4.0.tgz#4e1f1e196abedcef395b33b9674a042524e20d67" + integrity sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg== + dependencies: + "@noble/curves" "~1.4.0" + "@noble/hashes" "~1.4.0" + "@scure/base" "~1.1.6" + +"@scure/bip39@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.1.1.tgz#b54557b2e86214319405db819c4b6a370cf340c5" + integrity sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg== dependencies: - "@noble/hashes" "~1.1.1" + "@noble/hashes" "~1.2.0" "@scure/base" "~1.1.0" +"@scure/bip39@1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.3.0.tgz#0f258c16823ddd00739461ac31398b4e7d6a18c3" + integrity sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ== + dependencies: + "@noble/hashes" "~1.4.0" + "@scure/base" "~1.1.6" + "@sentry/core@5.30.0": version "5.30.0" resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.30.0.tgz#6b203664f69e75106ee8b5a2fe1d717379b331f3" @@ -980,20 +1907,533 @@ resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.30.0.tgz#9a5bd7ccff85ccfe7856d493bffa64cabc41e980" integrity sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww== dependencies: - "@sentry/types" "5.30.0" - tslib "^1.9.3" + "@sentry/types" "5.30.0" + tslib "^1.9.3" + +"@smithy/abort-controller@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@smithy/abort-controller/-/abort-controller-4.0.4.tgz#ab991d521fc78b5c7f24907fcd6803c0f2da51d9" + integrity sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA== + dependencies: + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@smithy/config-resolver@^4.1.4": + version "4.1.4" + resolved "https://registry.yarnpkg.com/@smithy/config-resolver/-/config-resolver-4.1.4.tgz#05d8eab8bb8eb73bec90c222fc19ac5608b1384e" + integrity sha512-prmU+rDddxHOH0oNcwemL+SwnzcG65sBF2yXRO7aeXIn/xTlq2pX7JLVbkBnVLowHLg4/OL4+jBmv9hVrVGS+w== + dependencies: + "@smithy/node-config-provider" "^4.1.3" + "@smithy/types" "^4.3.1" + "@smithy/util-config-provider" "^4.0.0" + "@smithy/util-middleware" "^4.0.4" + tslib "^2.6.2" + +"@smithy/core@^3.6.0": + version "3.6.0" + resolved "https://registry.yarnpkg.com/@smithy/core/-/core-3.6.0.tgz#be02f2a4a56ba83d37298454a0bddc89cbad510b" + integrity sha512-Pgvfb+TQ4wUNLyHzvgCP4aYZMh16y7GcfF59oirRHcgGgkH1e/s9C0nv/v3WP+Quymyr5je71HeFQCwh+44XLg== + dependencies: + "@smithy/middleware-serde" "^4.0.8" + "@smithy/protocol-http" "^5.1.2" + "@smithy/types" "^4.3.1" + "@smithy/util-base64" "^4.0.0" + "@smithy/util-body-length-browser" "^4.0.0" + "@smithy/util-middleware" "^4.0.4" + "@smithy/util-stream" "^4.2.2" + "@smithy/util-utf8" "^4.0.0" + tslib "^2.6.2" + +"@smithy/credential-provider-imds@^4.0.6": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.6.tgz#4cfd79a619cdbc9a75fcdc51a1193685f6a8944e" + integrity sha512-hKMWcANhUiNbCJouYkZ9V3+/Qf9pteR1dnwgdyzR09R4ODEYx8BbUysHwRSyex4rZ9zapddZhLFTnT4ZijR4pw== + dependencies: + "@smithy/node-config-provider" "^4.1.3" + "@smithy/property-provider" "^4.0.4" + "@smithy/types" "^4.3.1" + "@smithy/url-parser" "^4.0.4" + tslib "^2.6.2" + +"@smithy/eventstream-codec@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-codec/-/eventstream-codec-4.0.4.tgz#35abc26d6829cc61a0d14950857ccc5320bf92d2" + integrity sha512-7XoWfZqWb/QoR/rAU4VSi0mWnO2vu9/ltS6JZ5ZSZv0eovLVfDfu0/AX4ub33RsJTOth3TiFWSHS5YdztvFnig== + dependencies: + "@aws-crypto/crc32" "5.2.0" + "@smithy/types" "^4.3.1" + "@smithy/util-hex-encoding" "^4.0.0" + tslib "^2.6.2" + +"@smithy/eventstream-serde-browser@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.0.4.tgz#0c57cf0b66862106100a796751003733ce3f5273" + integrity sha512-3fb/9SYaYqbpy/z/H3yIi0bYKyAa89y6xPmIqwr2vQiUT2St+avRt8UKwsWt9fEdEasc5d/V+QjrviRaX1JRFA== + dependencies: + "@smithy/eventstream-serde-universal" "^4.0.4" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@smithy/eventstream-serde-config-resolver@^4.1.2": + version "4.1.2" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.1.2.tgz#4d41c1ecad1a9b1c694f32865a2f0d4b5bc0162d" + integrity sha512-JGtambizrWP50xHgbzZI04IWU7LdI0nh/wGbqH3sJesYToMi2j/DcoElqyOcqEIG/D4tNyxgRuaqBXWE3zOFhQ== + dependencies: + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@smithy/eventstream-serde-node@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.0.4.tgz#0fbd0ac288f02bf485eb307a14254ea8d8767746" + integrity sha512-RD6UwNZ5zISpOWPuhVgRz60GkSIp0dy1fuZmj4RYmqLVRtejFqQ16WmfYDdoSoAjlp1LX+FnZo+/hkdmyyGZ1w== + dependencies: + "@smithy/eventstream-serde-universal" "^4.0.4" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@smithy/eventstream-serde-universal@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.0.4.tgz#48b2b416dc0f576917c36373efaa4012f7310ab0" + integrity sha512-UeJpOmLGhq1SLox79QWw/0n2PFX+oPRE1ZyRMxPIaFEfCqWaqpB7BU9C8kpPOGEhLF7AwEqfFbtwNxGy4ReENA== + dependencies: + "@smithy/eventstream-codec" "^4.0.4" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@smithy/fetch-http-handler@^5.0.4": + version "5.0.4" + resolved "https://registry.yarnpkg.com/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.4.tgz#c68601b4676787e049b5d464d5f4b825dbb44013" + integrity sha512-AMtBR5pHppYMVD7z7G+OlHHAcgAN7v0kVKEpHuTO4Gb199Gowh0taYi9oDStFeUhetkeP55JLSVlTW1n9rFtUw== + dependencies: + "@smithy/protocol-http" "^5.1.2" + "@smithy/querystring-builder" "^4.0.4" + "@smithy/types" "^4.3.1" + "@smithy/util-base64" "^4.0.0" + tslib "^2.6.2" + +"@smithy/hash-node@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@smithy/hash-node/-/hash-node-4.0.4.tgz#f867cfe6b702ed8893aacd3e097f8ca8ecba579e" + integrity sha512-qnbTPUhCVnCgBp4z4BUJUhOEkVwxiEi1cyFM+Zj6o+aY8OFGxUQleKWq8ltgp3dujuhXojIvJWdoqpm6dVO3lQ== + dependencies: + "@smithy/types" "^4.3.1" + "@smithy/util-buffer-from" "^4.0.0" + "@smithy/util-utf8" "^4.0.0" + tslib "^2.6.2" + +"@smithy/invalid-dependency@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@smithy/invalid-dependency/-/invalid-dependency-4.0.4.tgz#8c2c539b2f22e857b4652bd2427a3d7a8befd610" + integrity sha512-bNYMi7WKTJHu0gn26wg8OscncTt1t2b8KcsZxvOv56XA6cyXtOAAAaNP7+m45xfppXfOatXF3Sb1MNsLUgVLTw== + dependencies: + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@smithy/is-array-buffer@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz#f84f0d9f9a36601a9ca9381688bd1b726fd39111" + integrity sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA== + dependencies: + tslib "^2.6.2" + +"@smithy/is-array-buffer@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz#55a939029321fec462bcc574890075cd63e94206" + integrity sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw== + dependencies: + tslib "^2.6.2" + +"@smithy/middleware-content-length@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@smithy/middleware-content-length/-/middleware-content-length-4.0.4.tgz#fad1f125779daf8d5f261dae6dbebba0f60c234b" + integrity sha512-F7gDyfI2BB1Kc+4M6rpuOLne5LOcEknH1n6UQB69qv+HucXBR1rkzXBnQTB2q46sFy1PM/zuSJOB532yc8bg3w== + dependencies: + "@smithy/protocol-http" "^5.1.2" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@smithy/middleware-endpoint@^4.1.13": + version "4.1.13" + resolved "https://registry.yarnpkg.com/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.13.tgz#7d5b5f8f61600270bd8c59aabf311c99b9127aba" + integrity sha512-xg3EHV/Q5ZdAO5b0UiIMj3RIOCobuS40pBBODguUDVdko6YK6QIzCVRrHTogVuEKglBWqWenRnZ71iZnLL3ZAQ== + dependencies: + "@smithy/core" "^3.6.0" + "@smithy/middleware-serde" "^4.0.8" + "@smithy/node-config-provider" "^4.1.3" + "@smithy/shared-ini-file-loader" "^4.0.4" + "@smithy/types" "^4.3.1" + "@smithy/url-parser" "^4.0.4" + "@smithy/util-middleware" "^4.0.4" + tslib "^2.6.2" + +"@smithy/middleware-retry@^4.1.14": + version "4.1.14" + resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-4.1.14.tgz#53ce619463a1ce4b95025aaafdf51369ef893196" + integrity sha512-eoXaLlDGpKvdmvt+YBfRXE7HmIEtFF+DJCbTPwuLunP0YUnrydl+C4tS+vEM0+nyxXrX3PSUFqC+lP1+EHB1Tw== + dependencies: + "@smithy/node-config-provider" "^4.1.3" + "@smithy/protocol-http" "^5.1.2" + "@smithy/service-error-classification" "^4.0.6" + "@smithy/smithy-client" "^4.4.5" + "@smithy/types" "^4.3.1" + "@smithy/util-middleware" "^4.0.4" + "@smithy/util-retry" "^4.0.6" + tslib "^2.6.2" + uuid "^9.0.1" + +"@smithy/middleware-serde@^4.0.8": + version "4.0.8" + resolved "https://registry.yarnpkg.com/@smithy/middleware-serde/-/middleware-serde-4.0.8.tgz#3704c8cc46acd0a7f910a78ee1d2f23ce928701f" + integrity sha512-iSSl7HJoJaGyMIoNn2B7czghOVwJ9nD7TMvLhMWeSB5vt0TnEYyRRqPJu/TqW76WScaNvYYB8nRoiBHR9S1Ddw== + dependencies: + "@smithy/protocol-http" "^5.1.2" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@smithy/middleware-stack@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@smithy/middleware-stack/-/middleware-stack-4.0.4.tgz#58e0c6a0d7678c6ad4d6af8dd9a00f749ffac7c5" + integrity sha512-kagK5ggDrBUCCzI93ft6DjteNSfY8Ulr83UtySog/h09lTIOAJ/xUSObutanlPT0nhoHAkpmW9V5K8oPyLh+QA== + dependencies: + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@smithy/node-config-provider@^4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@smithy/node-config-provider/-/node-config-provider-4.1.3.tgz#6626fe26c6fe7b0df34f71cb72764ccba414a815" + integrity sha512-HGHQr2s59qaU1lrVH6MbLlmOBxadtzTsoO4c+bF5asdgVik3I8o7JIOzoeqWc5MjVa+vD36/LWE0iXKpNqooRw== + dependencies: + "@smithy/property-provider" "^4.0.4" + "@smithy/shared-ini-file-loader" "^4.0.4" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@smithy/node-http-handler@^4.0.6": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@smithy/node-http-handler/-/node-http-handler-4.0.6.tgz#a022da499ba3af4b6b4c815104fde973c0eccc40" + integrity sha512-NqbmSz7AW2rvw4kXhKGrYTiJVDHnMsFnX4i+/FzcZAfbOBauPYs2ekuECkSbtqaxETLLTu9Rl/ex6+I2BKErPA== + dependencies: + "@smithy/abort-controller" "^4.0.4" + "@smithy/protocol-http" "^5.1.2" + "@smithy/querystring-builder" "^4.0.4" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@smithy/property-provider@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@smithy/property-provider/-/property-provider-4.0.4.tgz#303a8fd99665fff61eeb6ec3922eee53838962c5" + integrity sha512-qHJ2sSgu4FqF4U/5UUp4DhXNmdTrgmoAai6oQiM+c5RZ/sbDwJ12qxB1M6FnP+Tn/ggkPZf9ccn4jqKSINaquw== + dependencies: + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@smithy/protocol-http@^5.1.2": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@smithy/protocol-http/-/protocol-http-5.1.2.tgz#8094860c2407f250b80c95899e0385112d6eb98b" + integrity sha512-rOG5cNLBXovxIrICSBm95dLqzfvxjEmuZx4KK3hWwPFHGdW3lxY0fZNXfv2zebfRO7sJZ5pKJYHScsqopeIWtQ== + dependencies: + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@smithy/querystring-builder@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@smithy/querystring-builder/-/querystring-builder-4.0.4.tgz#f7546efd59d457b3d2525a330c6137e5f907864c" + integrity sha512-SwREZcDnEYoh9tLNgMbpop+UTGq44Hl9tdj3rf+yeLcfH7+J8OXEBaMc2kDxtyRHu8BhSg9ADEx0gFHvpJgU8w== + dependencies: + "@smithy/types" "^4.3.1" + "@smithy/util-uri-escape" "^4.0.0" + tslib "^2.6.2" + +"@smithy/querystring-parser@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@smithy/querystring-parser/-/querystring-parser-4.0.4.tgz#307ab95ee5f1a142ab46c2eddebeae68cb2f703d" + integrity sha512-6yZf53i/qB8gRHH/l2ZwUG5xgkPgQF15/KxH0DdXMDHjesA9MeZje/853ifkSY0x4m5S+dfDZ+c4x439PF0M2w== + dependencies: + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@smithy/service-error-classification@^4.0.6": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@smithy/service-error-classification/-/service-error-classification-4.0.6.tgz#5d4d3017f5b62258fbfc1067e14198e125a8286c" + integrity sha512-RRoTDL//7xi4tn5FrN2NzH17jbgmnKidUqd4KvquT0954/i6CXXkh1884jBiunq24g9cGtPBEXlU40W6EpNOOg== + dependencies: + "@smithy/types" "^4.3.1" + +"@smithy/shared-ini-file-loader@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.4.tgz#33c63468b95cfd5e7d642c8131d7acc034025e00" + integrity sha512-63X0260LoFBjrHifPDs+nM9tV0VMkOTl4JRMYNuKh/f5PauSjowTfvF3LogfkWdcPoxsA9UjqEOgjeYIbhb7Nw== + dependencies: + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@smithy/signature-v4@^5.1.2": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@smithy/signature-v4/-/signature-v4-5.1.2.tgz#5afd9d428bd26bb660bee8075b6e89fe93600c22" + integrity sha512-d3+U/VpX7a60seHziWnVZOHuEgJlclufjkS6zhXvxcJgkJq4UWdH5eOBLzHRMx6gXjsdT9h6lfpmLzbrdupHgQ== + dependencies: + "@smithy/is-array-buffer" "^4.0.0" + "@smithy/protocol-http" "^5.1.2" + "@smithy/types" "^4.3.1" + "@smithy/util-hex-encoding" "^4.0.0" + "@smithy/util-middleware" "^4.0.4" + "@smithy/util-uri-escape" "^4.0.0" + "@smithy/util-utf8" "^4.0.0" + tslib "^2.6.2" + +"@smithy/smithy-client@^4.4.5": + version "4.4.5" + resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-4.4.5.tgz#1c736618f3c4910880cc6862a5826348c1b70d5d" + integrity sha512-+lynZjGuUFJaMdDYSTMnP/uPBBXXukVfrJlP+1U/Dp5SFTEI++w6NMga8DjOENxecOF71V9Z2DllaVDYRnGlkg== + dependencies: + "@smithy/core" "^3.6.0" + "@smithy/middleware-endpoint" "^4.1.13" + "@smithy/middleware-stack" "^4.0.4" + "@smithy/protocol-http" "^5.1.2" + "@smithy/types" "^4.3.1" + "@smithy/util-stream" "^4.2.2" + tslib "^2.6.2" + +"@smithy/types@^4.3.1": + version "4.3.1" + resolved "https://registry.yarnpkg.com/@smithy/types/-/types-4.3.1.tgz#c11276ea16235d798f47a68aef9f44d3dbb70dd4" + integrity sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA== + dependencies: + tslib "^2.6.2" + +"@smithy/url-parser@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@smithy/url-parser/-/url-parser-4.0.4.tgz#049143f4c156356e177bd69242675db26fe4f4db" + integrity sha512-eMkc144MuN7B0TDA4U2fKs+BqczVbk3W+qIvcoCY6D1JY3hnAdCuhCZODC+GAeaxj0p6Jroz4+XMUn3PCxQQeQ== + dependencies: + "@smithy/querystring-parser" "^4.0.4" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@smithy/util-base64@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-base64/-/util-base64-4.0.0.tgz#8345f1b837e5f636e5f8470c4d1706ae0c6d0358" + integrity sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg== + dependencies: + "@smithy/util-buffer-from" "^4.0.0" + "@smithy/util-utf8" "^4.0.0" + tslib "^2.6.2" + +"@smithy/util-body-length-browser@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz#965d19109a4b1e5fe7a43f813522cce718036ded" + integrity sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA== + dependencies: + tslib "^2.6.2" + +"@smithy/util-body-length-node@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-body-length-node/-/util-body-length-node-4.0.0.tgz#3db245f6844a9b1e218e30c93305bfe2ffa473b3" + integrity sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg== + dependencies: + tslib "^2.6.2" + +"@smithy/util-buffer-from@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz#6fc88585165ec73f8681d426d96de5d402021e4b" + integrity sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA== + dependencies: + "@smithy/is-array-buffer" "^2.2.0" + tslib "^2.6.2" + +"@smithy/util-buffer-from@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz#b23b7deb4f3923e84ef50c8b2c5863d0dbf6c0b9" + integrity sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug== + dependencies: + "@smithy/is-array-buffer" "^4.0.0" + tslib "^2.6.2" + +"@smithy/util-config-provider@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-config-provider/-/util-config-provider-4.0.0.tgz#e0c7c8124c7fba0b696f78f0bd0ccb060997d45e" + integrity sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w== + dependencies: + tslib "^2.6.2" + +"@smithy/util-defaults-mode-browser@^4.0.21": + version "4.0.21" + resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.21.tgz#47895e42d64060d2a7f803a443fd160d0a329d83" + integrity sha512-wM0jhTytgXu3wzJoIqpbBAG5U6BwiubZ6QKzSbP7/VbmF1v96xlAbX2Am/mz0Zep0NLvLh84JT0tuZnk3wmYQA== + dependencies: + "@smithy/property-provider" "^4.0.4" + "@smithy/smithy-client" "^4.4.5" + "@smithy/types" "^4.3.1" + bowser "^2.11.0" + tslib "^2.6.2" + +"@smithy/util-defaults-mode-node@^4.0.21": + version "4.0.21" + resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.21.tgz#4682143fbfb0a4c6e08a6151f13af97018e6950e" + integrity sha512-/F34zkoU0GzpUgLJydHY8Rxu9lBn8xQC/s/0M0U9lLBkYbA1htaAFjWYJzpzsbXPuri5D1H8gjp2jBum05qBrA== + dependencies: + "@smithy/config-resolver" "^4.1.4" + "@smithy/credential-provider-imds" "^4.0.6" + "@smithy/node-config-provider" "^4.1.3" + "@smithy/property-provider" "^4.0.4" + "@smithy/smithy-client" "^4.4.5" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@smithy/util-endpoints@^3.0.6": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@smithy/util-endpoints/-/util-endpoints-3.0.6.tgz#a24b0801a1b94c0de26ad83da206b9add68117f2" + integrity sha512-YARl3tFL3WgPuLzljRUnrS2ngLiUtkwhQtj8PAL13XZSyUiNLQxwG3fBBq3QXFqGFUXepIN73pINp3y8c2nBmA== + dependencies: + "@smithy/node-config-provider" "^4.1.3" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@smithy/util-hex-encoding@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz#dd449a6452cffb37c5b1807ec2525bb4be551e8d" + integrity sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw== + dependencies: + tslib "^2.6.2" + +"@smithy/util-middleware@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@smithy/util-middleware/-/util-middleware-4.0.4.tgz#8f639de049082c687841ea5e69c6c36e12e31a3c" + integrity sha512-9MLKmkBmf4PRb0ONJikCbCwORACcil6gUWojwARCClT7RmLzF04hUR4WdRprIXal7XVyrddadYNfp2eF3nrvtQ== + dependencies: + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@smithy/util-retry@^4.0.6": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@smithy/util-retry/-/util-retry-4.0.6.tgz#f931fdd1f01786b21a82711e185c58410e8e41c7" + integrity sha512-+YekoF2CaSMv6zKrA6iI/N9yva3Gzn4L6n35Luydweu5MMPYpiGZlWqehPHDHyNbnyaYlz/WJyYAZnC+loBDZg== + dependencies: + "@smithy/service-error-classification" "^4.0.6" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@smithy/util-stream@^4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@smithy/util-stream/-/util-stream-4.2.2.tgz#beeb1edf690db9b7d7983f46ca4fb66e22253608" + integrity sha512-aI+GLi7MJoVxg24/3J1ipwLoYzgkB4kUfogZfnslcYlynj3xsQ0e7vk4TnTro9hhsS5PvX1mwmkRqqHQjwcU7w== + dependencies: + "@smithy/fetch-http-handler" "^5.0.4" + "@smithy/node-http-handler" "^4.0.6" + "@smithy/types" "^4.3.1" + "@smithy/util-base64" "^4.0.0" + "@smithy/util-buffer-from" "^4.0.0" + "@smithy/util-hex-encoding" "^4.0.0" + "@smithy/util-utf8" "^4.0.0" + tslib "^2.6.2" + +"@smithy/util-uri-escape@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz#a96c160c76f3552458a44d8081fade519d214737" + integrity sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg== + dependencies: + tslib "^2.6.2" + +"@smithy/util-utf8@^2.0.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@smithy/util-utf8/-/util-utf8-2.3.0.tgz#dd96d7640363259924a214313c3cf16e7dd329c5" + integrity sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A== + dependencies: + "@smithy/util-buffer-from" "^2.2.0" + tslib "^2.6.2" + +"@smithy/util-utf8@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-utf8/-/util-utf8-4.0.0.tgz#09ca2d9965e5849e72e347c130f2a29d5c0c863c" + integrity sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow== + dependencies: + "@smithy/util-buffer-from" "^4.0.0" + tslib "^2.6.2" + +"@smithy/util-waiter@^4.0.6": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@smithy/util-waiter/-/util-waiter-4.0.6.tgz#38044da5053f0d9118df05f55cd8fbec14ecf9da" + integrity sha512-slcr1wdRbX7NFphXZOxtxRNA7hXAAtJAXJDE/wdoMAos27SIquVCKiSqfB6/28YzQ8FCsB5NKkhdM5gMADbqxg== + dependencies: + "@smithy/abort-controller" "^4.0.4" + "@smithy/types" "^4.3.1" + tslib "^2.6.2" + +"@solidity-parser/parser@^0.14.0": + version "0.14.5" + resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.14.5.tgz#87bc3cc7b068e08195c219c91cd8ddff5ef1a804" + integrity sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg== + dependencies: + antlr4ts "^0.5.0-alpha.4" -"@solidity-parser/parser@^0.14.0", "@solidity-parser/parser@^0.14.1": - version "0.14.3" - resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.14.3.tgz#0d627427b35a40d8521aaa933cc3df7d07bfa36f" - integrity sha512-29g2SZ29HtsqA58pLCtopI1P/cPy5/UAzlcAXO6T/CNJimG6yA8kx4NaseMyJULiC+TEs02Y9/yeHzClqoA0hw== +"@solidity-parser/parser@^0.16.0": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.16.2.tgz#42cb1e3d88b3e8029b0c9befff00b634cd92d2fa" + integrity sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg== dependencies: antlr4ts "^0.5.0-alpha.4" +"@solidity-parser/parser@^0.20.1": + version "0.20.1" + resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.20.1.tgz#88efee3e0946a4856ed10355017692db9c259ff4" + integrity sha512-58I2sRpzaQUN+jJmWbHfbWf9AKfzqCI8JAdFB0vbyY+u8tBRcuTt9LxzasvR0LGQpcRv97eyV7l61FQ3Ib7zVw== + +"@tenderly/api-client@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@tenderly/api-client/-/api-client-1.1.0.tgz#fa06adf17ecc1ef83c5fb8536b71b542e7023228" + integrity sha512-kyye7TQ+RbDbJ7bSUjNf/O9fTtRYNUDIEUZQSrmNonowMw5/EpNi664eWaOoC00NEzxgttVrtme/GHvIOu7rNg== + dependencies: + axios "^0.27.2" + cli-table3 "^0.6.2" + commander "^9.4.0" + dotenv "^16.4.5" + js-yaml "^4.1.0" + open "^8.4.0" + prompts "^2.4.2" + tslog "^4.4.0" + +"@tenderly/hardhat-integration@^1.1.0": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@tenderly/hardhat-integration/-/hardhat-integration-1.1.1.tgz#6921c3f524d344efdd9b5f18c0500e9ac7ddcd27" + integrity sha512-VHa380DrKv+KA1N4vbJGLDoghbVqMZ4wEozbxRfCzlkSs5V1keNgudRSUFK6lgfKhkoAWRO+dA8MZYnJOvUOkA== + dependencies: + "@tenderly/api-client" "^1.1.0" + axios "^1.6.7" + dotenv "^16.4.5" + fs-extra "^10.1.0" + hardhat-deploy "^0.11.43" + npm-registry-fetch "^17.1.0" + semver "^7.6.3" + ts-node "^10.9.1" + tslog "^4.3.1" + typescript "^5.5.4" + +"@tenderly/hardhat-tenderly@^2.5.2": + version "2.5.2" + resolved "https://registry.yarnpkg.com/@tenderly/hardhat-tenderly/-/hardhat-tenderly-2.5.2.tgz#e0c632961b7f7a130e8708abc37f429c11601695" + integrity sha512-JCG1UkFBRZE2fL8g4jfbKUsju7gK3Dg6CxksJO9Db9ckM1EkL4wCY9G5KTLwh/UL0cT04J8ZK1RmaZ6hG8wfKA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@nomicfoundation/hardhat-ethers" "^3.0.0" + "@nomicfoundation/hardhat-ignition" "^0.15.5" + "@nomicfoundation/hardhat-verify" "^2.0.8" + "@openzeppelin/hardhat-upgrades" "^3.3.0" + "@openzeppelin/upgrades-core" "^1.32.2" + "@tenderly/hardhat-integration" "^1.1.0" + dotenv "^16.4.5" + ethers "^6.8.1" + +"@tenderly/sdk@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@tenderly/sdk/-/sdk-0.3.1.tgz#bf63991cfed04941608b112eaa9ea3839e1866ea" + integrity sha512-5WJjOqew7sYJNjVnNrqYbecqahBF+dEctk75G2ZO2JuDMUaLbbiloEYMelaPAMkBifNbN1w1qppG2KWBnt3Pkg== + dependencies: + axios "^1.3.4" + "@tsconfig/node10@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" - integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== "@tsconfig/node12@^1.0.7": version "1.0.11" @@ -1006,9 +2446,9 @@ integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== "@tsconfig/node16@^1.0.2": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" - integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== "@typechain/ethers-v5@^8.0.2": version "8.0.5" @@ -1025,36 +2465,31 @@ dependencies: fs-extra "^9.1.0" -"@types/async-eventemitter@^0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@types/async-eventemitter/-/async-eventemitter-0.2.1.tgz#f8e6280e87e8c60b2b938624b0a3530fb3e24712" - integrity sha512-M2P4Ng26QbAeITiH7w1d7OxtldgfAe0wobpyJzVK/XOb0cUGKU2R4pfAhqcJBXAe2ife5ZOhSv4wk7p+ffURtg== - -"@types/bn.js@^4.11.3": - version "4.11.6" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" - integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== - dependencies: - "@types/node" "*" - "@types/bn.js@^5.1.0", "@types/bn.js@^5.1.1": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.1.tgz#b51e1b55920a4ca26e9285ff79936bbdec910682" - integrity sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g== + version "5.2.0" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.2.0.tgz#4349b9710e98f9ab3cdc50f1c5e4dcbd8ef29c80" + integrity sha512-DLbJ1BPqxvQhIGbeu8VbUC1DiAiahHtAYvA0ZEAa4P31F7IaArc8z3C3BRQdWX4mtLQuABG4yzp76ZrS02Ui1Q== dependencies: "@types/node" "*" "@types/chai-as-promised@^7.1.3", "@types/chai-as-promised@^7.1.4": - version "7.1.5" - resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-7.1.5.tgz#6e016811f6c7a64f2eed823191c3a6955094e255" - integrity sha512-jStwss93SITGBwt/niYrkf2C+/1KTeZCZl1LaeezTlqppAKeoQC7jxyqYuP72sxBGKCIbw7oHgbYssIRzT5FCQ== + version "7.1.8" + resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz#f2b3d82d53c59626b5d6bbc087667ccb4b677fe9" + integrity sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw== dependencies: "@types/chai" "*" -"@types/chai@*", "@types/chai@^4.2.22": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.3.tgz#3c90752792660c4b562ad73b3fbd68bf3bc7ae07" - integrity sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g== +"@types/chai@*": + version "5.2.2" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-5.2.2.tgz#6f14cea18180ffc4416bc0fd12be05fdd73bdd6b" + integrity sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg== + dependencies: + "@types/deep-eql" "*" + +"@types/chai@^4.2.22": + version "4.3.20" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.20.tgz#cb291577ed342ca92600430841a00329ba05cecc" + integrity sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ== "@types/concat-stream@^1.6.0": version "1.6.1" @@ -1063,6 +2498,11 @@ dependencies: "@types/node" "*" +"@types/deep-eql@*": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/deep-eql/-/deep-eql-4.0.2.tgz#334311971d3a07121e7eb91b684a605e7eea9cbd" + integrity sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw== + "@types/form-data@0.0.33": version "0.0.33" resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-0.0.33.tgz#c9ac85b2a5fd18435b8c85d9ecb50e6d6c893ff8" @@ -1070,25 +2510,49 @@ dependencies: "@types/node" "*" +"@types/glob@^7.1.1": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + "@types/json-schema@^7.0.9": - version "7.0.11" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" - integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== "@types/lru-cache@^5.1.0": version "5.1.1" resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-5.1.1.tgz#c48c2e27b65d2a153b19bfc1a317e30872e01eef" integrity sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw== +"@types/minimatch@*": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-6.0.0.tgz#4d207b1cc941367bdcd195a3a781a7e4fc3b1e03" + integrity sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA== + dependencies: + minimatch "*" + "@types/mocha@^9.0.0": version "9.1.1" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4" integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw== "@types/node@*": - version "18.8.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.8.5.tgz#6a31f820c1077c3f8ce44f9e203e68a176e8f59e" - integrity sha512-Bq7G3AErwe5A/Zki5fdD3O6+0zDChhg671NfPjtIcbtzDNZTv4NPKMRFr7gtYPG7y+B8uTiNK4Ngd9T0FTar6Q== + version "24.0.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-24.0.6.tgz#d483f1407d022ef2a12118f7c02074ca218346c3" + integrity sha512-ZOyn+gOs749xU7ovp+Ibj0g1o3dFRqsfPnT22C2t5JzcRvgsEDpGawPbCISGKLudJk9Y0wiu9sYd6kUh0pc9TA== + dependencies: + undici-types "~7.8.0" + +"@types/node@22.7.5": + version "22.7.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" + integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ== + dependencies: + undici-types "~6.19.2" "@types/node@^10.0.3": version "10.17.60" @@ -1101,9 +2565,9 @@ integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== "@types/node@^16.11.7": - version "16.11.65" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.65.tgz#59500b86af757d6fcabd3dec32fecb6e357d7a45" - integrity sha512-Vfz7wGMOr4jbQGiQHVJm8VjeQwM9Ya7mHe9LtQ264/Epf5n1KiZShOFqk++nBzw6a/ubgYdB9Od7P+MH/LjoWw== + version "16.18.126" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.126.tgz#27875faa2926c0f475b39a8bb1e546c0176f8d4b" + integrity sha512-OTcgaiwfGFBKacvfwuHzzn1KLxH/er8mluiy8/uM3sGXHaRe73RrSIj01jow9t4kJEW633Ov+cOexXeiApTyAw== "@types/node@^8.0.0": version "8.10.66" @@ -1111,108 +2575,116 @@ integrity sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw== "@types/pbkdf2@^3.0.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@types/pbkdf2/-/pbkdf2-3.1.0.tgz#039a0e9b67da0cdc4ee5dab865caa6b267bb66b1" - integrity sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ== + version "3.1.2" + resolved "https://registry.yarnpkg.com/@types/pbkdf2/-/pbkdf2-3.1.2.tgz#2dc43808e9985a2c69ff02e2d2027bd4fe33e8dc" + integrity sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew== dependencies: "@types/node" "*" "@types/prettier@^2.1.1": - version "2.7.1" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.1.tgz#dfd20e2dc35f027cdd6c1908e80a5ddc7499670e" - integrity sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow== + version "2.7.3" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f" + integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== -"@types/qs@^6.2.31": - version "6.9.7" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" - integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== +"@types/qs@^6.2.31", "@types/qs@^6.9.7": + version "6.14.0" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.14.0.tgz#d8b60cecf62f2db0fb68e5e006077b9178b85de5" + integrity sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ== "@types/secp256k1@^4.0.1": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.3.tgz#1b8e55d8e00f08ee7220b4d59a6abe89c37a901c" - integrity sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w== + version "4.0.6" + resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.6.tgz#d60ba2349a51c2cbc5e816dcd831a42029d376bf" + integrity sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ== dependencies: "@types/node" "*" +"@types/semver@^7.3.12": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.7.0.tgz#64c441bdae033b378b6eef7d0c3d77c329b9378e" + integrity sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA== + "@typescript-eslint/eslint-plugin@^5.18.0": - version "5.40.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.40.0.tgz#0159bb71410eec563968288a17bd4478cdb685bd" - integrity sha512-FIBZgS3DVJgqPwJzvZTuH4HNsZhHMa9SjxTKAZTlMsPw/UzpEjcf9f4dfgDJEHjK+HboUJo123Eshl6niwEm/Q== - dependencies: - "@typescript-eslint/scope-manager" "5.40.0" - "@typescript-eslint/type-utils" "5.40.0" - "@typescript-eslint/utils" "5.40.0" + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz#aeef0328d172b9e37d9bab6dbc13b87ed88977db" + integrity sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag== + dependencies: + "@eslint-community/regexpp" "^4.4.0" + "@typescript-eslint/scope-manager" "5.62.0" + "@typescript-eslint/type-utils" "5.62.0" + "@typescript-eslint/utils" "5.62.0" debug "^4.3.4" + graphemer "^1.4.0" ignore "^5.2.0" - regexpp "^3.2.0" + natural-compare-lite "^1.4.0" semver "^7.3.7" tsutils "^3.21.0" "@typescript-eslint/parser@^5.18.0": - version "5.40.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.40.0.tgz#432bddc1fe9154945660f67c1ba6d44de5014840" - integrity sha512-Ah5gqyX2ySkiuYeOIDg7ap51/b63QgWZA7w6AHtFrag7aH0lRQPbLzUjk0c9o5/KZ6JRkTTDKShL4AUrQa6/hw== + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.62.0.tgz#1b63d082d849a2fcae8a569248fbe2ee1b8a56c7" + integrity sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA== dependencies: - "@typescript-eslint/scope-manager" "5.40.0" - "@typescript-eslint/types" "5.40.0" - "@typescript-eslint/typescript-estree" "5.40.0" + "@typescript-eslint/scope-manager" "5.62.0" + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/typescript-estree" "5.62.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.40.0": - version "5.40.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.40.0.tgz#d6ea782c8e3a2371ba3ea31458dcbdc934668fc4" - integrity sha512-d3nPmjUeZtEWRvyReMI4I1MwPGC63E8pDoHy0BnrYjnJgilBD3hv7XOiETKLY/zTwI7kCnBDf2vWTRUVpYw0Uw== +"@typescript-eslint/scope-manager@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c" + integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w== dependencies: - "@typescript-eslint/types" "5.40.0" - "@typescript-eslint/visitor-keys" "5.40.0" + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/visitor-keys" "5.62.0" -"@typescript-eslint/type-utils@5.40.0": - version "5.40.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.40.0.tgz#4964099d0158355e72d67a370249d7fc03331126" - integrity sha512-nfuSdKEZY2TpnPz5covjJqav+g5qeBqwSHKBvz7Vm1SAfy93SwKk/JeSTymruDGItTwNijSsno5LhOHRS1pcfw== +"@typescript-eslint/type-utils@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz#286f0389c41681376cdad96b309cedd17d70346a" + integrity sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew== dependencies: - "@typescript-eslint/typescript-estree" "5.40.0" - "@typescript-eslint/utils" "5.40.0" + "@typescript-eslint/typescript-estree" "5.62.0" + "@typescript-eslint/utils" "5.62.0" debug "^4.3.4" tsutils "^3.21.0" -"@typescript-eslint/types@5.40.0": - version "5.40.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.40.0.tgz#8de07e118a10b8f63c99e174a3860f75608c822e" - integrity sha512-V1KdQRTXsYpf1Y1fXCeZ+uhjW48Niiw0VGt4V8yzuaDTU8Z1Xl7yQDyQNqyAFcVhpYXIVCEuxSIWTsLDpHgTbw== +"@typescript-eslint/types@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" + integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== -"@typescript-eslint/typescript-estree@5.40.0": - version "5.40.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.40.0.tgz#e305e6a5d65226efa5471ee0f12e0ffaab6d3075" - integrity sha512-b0GYlDj8TLTOqwX7EGbw2gL5EXS2CPEWhF9nGJiGmEcmlpNBjyHsTwbqpyIEPVpl6br4UcBOYlcI2FJVtJkYhg== +"@typescript-eslint/typescript-estree@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" + integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA== dependencies: - "@typescript-eslint/types" "5.40.0" - "@typescript-eslint/visitor-keys" "5.40.0" + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/visitor-keys" "5.62.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@5.40.0": - version "5.40.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.40.0.tgz#647f56a875fd09d33c6abd70913c3dd50759b772" - integrity sha512-MO0y3T5BQ5+tkkuYZJBjePewsY+cQnfkYeRqS6tPh28niiIwPnQ1t59CSRcs1ZwJJNOdWw7rv9pF8aP58IMihA== +"@typescript-eslint/utils@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" + integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ== dependencies: + "@eslint-community/eslint-utils" "^4.2.0" "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.40.0" - "@typescript-eslint/types" "5.40.0" - "@typescript-eslint/typescript-estree" "5.40.0" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.62.0" + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/typescript-estree" "5.62.0" eslint-scope "^5.1.1" - eslint-utils "^3.0.0" semver "^7.3.7" -"@typescript-eslint/visitor-keys@5.40.0": - version "5.40.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.40.0.tgz#dd2d38097f68e0d2e1e06cb9f73c0173aca54b68" - integrity sha512-ijJ+6yig+x9XplEpG2K6FUdJeQGGj/15U3S56W9IqXKJqleuD7zJ2AX/miLezwxpd7ZxDAqO87zWufKg+RPZyQ== +"@typescript-eslint/visitor-keys@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e" + integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw== dependencies: - "@typescript-eslint/types" "5.40.0" + "@typescript-eslint/types" "5.62.0" eslint-visitor-keys "^3.3.0" "@ungap/promise-all-settled@1.1.2": @@ -1220,6 +2692,11 @@ resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== +"@ungap/structured-clone@^1.2.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" + integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -1230,50 +2707,27 @@ abbrev@1.0.x: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" integrity sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q== -abort-controller@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" - integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== - dependencies: - event-target-shim "^5.0.0" +abortcontroller-polyfill@^1.7.5: + version "1.7.8" + resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.8.tgz#fe8d4370403f02e2aa37e3d2b0b178bae9d83f49" + integrity sha512-9f1iZ2uWh92VcrU9Y8x+LdM4DLj75VE0MJB8zuF1iUnroEptStw+DQ8EQPMUdfe5k+PkB1uUfDQfWbhstH8LrQ== -abortcontroller-polyfill@^1.7.3: - version "1.7.5" - resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz#6738495f4e901fbb57b6c0611d0c75f76c485bed" - integrity sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ== - -abstract-level@^1.0.0, abstract-level@^1.0.2, abstract-level@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/abstract-level/-/abstract-level-1.0.3.tgz#78a67d3d84da55ee15201486ab44c09560070741" - integrity sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA== - dependencies: - buffer "^6.0.3" - catering "^2.1.0" - is-buffer "^2.0.5" - level-supports "^4.0.0" - level-transcoder "^1.0.1" - module-error "^1.0.1" - queue-microtask "^1.2.3" - -acorn-jsx@^5.0.0, acorn-jsx@^5.3.2: +acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== acorn-walk@^8.1.1: - version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== - -acorn@^6.0.7: - version "6.4.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" - integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== + version "8.3.4" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" + integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== + dependencies: + acorn "^8.11.0" -acorn@^8.4.1, acorn@^8.8.0: - version "8.8.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" - integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== +acorn@^8.11.0, acorn@^8.4.1, acorn@^8.9.0: + version "8.15.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" + integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== adm-zip@^0.4.16: version "0.4.16" @@ -1285,6 +2739,11 @@ aes-js@3.0.0: resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== +aes-js@4.0.0-beta.5: + version "4.0.0-beta.5" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== + agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -1292,6 +2751,11 @@ agent-base@6: dependencies: debug "4" +agent-base@^7.1.0, agent-base@^7.1.2: + version "7.1.3" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.3.tgz#29435eb821bc4194633a5b89e5bc4703bafc25a1" + integrity sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw== + aggregate-error@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" @@ -1300,7 +2764,7 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.6.1, ajv@^6.9.1: +ajv@^6.12.4, ajv@^6.12.6: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1311,14 +2775,25 @@ ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.6.1, ajv@^6.9.1: uri-js "^4.2.2" ajv@^8.0.1: - version "8.12.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" - integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== dependencies: - fast-deep-equal "^3.1.1" + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" json-schema-traverse "^1.0.0" require-from-string "^2.0.2" - uri-js "^4.2.2" + +amazon-cognito-identity-js@^6.3.6: + version "6.3.15" + resolved "https://registry.yarnpkg.com/amazon-cognito-identity-js/-/amazon-cognito-identity-js-6.3.15.tgz#bef9f1d7fddff6f0b4e2e2d9da04867d1559e20b" + integrity sha512-G2mzTlGYHKYh9oZDO0Gk94xVQ4iY9GYWBaYScbDYvz05ps6dqi0IvdNx1Lxi7oA3tjS5X+mUN7/svFJJdOB9YA== + dependencies: + "@aws-crypto/sha256-js" "1.2.2" + buffer "4.9.2" + fast-base64-decode "^1.0.0" + isomorphic-unfetch "^3.0.0" + js-cookie "^2.2.1" amdefine@>=0.0.4: version "1.0.1" @@ -1342,11 +2817,6 @@ ansi-colors@^4.1.1: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== -ansi-escapes@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== - ansi-escapes@^4.3.0: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" @@ -1359,17 +2829,17 @@ ansi-regex@^3.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== -ansi-regex@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" - integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== - ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-styles@^3.2.0, ansi-styles@^3.2.1: +ansi-regex@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== + +ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -1388,10 +2858,15 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== -antlr4@4.7.1: - version "4.7.1" - resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.7.1.tgz#69984014f096e9e775f53dd9744bf994d8959773" - integrity sha512-haHyTW7Y9joE5MVs37P2lNYfU2RWBLfcRDD8OWldcdZm5TiCE91B5Xl1oWSwiDUSd4rlExpt2pu1fksYQjRBYQ== +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + +antlr4@^4.11.0: + version "4.13.2" + resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.13.2.tgz#0d084ad0e32620482a9c3a0e2470c02e72e4006d" + integrity sha512-QiVbZhyy4xAZ17UPEuG3YTOt8ZaoeOR1CvEAqrEsDBsOqINslaB147i9xqljZqoyf5S+EUlGStaj+t22LT9MOg== antlr4ts@^0.5.0-alpha.4: version "0.5.0-alpha.4" @@ -1399,9 +2874,9 @@ antlr4ts@^0.5.0-alpha.4: integrity sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ== anymatch@~3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" @@ -1448,57 +2923,40 @@ asap@~2.0.6: resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== -asn1@~0.2.3: - version "0.2.6" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" - integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== - assertion-error@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== -ast-parents@0.0.1: +ast-parents@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/ast-parents/-/ast-parents-0.0.1.tgz#508fd0f05d0c48775d9eccda2e174423261e8dd3" integrity sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA== -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - astral-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== -async-eventemitter@^0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/async-eventemitter/-/async-eventemitter-0.2.4.tgz#f5e7c8ca7d3e46aab9ec40a292baf686a0bafaca" - integrity sha512-pd20BwL7Yt1zwDFy+8MX8F1+WCT8aQeKj0kQnTrH9WaeRETlRamVhD0JtRPmrV4GfOJ2F9CvdQkZeZhnh2TuHw== +async-mutex@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/async-mutex/-/async-mutex-0.4.1.tgz#bccf55b96f2baf8df90ed798cb5544a1f6ee4c2c" + integrity sha512-WfoBo4E/TbCX1G95XTjbWTE3X2XLG0m1Xbv2cwOtuPdyH9CZvnaA5nCt1ucjaKEgW2A5IF71hxrRhr83Je5xjA== + dependencies: + tslib "^2.4.0" + +async-retry@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" + integrity sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw== dependencies: - async "^2.4.0" + retry "0.13.1" async@1.x: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" integrity sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w== -async@^2.4.0: - version "2.6.4" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" - integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== - dependencies: - lodash "^4.17.14" - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -1509,20 +2967,19 @@ at-least-node@^1.0.0: resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" -aws4@^1.8.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" - integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== +axios@^0.21.1: + version "0.21.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== + dependencies: + follow-redirects "^1.14.0" axios@^0.24.0: version "0.24.0" @@ -1531,56 +2988,54 @@ axios@^0.24.0: dependencies: follow-redirects "^1.14.4" +axios@^0.27.2: + version "0.27.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" + integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== + dependencies: + follow-redirects "^1.14.9" + form-data "^4.0.0" + +axios@^1.3.4, axios@^1.5.1, axios@^1.6.7, axios@^1.7.4: + version "1.10.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.10.0.tgz#af320aee8632eaf2a400b6a1979fa75856f38d54" + integrity sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== base-x@^3.0.2: - version "3.0.9" - resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" - integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== + version "3.0.11" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.11.tgz#40d80e2a1aeacba29792ccc6c5354806421287ff" + integrity sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA== dependencies: safe-buffer "^5.0.1" -base64-js@^1.3.1: +base64-js@^1.0.2: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== - dependencies: - tweetnacl "^0.14.3" - bech32@1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== -bigint-crypto-utils@^3.0.23: - version "3.1.7" - resolved "https://registry.yarnpkg.com/bigint-crypto-utils/-/bigint-crypto-utils-3.1.7.tgz#c4c1b537c7c1ab7aadfaecf3edfd45416bf2c651" - integrity sha512-zpCQpIE2Oy5WIQpjC9iYZf8Uh9QqoS51ZCooAcNvzv1AQ3VWdT52D0ksr1+/faeK8HVIej1bxXcP75YcqH3KPA== - dependencies: - bigint-mod-arith "^3.1.0" - -bigint-mod-arith@^3.1.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/bigint-mod-arith/-/bigint-mod-arith-3.1.2.tgz#658e416bc593a463d97b59766226d0a3021a76b1" - integrity sha512-nx8J8bBeiRR+NlsROFH9jHswW5HO8mgfOSqW0AmjicMMvaONDa8AO+5ViKDUUNytBPWiwfvZP4/Bj4Y3lUfvgQ== - -bignumber.js@^9.0.0: - version "9.1.1" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.1.tgz#c4df7dc496bd849d4c9464344c1aa74228b4dac6" - integrity sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig== +bignumber.js@^9.0.0, bignumber.js@^9.1.2: + version "9.3.0" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.3.0.tgz#bdba7e2a4c1a2eba08290e8dcad4f36393c92acd" + integrity sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA== binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== blakejs@^1.1.0: version "1.2.1" @@ -1592,15 +3047,20 @@ bn.js@4.11.6: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" integrity sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA== -bn.js@^4.11.0, bn.js@^4.11.8, bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== +bn.js@^4.11.9: + version "4.12.2" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.2.tgz#3d8fed6796c24e177737f7cc5172ee04ef39ec99" + integrity sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw== bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" - integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + version "5.2.2" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.2.tgz#82c09f9ebbb17107cd72cb7fd39bd1f9d0aaa566" + integrity sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw== + +bowser@^2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f" + integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA== boxen@^5.1.2: version "5.1.2" @@ -1617,35 +3077,25 @@ boxen@^5.1.2: wrap-ansi "^7.0.0" brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + version "1.1.12" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843" + integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" brorand@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== -browser-level@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browser-level/-/browser-level-1.0.1.tgz#36e8c3183d0fe1c405239792faaab5f315871011" - integrity sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ== - dependencies: - abstract-level "^1.0.2" - catering "^2.1.1" - module-error "^1.0.2" - run-parallel-limit "^1.1.0" - browser-stdout@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" @@ -1689,59 +3139,70 @@ buffer-xor@^1.0.3: resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== -buffer@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== +buffer@4.9.2: + version "4.9.2" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" + integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" bufferutil@^4.0.1: - version "4.0.7" - resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.7.tgz#60c0d19ba2c992dd8273d3f73772ffc894c153ad" - integrity sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw== + version "4.0.9" + resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.9.tgz#6e81739ad48a95cad45a279588e13e95e24a800a" + integrity sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw== dependencies: node-gyp-build "^4.3.0" -busboy@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" - integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== - dependencies: - streamsearch "^1.1.0" - bytes@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -call-bind@^1.0.0, call-bind@^1.0.2: +cacache@^18.0.0: + version "18.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-18.0.4.tgz#4601d7578dadb59c66044e157d02a3314682d6a5" + integrity sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ== + dependencies: + "@npmcli/fs" "^3.1.0" + fs-minipass "^3.0.0" + glob "^10.2.2" + lru-cache "^10.0.1" + minipass "^7.0.3" + minipass-collect "^2.0.1" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + p-map "^4.0.0" + ssri "^10.0.0" + tar "^6.1.11" + unique-filename "^3.0.0" + +call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" + es-errors "^1.3.0" + function-bind "^1.1.2" -caller-callsite@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" - integrity sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ== +call-bind@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c" + integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== dependencies: - callsites "^2.0.0" + call-bind-apply-helpers "^1.0.0" + es-define-property "^1.0.0" + get-intrinsic "^1.2.4" + set-function-length "^1.2.2" -caller-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" - integrity sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A== +call-bound@^1.0.2, call-bound@^1.0.3, call-bound@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== dependencies: - caller-callsite "^2.0.0" - -callsites@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" - integrity sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ== + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" callsites@^3.0.0: version "3.1.0" @@ -1758,12 +3219,7 @@ caseless@^0.12.0, caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== -catering@^2.1.0, catering@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" - integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== - -cbor@^8.1.0: +cbor@8.1.0, cbor@^10.0.0, cbor@^8.1.0, cbor@^9.0.0: version "8.1.0" resolved "https://registry.yarnpkg.com/cbor/-/cbor-8.1.0.tgz#cfc56437e770b73417a2ecbfc9caf6b771af60d5" integrity sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg== @@ -1771,26 +3227,26 @@ cbor@^8.1.0: nofilter "^3.1.0" chai-as-promised@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0" - integrity sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA== + version "7.1.2" + resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.2.tgz#70cd73b74afd519754161386421fb71832c6d041" + integrity sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw== dependencies: check-error "^1.0.2" chai@^4.3.4: - version "4.3.6" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.6.tgz#ffe4ba2d9fa9d6680cc0b370adae709ec9011e9c" - integrity sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q== + version "4.5.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.5.0.tgz#707e49923afdd9b13a8b0b47d33d732d13812fd8" + integrity sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw== dependencies: assertion-error "^1.1.0" - check-error "^1.0.2" - deep-eql "^3.0.1" - get-func-name "^2.0.0" - loupe "^2.3.1" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" pathval "^1.1.1" - type-detect "^4.0.5" + type-detect "^4.1.0" -chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0: +chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -1798,7 +3254,7 @@ chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.2: +chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1808,26 +3264,23 @@ chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.2: supports-color "^5.3.0" chalk@^5.0.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.1.2.tgz#d957f370038b75ac572471e83be4c5ca9f8e8c45" - integrity sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ== - -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + version "5.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.4.1.tgz#1b48bf0963ec158dce2aacf69c093ae2dd2092d8" + integrity sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w== charenc@0.0.2, "charenc@>= 0.0.1": version "0.0.2" resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== -check-error@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" - integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA== +check-error@^1.0.2, check-error@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== + dependencies: + get-func-name "^2.0.2" -chokidar@3.5.3, chokidar@^3.4.0: +chokidar@3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -1842,6 +3295,21 @@ chokidar@3.5.3, chokidar@^3.4.0: optionalDependencies: fsevents "~2.3.2" +chokidar@^3.5.2: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + chokidar@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" @@ -1849,29 +3317,23 @@ chokidar@^4.0.0: dependencies: readdirp "^4.0.1" +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + ci-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -classic-level@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/classic-level/-/classic-level-1.2.0.tgz#2d52bdec8e7a27f534e67fdeb890abef3e643c27" - integrity sha512-qw5B31ANxSluWz9xBzklRWTUAJ1SXIdaVKTVS7HcTGKOAmExx65Wo5BUICW+YGORe2FOUaDghoI9ZDxj82QcFg== + version "1.0.6" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.6.tgz#8fe672437d01cd6c4561af5334e0cc50ff1955f7" + integrity sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw== dependencies: - abstract-level "^1.0.2" - catering "^2.1.0" - module-error "^1.0.1" - napi-macros "~2.0.0" - node-gyp-build "^4.3.0" + inherits "^2.0.4" + safe-buffer "^5.2.1" clean-stack@^2.0.0: version "2.2.0" @@ -1883,13 +3345,6 @@ cli-boxes@^2.2.1: resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw== - dependencies: - restore-cursor "^2.0.0" - cli-table3@^0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" @@ -1900,20 +3355,15 @@ cli-table3@^0.5.0: optionalDependencies: colors "^1.1.2" -cli-table3@^0.6.0: - version "0.6.3" - resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.3.tgz#61ab765aac156b52f222954ffc607a6f01dbeeb2" - integrity sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg== +cli-table3@^0.6.0, cli-table3@^0.6.2: + version "0.6.5" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.5.tgz#013b91351762739c16a9567c21a04632e449bf2f" + integrity sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ== dependencies: string-width "^4.2.0" optionalDependencies: "@colors/colors" "1.5.0" -cli-width@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" - integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== - cliui@^7.0.2: version "7.0.4" resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" @@ -1952,7 +3402,7 @@ colors@1.4.0, colors@^1.1.2: resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== -combined-stream@^1.0.6, combined-stream@~1.0.6: +combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -1984,21 +3434,26 @@ command-line-usage@^6.1.0: table-layout "^1.0.2" typical "^5.2.0" -commander@2.18.0: - version "2.18.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.18.0.tgz#2bf063ddee7c7891176981a2cc798e5754bc6970" - integrity sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ== - -commander@3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" - integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow== +commander@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== commander@^8.1.0: version "8.3.0" resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== +commander@^9.4.0: + version "9.5.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" + integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== + +compare-versions@^6.0.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-6.1.1.tgz#7af3cc1099ba37d244b3145a9af5201b629148a9" + integrity sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -2019,30 +3474,20 @@ cookie@^0.4.1: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== -core-util-is@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== - core-util-is@~1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== -cosmiconfig@^5.0.7: - version "5.2.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" - integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== +cosmiconfig@^8.0.0: + version "8.3.6" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3" + integrity sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA== dependencies: - import-fresh "^2.0.0" - is-directory "^0.3.1" - js-yaml "^3.13.1" - parse-json "^4.0.0" - -crc-32@^1.2.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" - integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== + import-fresh "^3.3.0" + js-yaml "^4.1.0" + parse-json "^5.2.0" + path-type "^4.0.0" create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: version "1.2.0" @@ -2055,7 +3500,17 @@ create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: ripemd160 "^2.0.1" sha.js "^2.4.0" -create-hmac@^1.1.4, create-hmac@^1.1.7: +create-hash@~1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd" + integrity sha512-snRpch/kwQhcdlnZKYanNF1m0RDlrCdSKQaH87w1FCFPVPNCQ/Il9QJKAX2jVBZddRdaHBMC+zXa9Gw9tmkNUA== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + ripemd160 "^2.0.0" + sha.js "^2.4.0" + +create-hmac@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== @@ -2072,28 +3527,17 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-fetch@^3.1.4: - version "3.1.5" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" - integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== - dependencies: - node-fetch "2.6.7" - -cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== +cross-fetch@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-4.1.0.tgz#8f69355007ee182e47fa692ecbaa37a52e43c3d2" + integrity sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw== dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" + node-fetch "^2.7.0" -cross-spawn@^7.0.2: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== +cross-spawn@^7.0.2, cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== dependencies: path-key "^3.1.0" shebang-command "^2.0.0" @@ -2104,27 +3548,25 @@ crypt@0.0.2, "crypt@>= 0.0.1": resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== -d@1, d@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" - integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== +d@1, d@^1.0.1, d@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.2.tgz#2aefd554b81981e7dccf72d6842ae725cb17e5de" + integrity sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw== dependencies: - es5-ext "^0.10.50" - type "^1.0.1" + es5-ext "^0.10.64" + type "^2.7.2" -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g== - dependencies: - assert-plus "^1.0.0" +death@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/death/-/death-1.1.0.tgz#01aa9c401edd92750514470b8266390c66c67318" + integrity sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w== -debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: + version "4.4.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" + integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== dependencies: - ms "2.1.2" + ms "^2.1.3" debug@4.3.3: version "4.3.3" @@ -2145,17 +3587,10 @@ decamelize@^4.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== -deep-eql@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" - integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== - dependencies: - type-detect "^4.0.0" - -deep-eql@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.1.tgz#b1154ea8c95012d9f23f37f4eecfd2ee8e5b9323" - integrity sha512-rc6HkZswtl+KMi/IODZ8k7C/P37clC2Rf1HYI11GqdbgvggIyHjsU5MdjlTlaP6eu24c0sR3mcW2SqsVZ1sXUw== +deep-eql@^4.0.1, deep-eql@^4.1.3: + version "4.1.4" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.4.tgz#d0d3912865911bb8fac5afb4e3acfa6a28dc72b7" + integrity sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg== dependencies: type-detect "^4.0.0" @@ -2174,6 +3609,20 @@ deep-object-diff@^1.1.9: resolved "https://registry.yarnpkg.com/deep-object-diff/-/deep-object-diff-1.1.9.tgz#6df7ef035ad6a0caa44479c536ed7b02570f4595" integrity sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA== +define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -2200,9 +3649,16 @@ diff@^4.0.1: integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== diff@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40" - integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw== + version "5.2.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" + integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== + +difflib@^0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/difflib/-/difflib-0.2.4.tgz#b5e30361a6db023176d562892db85940a718f47e" + integrity sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w== + dependencies: + heap ">= 0.2.0" dir-glob@^3.0.1: version "3.0.1" @@ -2223,15 +3679,26 @@ dotenv@^10.0.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw== +dotenv@^16.4.5: + version "16.6.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.6.1.tgz#773f0e69527a8315c7285d5ee73c4459d20a8020" + integrity sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow== + +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== -elliptic@6.5.4, elliptic@^6.5.2, elliptic@^6.5.4: +elliptic@6.5.4: version "6.5.4" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== @@ -2244,42 +3711,101 @@ elliptic@6.5.4, elliptic@^6.5.2, elliptic@^6.5.4: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== +elliptic@6.6.1, elliptic@^6.5.7: + version "6.6.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.1.tgz#3b8ffb02670bf69e382c7f65bf524c97c5405c06" + integrity sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -enquirer@^2.3.0: - version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +encode-utf8@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/encode-utf8/-/encode-utf8-1.0.3.tgz#f30fdd31da07fb596f281beb2f6b027851994cda" + integrity sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw== + +encoding@^0.1.13: + version "0.1.13" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" + integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== + dependencies: + iconv-lite "^0.6.2" + +enquirer@^2.3.0, enquirer@^2.3.6: + version "2.4.1" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" + integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== dependencies: ansi-colors "^4.1.1" + strip-ansi "^6.0.1" env-paths@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== +err-code@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" + integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-define-property@^1.0.0, es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== dependencies: - is-arrayish "^0.2.1" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" -es5-ext@^0.10.35, es5-ext@^0.10.50: - version "0.10.62" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5" - integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA== +es5-ext@^0.10.35, es5-ext@^0.10.62, es5-ext@^0.10.63, es5-ext@^0.10.64, es5-ext@~0.10.14: + version "0.10.64" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.64.tgz#12e4ffb48f1ba2ea777f1fcdd1918ef73ea21714" + integrity sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg== dependencies: es6-iterator "^2.0.3" es6-symbol "^3.1.3" + esniff "^2.0.1" next-tick "^1.1.0" es6-iterator@^2.0.3: @@ -2297,17 +3823,17 @@ es6-promise@^4.2.8: integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== es6-symbol@^3.1.1, es6-symbol@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" - integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== + version "3.1.4" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.4.tgz#f4e7d28013770b4208ecbf3e0bf14d3bcb557b8c" + integrity sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg== dependencies: - d "^1.0.1" - ext "^1.1.2" + d "^1.0.2" + ext "^1.7.0" escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: version "4.0.0" @@ -2331,14 +3857,6 @@ escodegen@1.8.x: optionalDependencies: source-map "~0.2.0" -eslint-scope@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" - integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" @@ -2347,146 +3865,81 @@ eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-scope@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" - integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-utils@^1.3.1: - version "1.4.3" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint-visitor-keys@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" - integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== - -eslint@^5.6.0: - version "5.16.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" - integrity sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg== - dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.9.1" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" - doctrine "^3.0.0" - eslint-scope "^4.0.3" - eslint-utils "^1.3.1" - eslint-visitor-keys "^1.0.0" - espree "^5.0.1" - esquery "^1.0.1" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob "^7.1.2" - globals "^11.7.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - inquirer "^6.2.2" - js-yaml "^3.13.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.11" - minimatch "^3.0.4" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.2" - progress "^2.0.0" - regexpp "^2.0.1" - semver "^5.5.1" - strip-ansi "^4.0.0" - strip-json-comments "^2.0.1" - table "^5.2.3" - text-table "^0.2.0" +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== eslint@^8.12.0: - version "8.25.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.25.0.tgz#00eb962f50962165d0c4ee3327708315eaa8058b" - integrity sha512-DVlJOZ4Pn50zcKW5bYH7GQK/9MsoQG2d5eDH0ebEkE8PbgzTTmtt/VTH9GGJ4BfeZCpBLqFfvsjX35UacUL83A== - dependencies: - "@eslint/eslintrc" "^1.3.3" - "@humanwhocodes/config-array" "^0.10.5" + version "8.57.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9" + integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.1" + "@humanwhocodes/config-array" "^0.13.0" "@humanwhocodes/module-importer" "^1.0.1" - ajv "^6.10.0" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.3.2" doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.1.1" - eslint-utils "^3.0.0" - eslint-visitor-keys "^3.3.0" - espree "^9.4.0" - esquery "^1.4.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^6.0.1" find-up "^5.0.0" - glob-parent "^6.0.1" - globals "^13.15.0" - globby "^11.1.0" - grapheme-splitter "^1.0.4" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" ignore "^5.2.0" - import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - js-sdsl "^4.1.4" + is-path-inside "^3.0.3" js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" lodash.merge "^4.6.2" minimatch "^3.1.2" natural-compare "^1.4.0" - optionator "^0.9.1" - regexpp "^3.2.0" + optionator "^0.9.3" strip-ansi "^6.0.1" - strip-json-comments "^3.1.0" text-table "^0.2.0" -espree@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" - integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A== +esniff@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/esniff/-/esniff-2.0.1.tgz#a4d4b43a5c71c7ec51c51098c1d8a29081f9b308" + integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg== dependencies: - acorn "^6.0.7" - acorn-jsx "^5.0.0" - eslint-visitor-keys "^1.0.0" + d "^1.0.1" + es5-ext "^0.10.62" + event-emitter "^0.3.5" + type "^2.7.2" -espree@^9.4.0: - version "9.4.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.0.tgz#cd4bc3d6e9336c433265fc0aa016fc1aaf182f8a" - integrity sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw== +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== dependencies: - acorn "^8.8.0" + acorn "^8.9.0" acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.3.0" + eslint-visitor-keys "^3.4.1" esprima@2.7.x, esprima@^2.7.1: version "2.7.3" @@ -2498,14 +3951,14 @@ esprima@^4.0.0: resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.0.1, esquery@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== +esquery@^1.4.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== dependencies: estraverse "^5.1.0" -esrecurse@^4.1.0, esrecurse@^4.3.0: +esrecurse@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== @@ -2533,34 +3986,32 @@ esutils@^2.0.2: integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== eth-gas-reporter@^0.2.25: - version "0.2.25" - resolved "https://registry.yarnpkg.com/eth-gas-reporter/-/eth-gas-reporter-0.2.25.tgz#546dfa946c1acee93cb1a94c2a1162292d6ff566" - integrity sha512-1fRgyE4xUB8SoqLgN3eDfpDfwEfRxh2Sz1b7wzFbyQA+9TekMmvSjjoRu9SKcSVyK+vLkLIsVbJDsTWjw195OQ== + version "0.2.27" + resolved "https://registry.yarnpkg.com/eth-gas-reporter/-/eth-gas-reporter-0.2.27.tgz#928de8548a674ed64c7ba0bf5795e63079150d4e" + integrity sha512-femhvoAM7wL0GcI8ozTdxfuBtBFJ9qsyIAsmKVjlWAHUbdnnXHt+lKzz/kmldM5lA9jLuNHGwuIxorNpLbR1Zw== dependencies: - "@ethersproject/abi" "^5.0.0-beta.146" "@solidity-parser/parser" "^0.14.0" + axios "^1.5.1" cli-table3 "^0.5.0" colors "1.4.0" ethereum-cryptography "^1.0.3" - ethers "^4.0.40" + ethers "^5.7.2" fs-readdir-recursive "^1.1.0" lodash "^4.17.14" markdown-table "^1.1.3" - mocha "^7.1.1" + mocha "^10.2.0" req-cwd "^2.0.0" - request "^2.88.0" - request-promise-native "^1.0.5" sha1 "^1.1.1" sync-request "^6.0.0" ethereum-bloom-filters@^1.0.6: - version "1.0.10" - resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz#3ca07f4aed698e75bd134584850260246a5fed8a" - integrity sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA== + version "1.2.0" + resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.2.0.tgz#8294f074c1a6cbd32c39d2cc77ce86ff14797dab" + integrity sha512-28hyiE7HVsWubqhpVLVmZXFd4ITeHi+BUu05o9isf0GUpMtzBUi+8/gFrGaGYzvGAJQmJ3JKj77Mk9G98T84rA== dependencies: - js-sha3 "^0.8.0" + "@noble/hashes" "^1.4.0" -ethereum-cryptography@0.1.3, ethereum-cryptography@^0.1.3: +ethereum-cryptography@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191" integrity sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ== @@ -2582,37 +4033,26 @@ ethereum-cryptography@0.1.3, ethereum-cryptography@^0.1.3: setimmediate "^1.0.5" ethereum-cryptography@^1.0.3: - version "1.1.2" - resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-1.1.2.tgz#74f2ac0f0f5fe79f012c889b3b8446a9a6264e6d" - integrity sha512-XDSJlg4BD+hq9N2FjvotwUET9Tfxpxc3kWGE2AqUG5vcbeunnbImVk3cj6e/xT3phdW21mE8R5IugU4fspQDcQ== - dependencies: - "@noble/hashes" "1.1.2" - "@noble/secp256k1" "1.6.3" - "@scure/bip32" "1.1.0" - "@scure/bip39" "1.1.0" - -ethereumjs-abi@^0.6.8: - version "0.6.8" - resolved "https://registry.yarnpkg.com/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz#71bc152db099f70e62f108b7cdfca1b362c6fcae" - integrity sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA== + version "1.2.0" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz#5ccfa183e85fdaf9f9b299a79430c044268c9b3a" + integrity sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw== dependencies: - bn.js "^4.11.8" - ethereumjs-util "^6.0.0" + "@noble/hashes" "1.2.0" + "@noble/secp256k1" "1.7.1" + "@scure/bip32" "1.1.5" + "@scure/bip39" "1.1.1" -ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz#fcb4e4dd5ceacb9d2305426ab1a5cd93e3163b69" - integrity sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw== +ethereum-cryptography@^2.0.0, ethereum-cryptography@^2.1.2, ethereum-cryptography@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz#58f2810f8e020aecb97de8c8c76147600b0b8ccf" + integrity sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg== dependencies: - "@types/bn.js" "^4.11.3" - bn.js "^4.11.0" - create-hash "^1.1.2" - elliptic "^6.5.2" - ethereum-cryptography "^0.1.3" - ethjs-util "0.1.6" - rlp "^2.2.3" + "@noble/curves" "1.4.2" + "@noble/hashes" "1.4.0" + "@scure/bip32" "1.4.0" + "@scure/bip39" "1.3.0" -ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.5: +ethereumjs-util@^7.0.3, ethereumjs-util@^7.1.5: version "7.1.5" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== @@ -2623,7 +4063,7 @@ ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.5: ethereum-cryptography "^0.1.3" rlp "^2.2.4" -ethers@5.7.2, ethers@^5.1.0, ethers@^5.7.2: +ethers@5.7.2: version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== @@ -2659,56 +4099,54 @@ ethers@5.7.2, ethers@^5.1.0, ethers@^5.7.2: "@ethersproject/web" "5.7.1" "@ethersproject/wordlists" "5.7.0" -ethers@^4.0.40: - version "4.0.49" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.49.tgz#0eb0e9161a0c8b4761be547396bbe2fb121a8894" - integrity sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg== - dependencies: - aes-js "3.0.0" - bn.js "^4.11.9" - elliptic "6.5.4" - hash.js "1.1.3" - js-sha3 "0.5.7" - scrypt-js "2.0.4" - setimmediate "1.0.4" - uuid "2.0.1" - xmlhttprequest "1.8.0" - -ethers@^5.7.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.1.tgz#48c83a44900b5f006eb2f65d3ba6277047fd4f33" - integrity sha512-5krze4dRLITX7FpU8J4WscXqADiKmyeNlylmmDLbS95DaZpBhDe2YSwRQwKXWNyXcox7a3gBgm/MkGXV1O1S/Q== - dependencies: - "@ethersproject/abi" "5.7.0" - "@ethersproject/abstract-provider" "5.7.0" - "@ethersproject/abstract-signer" "5.7.0" - "@ethersproject/address" "5.7.0" - "@ethersproject/base64" "5.7.0" - "@ethersproject/basex" "5.7.0" - "@ethersproject/bignumber" "5.7.0" - "@ethersproject/bytes" "5.7.0" - "@ethersproject/constants" "5.7.0" - "@ethersproject/contracts" "5.7.0" - "@ethersproject/hash" "5.7.0" - "@ethersproject/hdnode" "5.7.0" - "@ethersproject/json-wallets" "5.7.0" - "@ethersproject/keccak256" "5.7.0" - "@ethersproject/logger" "5.7.0" - "@ethersproject/networks" "5.7.1" - "@ethersproject/pbkdf2" "5.7.0" - "@ethersproject/properties" "5.7.0" - "@ethersproject/providers" "5.7.1" - "@ethersproject/random" "5.7.0" - "@ethersproject/rlp" "5.7.0" - "@ethersproject/sha2" "5.7.0" - "@ethersproject/signing-key" "5.7.0" - "@ethersproject/solidity" "5.7.0" - "@ethersproject/strings" "5.7.0" - "@ethersproject/transactions" "5.7.0" - "@ethersproject/units" "5.7.0" - "@ethersproject/wallet" "5.7.0" - "@ethersproject/web" "5.7.1" - "@ethersproject/wordlists" "5.7.0" +ethers@^5.1.0, ethers@^5.7.0, ethers@^5.7.2, ethers@^5.8.0: + version "5.8.0" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.8.0.tgz#97858dc4d4c74afce83ea7562fe9493cedb4d377" + integrity sha512-DUq+7fHrCg1aPDFCHx6UIPb3nmt2XMpM7Y/g2gLhsl3lIBqeAfOJIl1qEvRf2uq3BiKxmh6Fh5pfp2ieyek7Kg== + dependencies: + "@ethersproject/abi" "5.8.0" + "@ethersproject/abstract-provider" "5.8.0" + "@ethersproject/abstract-signer" "5.8.0" + "@ethersproject/address" "5.8.0" + "@ethersproject/base64" "5.8.0" + "@ethersproject/basex" "5.8.0" + "@ethersproject/bignumber" "5.8.0" + "@ethersproject/bytes" "5.8.0" + "@ethersproject/constants" "5.8.0" + "@ethersproject/contracts" "5.8.0" + "@ethersproject/hash" "5.8.0" + "@ethersproject/hdnode" "5.8.0" + "@ethersproject/json-wallets" "5.8.0" + "@ethersproject/keccak256" "5.8.0" + "@ethersproject/logger" "5.8.0" + "@ethersproject/networks" "5.8.0" + "@ethersproject/pbkdf2" "5.8.0" + "@ethersproject/properties" "5.8.0" + "@ethersproject/providers" "5.8.0" + "@ethersproject/random" "5.8.0" + "@ethersproject/rlp" "5.8.0" + "@ethersproject/sha2" "5.8.0" + "@ethersproject/signing-key" "5.8.0" + "@ethersproject/solidity" "5.8.0" + "@ethersproject/strings" "5.8.0" + "@ethersproject/transactions" "5.8.0" + "@ethersproject/units" "5.8.0" + "@ethersproject/wallet" "5.8.0" + "@ethersproject/web" "5.8.0" + "@ethersproject/wordlists" "5.8.0" + +ethers@^6.14.0, ethers@^6.7.0, ethers@^6.8.1: + version "6.14.4" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.14.4.tgz#0f6fbc562a8425c7c888da307fa71ef796be0c04" + integrity sha512-Jm/dzRs2Z9iBrT6e9TvGxyb5YVKAPLlpna7hjxH7KH/++DSh2T/JVmQUv7iHI5E55hDbp/gEVvstWYXVxXFzsA== + dependencies: + "@adraffy/ens-normalize" "1.10.1" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@types/node" "22.7.5" + aes-js "4.0.0-beta.5" + tslib "2.7.0" + ws "8.17.1" ethjs-unit@0.1.6: version "0.1.6" @@ -2718,18 +4156,13 @@ ethjs-unit@0.1.6: bn.js "4.11.6" number-to-bn "1.7.0" -ethjs-util@0.1.6, ethjs-util@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" - integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w== +event-emitter@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + integrity sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA== dependencies: - is-hex-prefixed "1.0.0" - strip-hex-prefix "1.0.0" - -event-target-shim@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" - integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + d "1" + es5-ext "~0.10.14" eventemitter3@4.0.4: version "4.0.4" @@ -2744,57 +4177,38 @@ evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" -ext@^1.1.2: +ext@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f" integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw== dependencies: type "^2.7.2" -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== - -extsprintf@^1.2.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" - integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== +fast-base64-decode@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz#b434a0dd7d92b12b43f26819300d2dafb83ee418" + integrity sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q== fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-diff@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" - integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== +fast-diff@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" + integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== -fast-glob@^3.2.7, fast-glob@^3.2.9: - version "3.2.12" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" - integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== +fast-glob@^3.0.3, fast-glob@^3.2.7, fast-glob@^3.2.9: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" glob-parent "^5.1.2" merge2 "^1.3.0" - micromatch "^4.0.4" + micromatch "^4.0.8" fast-json-stable-stringify@^2.0.0: version "2.1.0" @@ -2806,26 +4220,29 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== -fastq@^1.6.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== - dependencies: - reusify "^1.0.4" +fast-uri@^3.0.1: + version "3.0.6" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.6.tgz#88f130b77cfaea2378d56bf970dea21257a68748" + integrity sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw== -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA== +fast-xml-parser@4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz#86dbf3f18edf8739326447bcaac31b4ae7f6514f" + integrity sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw== dependencies: - escape-string-regexp "^1.0.5" + strnum "^1.0.5" -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== +fastq@^1.6.0: + version "1.19.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5" + integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ== dependencies: - flat-cache "^2.0.1" + reusify "^1.0.4" + +fdir@^6.4.4: + version "6.4.6" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.6.tgz#2b268c0232697063111bbf3f64810a2a741ba281" + integrity sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w== file-entry-cache@^6.0.1: version "6.0.1" @@ -2834,10 +4251,10 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" @@ -2856,28 +4273,13 @@ find-up@5.0.0, find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ== - dependencies: - locate-path "^2.0.0" - -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== - dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" - flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== dependencies: - flatted "^3.1.0" + flatted "^3.2.9" + keyv "^4.5.3" rimraf "^3.0.2" flat@^5.0.2: @@ -2885,49 +4287,58 @@ flat@^5.0.2: resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== +flatted@^3.2.9: + version "3.3.3" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" + integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== -flatted@^3.1.0: - version "3.2.7" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" - integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== +fmix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/fmix/-/fmix-0.1.0.tgz#c7bbf124dec42c9d191cfb947d0a9778dd986c0c" + integrity sha512-Y6hyofImk9JdzU8k5INtTXX1cu8LDlePWDFU5sftm9H+zKCr5SGrVjdhkvsim646cw5zD0nADj8oHyXMZmCZ9w== + dependencies: + imul "^1.0.0" -follow-redirects@^1.12.1, follow-redirects@^1.14.4: - version "1.15.2" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" - integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== +follow-redirects@^1.12.1, follow-redirects@^1.14.0, follow-redirects@^1.14.4, follow-redirects@^1.14.9, follow-redirects@^1.15.6: + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== +for-each@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.5.tgz#d650688027826920feeb0af747ee7b9421a41d47" + integrity sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg== dependencies: - is-callable "^1.1.3" + is-callable "^1.2.7" -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== +foreground-child@^3.1.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" + integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== + dependencies: + cross-spawn "^7.0.6" + signal-exit "^4.0.1" form-data@^2.2.0: - version "2.5.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" - integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== + version "2.5.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.3.tgz#f9bcf87418ce748513c0c3494bb48ec270c97acc" + integrity sha512-XHIrMD0NpDrNM/Ckf7XJiBbLl57KEhT3+i3yY+eWm+cqYZJQTZrKo8Y8AWKnuV5GT4scfuUGt9LzNoIx3dU1nQ== dependencies: asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" + combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + mime-types "^2.1.35" + safe-buffer "^5.2.1" -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== +form-data@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.3.tgz#608b1b3f3e28be0fccf5901fc85fb3641e5cf0ae" + integrity sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA== dependencies: asynckit "^0.4.0" - combined-stream "^1.0.6" + combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + hasown "^2.0.2" mime-types "^2.1.12" fp-ts@1.19.3: @@ -2940,16 +4351,14 @@ fp-ts@^1.0.0: resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.19.5.tgz#3da865e585dfa1fdfd51785417357ac50afc520a" integrity sha512-wDNqTimnzs8QqpldiId9OavWK2NptormjXnRJTQecNjzwfyp6P/8s/zG8e4h3ja3oqkKaY72UlTjQYt/1yXf9A== -fs-extra@^0.30.0: - version "0.30.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" - integrity sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA== +fs-extra@^10.0.0, fs-extra@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" + integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - klaw "^1.0.0" - path-is-absolute "^1.0.0" - rimraf "^2.2.8" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" fs-extra@^7.0.0, fs-extra@^7.0.1: version "7.0.1" @@ -2960,6 +4369,15 @@ fs-extra@^7.0.0, fs-extra@^7.0.1: jsonfile "^4.0.0" universalify "^0.1.0" +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-extra@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" @@ -2970,6 +4388,20 @@ fs-extra@^9.1.0: jsonfile "^6.0.1" universalify "^2.0.0" +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + +fs-minipass@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-3.0.3.tgz#79a85981c4dc120065e96f62086bf6f9dc26cc54" + integrity sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw== + dependencies: + minipass "^7.0.3" + fs-readdir-recursive@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" @@ -2981,59 +4413,61 @@ fs.realpath@^1.0.0: integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-func-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" - integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== - -get-intrinsic@^1.0.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" - integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.3" +get-func-name@^2.0.1, get-func-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== -get-intrinsic@^1.1.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" - integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.3" +get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" get-port@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc" integrity sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg== -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng== +get-proto@^1.0.0, get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + +ghost-testrpc@^0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz#c4de9557b1d1ae7b2d20bbe474a91378ca90ce92" + integrity sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ== dependencies: - assert-plus "^1.0.0" + chalk "^2.4.2" + node-emoji "^1.10.0" glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" @@ -3042,7 +4476,7 @@ glob-parent@^5.1.2, glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -glob-parent@^6.0.1: +glob-parent@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== @@ -3061,6 +4495,18 @@ glob@7.2.0: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^10.2.2: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + glob@^5.0.15: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" @@ -3072,7 +4518,7 @@ glob@^5.0.15: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.2, glob@^7.1.3, glob@^7.1.6: +glob@^7.0.0, glob@^7.1.3, glob@^7.1.6: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -3084,18 +4530,54 @@ glob@^7.1.2, glob@^7.1.3, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" -globals@^11.7.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== +glob@^8.0.3: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + +global-modules@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== + dependencies: + global-prefix "^3.0.0" + +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" -globals@^13.15.0: - version "13.17.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.17.0.tgz#902eb1e680a41da93945adbdcb5a9f361ba69bd4" - integrity sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw== +globals@^13.19.0: + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== dependencies: type-fest "^0.20.2" +globby@^10.0.1: + version "10.0.2" + resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543" + integrity sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg== + dependencies: + "@types/glob" "^7.1.1" + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.0.3" + glob "^7.1.3" + ignore "^5.1.1" + merge2 "^1.2.3" + slash "^3.0.0" + globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" @@ -3108,22 +4590,20 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" +gopd@^1.0.1, gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0: - version "4.2.10" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== -grapheme-splitter@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" - integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== growl@1.10.5: version "1.10.5" @@ -3131,30 +4611,17 @@ growl@1.10.5: integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== handlebars@^4.0.1: - version "4.7.7" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" - integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== + version "4.7.8" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" + integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ== dependencies: minimist "^1.2.5" - neo-async "^2.6.0" + neo-async "^2.6.2" source-map "^0.6.1" wordwrap "^1.0.0" optionalDependencies: uglify-js "^3.1.4" -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q== - -har-validator@~5.1.3: - version "5.1.5" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" - integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== - dependencies: - ajv "^6.12.3" - har-schema "^2.0.0" - "hardhat-chai-matchers@https://github.com/jflatow/hardhat/releases/download/viaIR/nomicfoundation-hardhat-chai-matchers-v1.0.4.tgz": version "1.0.4" resolved "https://github.com/jflatow/hardhat/releases/download/viaIR/nomicfoundation-hardhat-chai-matchers-v1.0.4.tgz#785d92b3ad4a66a888153ac0dcc55b319d5c9b65" @@ -3180,30 +4647,53 @@ hardhat-contract-sizer@^2.10.0: cli-table3 "^0.6.0" strip-ansi "^6.0.0" -hardhat-cover@compound-finance/hardhat-cover: - version "1.0.0" - resolved "https://codeload.github.com/compound-finance/hardhat-cover/tar.gz/c9064e8bf04d3ae34773adbfee70cade741078ec" +hardhat-deploy@^0.11.43: + version "0.11.45" + resolved "https://registry.yarnpkg.com/hardhat-deploy/-/hardhat-deploy-0.11.45.tgz#bed86118175a38a03bb58aba2ce1ed5e80a20bc8" + integrity sha512-aC8UNaq3JcORnEUIwV945iJuvBwi65tjHVDU3v6mOcqik7WAzHVCJ7cwmkkipsHrWysrB5YvGF1q9S1vIph83w== + dependencies: + "@ethersproject/abi" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/contracts" "^5.7.0" + "@ethersproject/providers" "^5.7.2" + "@ethersproject/solidity" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wallet" "^5.7.0" + "@types/qs" "^6.9.7" + axios "^0.21.1" + chalk "^4.1.2" + chokidar "^3.5.2" + debug "^4.3.2" + enquirer "^2.3.6" + ethers "^5.7.0" + form-data "^4.0.0" + fs-extra "^10.0.0" + match-all "^1.2.6" + murmur-128 "^0.2.1" + qs "^6.9.4" + zksync-web3 "^0.14.3" hardhat-gas-reporter@^1.0.7: - version "1.0.9" - resolved "https://registry.yarnpkg.com/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.9.tgz#9a2afb354bc3b6346aab55b1c02ca556d0e16450" - integrity sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg== + version "1.0.10" + resolved "https://registry.yarnpkg.com/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.10.tgz#ebe5bda5334b5def312747580cd923c2b09aef1b" + integrity sha512-02N4+So/fZrzJ88ci54GqwVA3Zrf0C9duuTyGt0CFRIh/CdNwbnTgkXkRfojOMLBQ+6t+lBIkgbsOtqMvNwikA== dependencies: array-uniq "1.0.3" eth-gas-reporter "^0.2.25" sha1 "^1.1.1" -hardhat@2.22.14: - version "2.22.14" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.22.14.tgz#389bb3789a52adc0b1a3b4bfc9b891239d5a2b42" - integrity sha512-sD8vHtS9l5QQVHzyPPe3auwZDJyZ0fG3Z9YENVa4oOqVEefCuHcPzdU736rei3zUKTqkX0zPIHkSMHpu02Fq1A== +hardhat@^2.0.4: + version "2.25.0" + resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.25.0.tgz#473bf07b62a0ea30cf003e4585f71a0ffc70c739" + integrity sha512-yBiA74Yj3VnTRj7lhnn8GalvBdvsMOqTKRrRATSy/2v0VIR2hR0Jcnmfn4aQBLtGAnr3Q2c8CxL0g3LYegUp+g== dependencies: + "@ethereumjs/util" "^9.1.0" "@ethersproject/abi" "^5.1.2" - "@metamask/eth-sig-util" "^4.0.0" - "@nomicfoundation/edr" "^0.6.4" - "@nomicfoundation/ethereumjs-common" "4.0.4" - "@nomicfoundation/ethereumjs-tx" "5.0.4" - "@nomicfoundation/ethereumjs-util" "9.0.4" + "@nomicfoundation/edr" "^0.11.1" "@nomicfoundation/solidity-analyzer" "^0.1.0" "@sentry/node" "^5.18.1" "@types/bn.js" "^5.1.0" @@ -3212,90 +4702,79 @@ hardhat@2.22.14: aggregate-error "^3.0.0" ansi-escapes "^4.3.0" boxen "^5.1.2" - chalk "^2.4.2" chokidar "^4.0.0" ci-info "^2.0.0" debug "^4.1.1" enquirer "^2.3.0" env-paths "^2.2.0" ethereum-cryptography "^1.0.3" - ethereumjs-abi "^0.6.8" - find-up "^2.1.0" + find-up "^5.0.0" fp-ts "1.19.3" fs-extra "^7.0.1" - glob "7.2.0" immutable "^4.0.0-rc.12" io-ts "1.10.4" json-stream-stringify "^3.1.4" keccak "^3.0.2" lodash "^4.17.11" + micro-eth-signer "^0.14.0" mnemonist "^0.38.0" mocha "^10.0.0" p-map "^4.0.0" + picocolors "^1.1.0" raw-body "^2.4.1" resolve "1.17.0" semver "^6.3.0" solc "0.8.26" source-map-support "^0.5.13" stacktrace-parser "^0.1.10" + tinyglobby "^0.2.6" tsort "0.0.1" undici "^5.14.0" uuid "^8.3.2" ws "^7.4.6" -hardhat@^2.0.4: - version "2.12.0" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.12.0.tgz#51e59f1ff4991bcb66d1a380ea807e6c15fcac34" - integrity sha512-mNJFbVG479HwOzxiaLxobyvED2M1aEAuPPYhEo1+88yicMDSTrU2JIS7vV+V0GSNQKaDoiHCmV6bcKjiljT/dQ== +hardhat@^2.22.17: + version "2.26.0" + resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.26.0.tgz#8244d7be2ae69f89240fba78f4e35adf5883c764" + integrity sha512-hwEUBvMJzl3Iuru5bfMOEDeF2d7cbMNNF46rkwdo8AeW2GDT4VxFLyYWTi6PTLrZiftHPDiKDlAdAiGvsR9FYA== dependencies: + "@ethereumjs/util" "^9.1.0" "@ethersproject/abi" "^5.1.2" - "@metamask/eth-sig-util" "^4.0.0" - "@nomicfoundation/ethereumjs-block" "^4.0.0" - "@nomicfoundation/ethereumjs-blockchain" "^6.0.0" - "@nomicfoundation/ethereumjs-common" "^3.0.0" - "@nomicfoundation/ethereumjs-evm" "^1.0.0" - "@nomicfoundation/ethereumjs-rlp" "^4.0.0" - "@nomicfoundation/ethereumjs-statemanager" "^1.0.0" - "@nomicfoundation/ethereumjs-trie" "^5.0.0" - "@nomicfoundation/ethereumjs-tx" "^4.0.0" - "@nomicfoundation/ethereumjs-util" "^8.0.0" - "@nomicfoundation/ethereumjs-vm" "^6.0.0" + "@nomicfoundation/edr" "^0.11.3" "@nomicfoundation/solidity-analyzer" "^0.1.0" "@sentry/node" "^5.18.1" - "@types/bn.js" "^5.1.0" - "@types/lru-cache" "^5.1.0" - abort-controller "^3.0.0" adm-zip "^0.4.16" aggregate-error "^3.0.0" ansi-escapes "^4.3.0" - chalk "^2.4.2" - chokidar "^3.4.0" + boxen "^5.1.2" + chokidar "^4.0.0" ci-info "^2.0.0" debug "^4.1.1" enquirer "^2.3.0" env-paths "^2.2.0" ethereum-cryptography "^1.0.3" - ethereumjs-abi "^0.6.8" - find-up "^2.1.0" + find-up "^5.0.0" fp-ts "1.19.3" fs-extra "^7.0.1" - glob "7.2.0" immutable "^4.0.0-rc.12" io-ts "1.10.4" + json-stream-stringify "^3.1.4" keccak "^3.0.2" lodash "^4.17.11" + micro-eth-signer "^0.16.0" mnemonist "^0.38.0" mocha "^10.0.0" p-map "^4.0.0" - qs "^6.7.0" + picocolors "^1.1.0" raw-body "^2.4.1" resolve "1.17.0" semver "^6.3.0" - solc "0.7.3" + solc "0.8.26" source-map-support "^0.5.13" stacktrace-parser "^0.1.10" + tinyglobby "^0.2.6" tsort "0.0.1" - undici "^5.4.0" + undici "^5.14.0" uuid "^8.3.2" ws "^7.4.6" @@ -3314,24 +4793,31 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-symbols@^1.0.2, has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== dependencies: - has-symbols "^1.0.2" + has-symbols "^1.0.3" -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== +hash-base@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1" + integrity sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw== dependencies: - function-bind "^1.1.1" + inherits "^2.0.1" hash-base@^3.0.0: version "3.1.0" @@ -3339,16 +4825,8 @@ hash-base@^3.0.0: integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== dependencies: inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -hash.js@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" - integrity sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.0" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: version "1.1.7" @@ -3358,11 +4836,23 @@ hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: inherits "^2.0.3" minimalistic-assert "^1.0.1" +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + he@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +"heap@>= 0.2.0": + version "0.2.7" + resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.7.tgz#1e6adf711d3f27ce35a81fe3b7bd576c2260a8fc" + integrity sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg== + hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -3372,6 +4862,13 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +hosted-git-info@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-7.0.2.tgz#9b751acac097757667f30114607ef7b661ff4f17" + integrity sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w== + dependencies: + lru-cache "^10.0.1" + http-basic@^8.1.1: version "8.1.3" resolved "https://registry.yarnpkg.com/http-basic/-/http-basic-8.1.3.tgz#a7cabee7526869b9b710136970805b1004261bbf" @@ -3382,6 +4879,11 @@ http-basic@^8.1.1: http-response-object "^3.0.1" parse-cache-control "^1.0.1" +http-cache-semantics@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz#205f4db64f8562b76a4ff9235aa5279839a09dd5" + integrity sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ== + http-errors@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" @@ -3398,6 +4900,14 @@ http-https@^1.0.0: resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" integrity sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg== +http-proxy-agent@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" + integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" + http-response-object@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/http-response-object/-/http-response-object-3.0.2.tgz#7f435bb210454e4360d074ef1f989d5ea8aa9810" @@ -3405,15 +4915,6 @@ http-response-object@^3.0.1: dependencies: "@types/node" "^10.0.3" -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ== - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - https-proxy-agent@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" @@ -3422,49 +4923,61 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" -iconv-lite@0.4.24, iconv-lite@^0.4.24: +https-proxy-agent@^7.0.1: + version "7.0.6" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9" + integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw== + dependencies: + agent-base "^7.1.2" + debug "4" + +iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" -ieee754@^1.2.1: +iconv-lite@^0.6.2: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +ieee754@^1.1.4: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +ignore@^5.1.1, ignore@^5.2.0, ignore@^5.2.4: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== -ignore@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" - integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== +immer@10.0.2: + version "10.0.2" + resolved "https://registry.yarnpkg.com/immer/-/immer-10.0.2.tgz#11636c5b77acf529e059582d76faf338beb56141" + integrity sha512-Rx3CqeqQ19sxUtYV9CU911Vhy8/721wRFnJv3REVGWUmoAcIwzifTsdmJte/MV+0/XpM35LZdQMBGkRIoLPwQA== immutable@^4.0.0-rc.12: - version "4.1.0" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.1.0.tgz#f795787f0db780183307b9eb2091fcac1f6fafef" - integrity sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ== - -import-fresh@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" - integrity sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg== - dependencies: - caller-path "^2.0.0" - resolve-from "^3.0.0" + version "4.3.7" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.7.tgz#c70145fc90d89fb02021e65c84eb0226e4e5a381" + integrity sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw== -import-fresh@^3.0.0, import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== +import-fresh@^3.2.1, import-fresh@^3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== dependencies: parent-module "^1.0.0" resolve-from "^4.0.0" +imul@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/imul/-/imul-1.0.1.tgz#9d5867161e8b3de96c2c38d5dc7cb102f35e2ac9" + integrity sha512-WFAgfwPLAjU66EKt6vRdTlKj4nAgIDQzh29JonLa4Bqtl6D8JrIMvWjCnx7xEjVNmP3U0fM5o8ZObk7d0f62bA== + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -3488,24 +5001,15 @@ inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, i resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -inquirer@^6.2.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" - integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== - dependencies: - ansi-escapes "^3.2.0" - chalk "^2.4.2" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^3.0.3" - figures "^2.0.0" - lodash "^4.17.12" - mute-stream "0.0.7" - run-async "^2.2.0" - rxjs "^6.4.0" - string-width "^2.1.0" - strip-ansi "^5.1.0" - through "^2.3.6" +ini@^1.3.5: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +interpret@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== io-ts@1.10.4: version "1.10.4" @@ -3514,13 +5018,21 @@ io-ts@1.10.4: dependencies: fp-ts "^1.0.0" +ip-address@^9.0.5: + version "9.0.5" + resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-9.0.5.tgz#117a960819b08780c3bd1f14ef3c1cc1d3f3ea5a" + integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g== + dependencies: + jsbn "1.1.0" + sprintf-js "^1.1.3" + is-arguments@^1.0.4: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.2.0.tgz#ad58c6aecf563b78ef2bf04df540da8f5d7d8e1b" + integrity sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA== dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" + call-bound "^1.0.2" + has-tostringtag "^1.0.2" is-arrayish@^0.2.1: version "0.2.1" @@ -3534,25 +5046,27 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-buffer@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" - integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== - is-buffer@~1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-callable@^1.1.3: +is-callable@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-directory@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" - integrity sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw== +is-core-module@^2.16.0: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + dependencies: + hasown "^2.0.2" + +is-docker@^2.0.0, is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== is-extglob@^2.1.1: version "2.1.1" @@ -3570,11 +5084,14 @@ is-fullwidth-code-point@^3.0.0: integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== is-generator-function@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" - integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.1.0.tgz#bf3eeda931201394f57b5dba2800f91a238309ca" + integrity sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ== dependencies: - has-tostringtag "^1.0.0" + call-bound "^1.0.3" + get-proto "^1.0.0" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" @@ -3588,28 +5105,44 @@ is-hex-prefixed@1.0.0: resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" integrity sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA== +is-lambda@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" + integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== + is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + is-plain-obj@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== -is-typed-array@^1.1.10, is-typed-array@^1.1.3: - version "1.1.10" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" - integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== +is-regex@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22" + integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g== + dependencies: + call-bound "^1.0.2" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +is-typed-array@^1.1.14, is-typed-array@^1.1.3: + version "1.1.15" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b" + integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" + which-typed-array "^1.1.16" -is-typedarray@^1.0.0, is-typedarray@~1.0.0: +is-typedarray@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== @@ -3619,20 +5152,44 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -isarray@~1.0.0: +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== +isomorphic-unfetch@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz#87341d5f4f7b63843d468438128cb087b7c3e98f" + integrity sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q== + dependencies: + node-fetch "^2.6.1" + unfetch "^4.2.0" + +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" jest-diff@^27.4.2: version "27.5.1" @@ -3649,15 +5206,10 @@ jest-get-type@^27.5.1: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== -js-sdsl@^4.1.4: - version "4.1.5" - resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.1.5.tgz#1ff1645e6b4d1b028cd3f862db88c9d887f26e2a" - integrity sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q== - -js-sha3@0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" - integrity sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g== +js-cookie@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" + integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== js-sha3@0.8.0, js-sha3@^0.8.0: version "0.8.0" @@ -3669,7 +5221,7 @@ js-tokens@^4.0.0: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@3.x, js-yaml@^3.12.0, js-yaml@^3.13.0, js-yaml@^3.13.1: +js-yaml@3.x: version "3.14.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== @@ -3684,15 +5236,20 @@ js-yaml@4.1.0, js-yaml@^4.1.0: dependencies: argparse "^2.0.1" -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== +jsbn@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" + integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== json-schema-traverse@^0.4.1: version "0.4.1" @@ -3704,11 +5261,6 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== -json-schema@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" - integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== - json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" @@ -3719,17 +5271,15 @@ json-stream-stringify@^3.1.4: resolved "https://registry.yarnpkg.com/json-stream-stringify/-/json-stream-stringify-3.1.6.tgz#ebe32193876fb99d4ec9f612389a8d8e2b5d54d4" integrity sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog== -json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: +json-stringify-safe@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== -jsonfile@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" - integrity sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw== - optionalDependencies: - graceful-fs "^4.1.6" +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== jsonfile@^4.0.0: version "4.0.0" @@ -3747,60 +5297,41 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -jsprim@^1.2.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" - integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.4.0" - verror "1.10.0" +jsonparse@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== + +jsonschema@^1.2.4: + version "1.5.0" + resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.5.0.tgz#f6aceb1ab9123563dd901d05f81f9d4883d3b7d8" + integrity sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw== keccak@^3.0.0, keccak@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.2.tgz#4c2c6e8c54e04f2670ee49fa734eb9da152206e0" - integrity sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ== + version "3.0.4" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.4.tgz#edc09b89e633c0549da444432ecf062ffadee86d" + integrity sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q== dependencies: node-addon-api "^2.0.0" node-gyp-build "^4.2.0" readable-stream "^3.6.0" -klaw@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" - integrity sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw== - optionalDependencies: - graceful-fs "^4.1.9" - -level-supports@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-4.0.1.tgz#431546f9d81f10ff0fea0e74533a0e875c08c66a" - integrity sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA== - -level-transcoder@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/level-transcoder/-/level-transcoder-1.0.1.tgz#f8cef5990c4f1283d4c86d949e73631b0bc8ba9c" - integrity sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w== +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== dependencies: - buffer "^6.0.3" - module-error "^1.0.1" + json-buffer "3.0.1" -level@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/level/-/level-8.0.0.tgz#41b4c515dabe28212a3e881b61c161ffead14394" - integrity sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ== - dependencies: - browser-level "^1.0.1" - classic-level "^1.2.0" +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== levn@^0.4.1: version "0.4.1" @@ -3810,13 +5341,18 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA== +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== locate-path@^6.0.0: version "6.0.0" @@ -3830,6 +5366,16 @@ lodash.camelcase@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== +lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== + +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -3840,7 +5386,7 @@ lodash.truncate@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== -lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21: +lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -3853,26 +5399,17 @@ log-symbols@4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" -loupe@^2.3.1: - version "2.3.4" - resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.4.tgz#7e0b9bffc76f148f9be769cb1321d3dcf3cb25f3" - integrity sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ== - dependencies: - get-func-name "^2.0.0" - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== +loupe@^2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" + integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== dependencies: - yallist "^3.0.2" + get-func-name "^2.0.1" -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" +lru-cache@^10.0.1, lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== lru_map@^0.3.3: version "0.3.3" @@ -3884,15 +5421,38 @@ make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +make-fetch-happen@^13.0.0: + version "13.0.1" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz#273ba2f78f45e1f3a6dca91cede87d9fa4821e36" + integrity sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA== + dependencies: + "@npmcli/agent" "^2.0.0" + cacache "^18.0.0" + http-cache-semantics "^4.1.1" + is-lambda "^1.0.1" + minipass "^7.0.2" + minipass-fetch "^3.0.0" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + negotiator "^0.6.3" + proc-log "^4.2.0" + promise-retry "^2.0.1" + ssri "^10.0.0" + markdown-table@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-1.1.3.tgz#9fcb69bcfdb8717bfd0398c6ec2d93036ef8de60" integrity sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q== -mcl-wasm@^0.7.1: - version "0.7.9" - resolved "https://registry.yarnpkg.com/mcl-wasm/-/mcl-wasm-0.7.9.tgz#c1588ce90042a8700c3b60e40efb339fc07ab87f" - integrity sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ== +match-all@^1.2.6: + version "1.2.7" + resolved "https://registry.yarnpkg.com/match-all/-/match-all-1.2.7.tgz#3c03b7f7ee372ae177aac5eca08c3ad6af59633a" + integrity sha512-qSpsBKarh55r9KyXzFC3xBLRf2GlGasba2em9kbpRsSlGvdTAqjx3QD0r3FKSARiW+OE4iMHYsolM3aX9n5djw== + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== md5.js@^1.3.4: version "1.3.5" @@ -3903,7 +5463,7 @@ md5.js@^1.3.4: inherits "^2.0.1" safe-buffer "^5.1.2" -md5@^2.1.0: +md5@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== @@ -3912,31 +5472,52 @@ md5@^2.1.0: crypt "0.0.2" is-buffer "~1.1.6" -memory-level@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/memory-level/-/memory-level-1.0.0.tgz#7323c3fd368f9af2f71c3cd76ba403a17ac41692" - integrity sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og== - dependencies: - abstract-level "^1.0.0" - functional-red-black-tree "^1.0.1" - module-error "^1.0.1" - memorystream@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" integrity sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw== -merge2@^1.3.0, merge2@^1.4.1: +merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== +micro-eth-signer@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/micro-eth-signer/-/micro-eth-signer-0.14.0.tgz#8aa1fe997d98d6bdf42f2071cef7eb01a66ecb22" + integrity sha512-5PLLzHiVYPWClEvZIXXFu5yutzpadb73rnQCpUqIHu3No3coFuWQNfE5tkBQJ7djuLYl6aRLaS0MgWJYGoqiBw== + dependencies: + "@noble/curves" "~1.8.1" + "@noble/hashes" "~1.7.1" + micro-packed "~0.7.2" + +micro-eth-signer@^0.16.0: + version "0.16.0" + resolved "https://registry.yarnpkg.com/micro-eth-signer/-/micro-eth-signer-0.16.0.tgz#a35d0de41ae9164ec96150a0f1fc29e7635ff106" + integrity sha512-rsSJcMGfY+kt3ROlL3U6y5BcjkK2H0zDKUQV6soo1JvjrctKKe+X7rKB0YIuwhWjlhJIoVHLuRYF+GXyyuVXxQ== + dependencies: + "@noble/curves" "~1.9.2" + "@noble/hashes" "2.0.0-beta.1" + micro-packed "~0.7.3" + +micro-ftch@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/micro-ftch/-/micro-ftch-0.3.1.tgz#6cb83388de4c1f279a034fb0cf96dfc050853c5f" + integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== + +micro-packed@~0.7.2, micro-packed@~0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/micro-packed/-/micro-packed-0.7.3.tgz#59e96b139dffeda22705c7a041476f24cabb12b6" + integrity sha512-2Milxs+WNC00TRlem41oRswvw31146GiSaoCT7s3Xi2gMUglW5QBeqlQaZeHr5tJx9nm3i57LNXPqxOOaWtTYg== + dependencies: + "@scure/base" "~1.2.5" + +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" mime-db@1.52.0: @@ -3944,18 +5525,13 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@~2.1.19: +mime-types@^2.1.12, mime-types@^2.1.35: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -3966,37 +5542,99 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== -"minimatch@2 || 3", minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@*, "minimatch@2 || 3", minimatch@4.2.1, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2, minimatch@^5.0.1, minimatch@^9.0.4, minimatch@^9.0.5: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" -minimatch@4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.1.tgz#40d9d511a46bdc4e563c22c3080cde9c0d8299b4" - integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g== +minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +minipass-collect@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-2.0.1.tgz#1621bc77e12258a12c60d34e2276ec5c20680863" + integrity sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw== dependencies: - brace-expansion "^1.1.7" + minipass "^7.0.3" -minimist@^1.2.5, minimist@^1.2.6: - version "1.2.7" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" - integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== +minipass-fetch@^3.0.0: + version "3.0.5" + resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-3.0.5.tgz#f0f97e40580affc4a35cc4a1349f05ae36cb1e4c" + integrity sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg== + dependencies: + minipass "^7.0.3" + minipass-sized "^1.0.3" + minizlib "^2.1.2" + optionalDependencies: + encoding "^0.1.13" + +minipass-flush@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" + integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== + dependencies: + minipass "^3.0.0" + +minipass-pipeline@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" + integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== + dependencies: + minipass "^3.0.0" + +minipass-sized@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" + integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== + dependencies: + minipass "^3.0.0" + +minipass@^3.0.0: + version "3.3.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" + integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== + dependencies: + yallist "^4.0.0" + +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== + +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3, minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + +minizlib@^2.1.1, minizlib@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" -mkdirp@0.5.x, mkdirp@^0.5.1, mkdirp@~0.5.1: +mkdirp@0.5.x: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== dependencies: minimist "^1.2.6" -mkdirp@^1.0.4: +mkdirp@^1.0.3, mkdirp@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== +mkdirp@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" + integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== + mnemonist@^0.38.0: version "0.38.5" resolved "https://registry.yarnpkg.com/mnemonist/-/mnemonist-0.38.5.tgz#4adc7f4200491237fe0fa689ac0b86539685cade" @@ -4005,15 +5643,15 @@ mnemonist@^0.38.0: obliterator "^2.0.0" mocha-junit-reporter@^2.0.2: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-2.1.0.tgz#7997348c2e757686c54e42b3756930b55a4518a4" - integrity sha512-Zhz1J+XqJUaAOuSFtHgi2+b+W3rP1SZtaU3HHNNp1iEKMSeoC1/EQUVkGknkLNOBxJhXJ4xLgOr8TbYAZOkUIw== + version "2.2.1" + resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-2.2.1.tgz#739f5595d0f051d07af9d74e32c416e13a41cde5" + integrity sha512-iDn2tlKHn8Vh8o4nCzcUVW4q7iXp7cC4EB78N0cDHIobLymyHNwe0XG8HEHHjc3hJlXm0Vy6zcrxaIhnI2fWmw== dependencies: - debug "^2.2.0" - md5 "^2.1.0" - mkdirp "~0.5.1" + debug "^4.3.4" + md5 "^2.3.0" + mkdirp "^3.0.0" strip-ansi "^6.0.1" - xml "^1.0.0" + xml "^1.0.1" mocha-multi-reporters@hayesgm/mocha-multi-reporters#hayesgm/reporter-options-to-option: version "1.5.1" @@ -4022,7 +5660,7 @@ mocha-multi-reporters@hayesgm/mocha-multi-reporters#hayesgm/reporter-options-to- debug "^4.1.1" lodash "^4.17.15" -mocha@^10.0.0, mocha@^7.1.1, mocha@^9.1.3: +mocha@^10.0.0, mocha@^10.2.0, mocha@^9.1.3: version "9.2.2" resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.2.tgz#d70db46bdb93ca57402c809333e5a84977a88fb9" integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g== @@ -4052,11 +5690,6 @@ mocha@^10.0.0, mocha@^7.1.1, mocha@^9.1.3: yargs-parser "20.2.4" yargs-unparser "2.0.0" -module-error@^1.0.1, module-error@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" - integrity sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA== - ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -4067,32 +5700,52 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3: +ms@2.1.3, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - integrity sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ== +murmur-128@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/murmur-128/-/murmur-128-0.2.1.tgz#a9f6568781d2350ecb1bf80c14968cadbeaa4b4d" + integrity sha512-WseEgiRkI6aMFBbj8Cg9yBj/y+OdipwVC7zUo3W2W1JAJITwouUOtpqsmGSg67EQmwwSyod7hsVsWY5LsrfQVg== + dependencies: + encode-utf8 "^1.0.2" + fmix "^0.1.0" + imul "^1.0.0" nanoid@3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== -napi-macros@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" - integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg== +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -neo-async@^2.6.0: +ndjson@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ndjson/-/ndjson-2.0.0.tgz#320ac86f6fe53f5681897349b86ac6f43bfa3a19" + integrity sha512-nGl7LRGrzugTtaFcJMhLbpzJM6XdivmbkdlaGcrk/LXg2KL/YBC6z1g70xh0/al+oFuVFP8N8kiWRucmeEH/qQ== + dependencies: + json-stringify-safe "^5.0.1" + minimist "^1.2.5" + readable-stream "^3.6.0" + split2 "^3.0.0" + through2 "^4.0.0" + +negotiator@^0.6.3: + version "0.6.4" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.4.tgz#777948e2452651c570b712dd01c23e262713fff7" + integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w== + +neo-async@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== @@ -4102,19 +5755,13 @@ next-tick@^1.1.0: resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - nock@^13.2.2: - version "13.2.9" - resolved "https://registry.yarnpkg.com/nock/-/nock-13.2.9.tgz#4faf6c28175d36044da4cfa68e33e5a15086ad4c" - integrity sha512-1+XfJNYF1cjGB+TKMWi29eZ0b82QOvQs2YoLNzbpWGqFMtRQHTa57osqdGj4FrFPgkO4D4AZinzUJR9VvW3QUA== + version "13.5.6" + resolved "https://registry.yarnpkg.com/nock/-/nock-13.5.6.tgz#5e693ec2300bbf603b61dae6df0225673e6c4997" + integrity sha512-o2zOYiCpzRqSzPj0Zt/dQ/DqZeYoaQ7TUonc/xUPjCGl9WeHpNbxgVvOquXYAaJzI0M9BXV3HTzG0p8IUAbBTQ== dependencies: debug "^4.1.0" json-stringify-safe "^5.0.1" - lodash "^4.17.21" propagate "^2.0.0" node-addon-api@^2.0.0: @@ -4122,17 +5769,29 @@ node-addon-api@^2.0.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== -node-fetch@2, node-fetch@2.6.7: - version "2.6.7" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== +node-addon-api@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762" + integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== + +node-emoji@^1.10.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.11.0.tgz#69a0150e6946e2f115e9d7ea4df7971e2628301c" + integrity sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A== + dependencies: + lodash "^4.17.21" + +node-fetch@2, node-fetch@^2.6.1, node-fetch@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== dependencies: whatwg-url "^5.0.0" node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40" - integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg== + version "4.8.4" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.4.tgz#8a70ee85464ae52327772a90d66c6077a900cfc8" + integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ== nofilter@^3.1.0: version "3.1.0" @@ -4151,6 +5810,30 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +npm-package-arg@^11.0.0: + version "11.0.3" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-11.0.3.tgz#dae0c21199a99feca39ee4bfb074df3adac87e2d" + integrity sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw== + dependencies: + hosted-git-info "^7.0.0" + proc-log "^4.0.0" + semver "^7.3.5" + validate-npm-package-name "^5.0.0" + +npm-registry-fetch@^17.1.0: + version "17.1.0" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-17.1.0.tgz#fb69e8e762d456f08bda2f5f169f7638fb92beb1" + integrity sha512-5+bKQRH0J1xG1uZ1zMNvxW0VEyoNWgJpY9UDuluPFLKDfJ9u2JmmjmTJV1srBGQOROfdBMiVvnH2Zvpbm+xkVA== + dependencies: + "@npmcli/redact" "^2.0.0" + jsonparse "^1.3.1" + make-fetch-happen "^13.0.0" + minipass "^7.0.2" + minipass-fetch "^3.0.0" + minizlib "^2.1.2" + npm-package-arg "^11.0.0" + proc-log "^4.0.0" + number-to-bn@1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" @@ -4159,25 +5842,20 @@ number-to-bn@1.7.0: bn.js "4.11.6" strip-hex-prefix "1.0.0" -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-inspect@^1.9.0: - version "1.12.2" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" - integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== +object-inspect@^1.13.3: + version "1.13.4" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" + integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== obliterator@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-2.0.4.tgz#fa650e019b2d075d745e44f1effeb13a2adbe816" - integrity sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ== + version "2.0.5" + resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-2.0.5.tgz#031e0145354b0c18840336ae51d41e7d6d2c76aa" + integrity sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw== oboe@2.1.5: version "2.1.5" @@ -4193,14 +5871,16 @@ once@1.x, once@^1.3.0: dependencies: wrappy "1" -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ== +open@^8.4.0: + version "8.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" + integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== dependencies: - mimic-fn "^1.0.0" + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" -optionator@^0.8.1, optionator@^0.8.2: +optionator@^0.8.1: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== @@ -4212,17 +5892,17 @@ optionator@^0.8.1, optionator@^0.8.2: type-check "~0.3.2" word-wrap "~1.2.3" -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== dependencies: deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" - word-wrap "^1.2.3" + word-wrap "^1.2.5" ordinal@^1.0.3: version "1.0.3" @@ -4234,13 +5914,6 @@ os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - p-limit@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" @@ -4248,13 +5921,6 @@ p-limit@^3.0.2: dependencies: yocto-queue "^0.1.0" -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg== - dependencies: - p-limit "^1.1.0" - p-locate@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" @@ -4269,10 +5935,10 @@ p-map@^4.0.0: dependencies: aggregate-error "^3.0.0" -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== +package-json-from-dist@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== parent-module@^1.0.0: version "1.0.1" @@ -4286,18 +5952,15 @@ parse-cache-control@^1.0.1: resolved "https://registry.yarnpkg.com/parse-cache-control/-/parse-cache-control-1.0.1.tgz#8eeab3e54fa56920fe16ba38f77fa21aacc2d74e" integrity sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg== -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw== +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== dependencies: + "@babel/code-frame" "^7.0.0" error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" path-exists@^4.0.0: version "4.0.0" @@ -4309,26 +5972,24 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-is-inside@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== - -path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== - path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.6: +path-parse@^1.0.6, path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -4340,26 +6001,47 @@ pathval@^1.1.1: integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== pbkdf2@^3.0.17: - version "3.1.2" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" - integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== + version "3.1.3" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.3.tgz#8be674d591d65658113424592a95d1517318dd4b" + integrity sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA== dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" + create-hash "~1.1.3" + create-hmac "^1.1.7" + ripemd160 "=2.0.1" + safe-buffer "^5.2.1" + sha.js "^2.4.11" + to-buffer "^1.2.0" -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== +picocolors@^1.1.0, picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +picomatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" + integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pluralize@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" + integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== + +possible-typed-array-names@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz#93e3582bc0e5426586d9d07b79ee40fc841de4ae" + integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg== + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -4370,15 +6052,10 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== -prettier@^1.14.3: - version "1.19.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" - integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== - -prettier@^2.1.2: - version "2.7.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" - integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== +prettier@^2.1.2, prettier@^2.8.3: + version "2.8.8" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" + integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== pretty-format@^27.5.1: version "27.5.1" @@ -4389,51 +6066,71 @@ pretty-format@^27.5.1: ansi-styles "^5.0.0" react-is "^17.0.1" +proc-log@^4.0.0, proc-log@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-4.2.0.tgz#b6f461e4026e75fdfe228b265e9f7a00779d7034" + integrity sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA== + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== +promise-retry@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" + integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== + dependencies: + err-code "^2.0.2" + retry "^0.12.0" promise@^8.0.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/promise/-/promise-8.2.0.tgz#a1f6280ab67457fbfc8aad2b198c9497e9e5c806" - integrity sha512-+CMAlLHqwRYwBMXKCP+o8ns7DN+xHDUiI+0nArsiJ9y+kJVPLFxEaSw6Ha9s9H0tftxg2Yzl25wqj9G7m5wLZg== + version "8.3.0" + resolved "https://registry.yarnpkg.com/promise/-/promise-8.3.0.tgz#8cb333d1edeb61ef23869fbb8a4ea0279ab60e0a" + integrity sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg== dependencies: asap "~2.0.6" +prompts@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + propagate@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/propagate/-/propagate-2.0.1.tgz#40cdedab18085c792334e64f0ac17256d38f9a45" integrity sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag== -psl@^1.1.28: - version "1.9.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" - integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== +proper-lockfile@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" + integrity sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA== + dependencies: + graceful-fs "^4.2.4" + retry "^0.12.0" + signal-exit "^3.0.2" -punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== -qs@^6.4.0, qs@^6.7.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== - dependencies: - side-channel "^1.0.4" +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== -qs@~6.5.2: - version "6.5.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" - integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== +qs@^6.4.0, qs@^6.9.4: + version "6.14.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.0.tgz#c63fa40680d2c5c941412a0e899c89af60c0a930" + integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w== + dependencies: + side-channel "^1.1.0" -queue-microtask@^1.2.2, queue-microtask@^1.2.3: +queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== @@ -4446,9 +6143,9 @@ randombytes@^2.1.0: safe-buffer "^5.1.0" raw-body@^2.4.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" - integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== dependencies: bytes "3.1.2" http-errors "2.0.0" @@ -4460,10 +6157,19 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== +readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readable-stream@^2.2.2: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -4473,19 +6179,10 @@ readable-stream@^2.2.2: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - readdirp@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.1.tgz#bd115327129672dc47f87408f05df9bd9ca3ef55" - integrity sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw== + version "4.1.2" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d" + integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== readdirp@~3.6.0: version "3.6.0" @@ -4494,21 +6191,25 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw== + dependencies: + resolve "^1.1.6" + +recursive-readdir@^2.2.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.3.tgz#e726f328c0d69153bcabd5c322d3195252379372" + integrity sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA== + dependencies: + minimatch "^3.0.5" + reduce-flatten@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27" integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w== -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - -regexpp@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - req-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/req-cwd/-/req-cwd-2.0.0.tgz#d4082b4d44598036640fb73ddea01ed53db49ebc" @@ -4523,54 +6224,12 @@ req-from@^2.0.0: dependencies: resolve-from "^3.0.0" -request-promise-core@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f" - integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw== - dependencies: - lodash "^4.17.19" - -request-promise-native@^1.0.5: - version "1.0.9" - resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28" - integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g== - dependencies: - request-promise-core "1.1.4" - stealthy-require "^1.1.1" - tough-cookie "^2.3.3" - -request@^2.88.0: - version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== -require-from-string@^2.0.0, require-from-string@^2.0.2: +require-from-string@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== @@ -4597,32 +6256,29 @@ resolve@1.17.0: dependencies: path-parse "^1.0.6" -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q== +resolve@^1.1.6: + version "1.22.10" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" + integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" + is-core-module "^2.16.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== +retry@0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== -rimraf@^2.2.8: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" +reusify@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.1.0.tgz#0fe13b9522e1473f51b558ee796e08f11f9b489f" + integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== rimraf@^3.0.2: version "3.0.2" @@ -4631,6 +6287,14 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" +ripemd160@=2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7" + integrity sha512-J7f4wutN8mdbV08MJnXibYpCOPHR+yzy+iQ/AsjMv2j8cLavQ8VGagDFUwwTAdF8FmRKVeNpbTTEwNHCW1g94w== + dependencies: + hash-base "^2.0.0" + inherits "^2.0.1" + ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" @@ -4639,25 +6303,13 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" -rlp@^2.2.3, rlp@^2.2.4: +rlp@^2.2.4: version "2.2.7" resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.7.tgz#33f31c4afac81124ac4b283e2bd4d9720b30beaf" integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== dependencies: bn.js "^5.2.0" -run-async@^2.2.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - -run-parallel-limit@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz#be80e936f5768623a38a963262d6bef8ff11e7ba" - integrity sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw== - dependencies: - queue-microtask "^1.2.2" - run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -4665,19 +6317,7 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rustbn.js@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/rustbn.js/-/rustbn.js-0.2.0.tgz#8082cb886e707155fd1cb6f23bd591ab8d55d0ca" - integrity sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA== - -rxjs@^6.4.0: - version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" - integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== - dependencies: - tslib "^1.9.0" - -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -4687,7 +6327,16 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +safe-regex-test@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1" + integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-regex "^1.2.1" + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -4712,41 +6361,34 @@ sc-istanbul@^0.4.5: which "^1.1.1" wordwrap "^1.0.0" -scrypt-js@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.4.tgz#32f8c5149f0797672e551c07e230f834b6af5f16" - integrity sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw== - scrypt-js@3.0.1, scrypt-js@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== secp256k1@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.3.tgz#c4559ecd1b8d3c1827ed2d1b94190d69ce267303" - integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA== + version "4.0.4" + resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.4.tgz#58f0bfe1830fe777d9ca1ffc7574962a8189f8ab" + integrity sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw== dependencies: - elliptic "^6.5.4" - node-addon-api "^2.0.0" + elliptic "^6.5.7" + node-addon-api "^5.0.0" node-gyp-build "^4.2.0" -semver@^5.5.0, semver@^5.5.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== +semver@^5.5.0: + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.7, semver@^7.3.8: - version "7.3.8" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" - integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== - dependencies: - lru-cache "^6.0.0" +semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2, semver@^7.6.2, semver@^7.6.3: + version "7.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" + integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== serialize-javascript@6.0.0: version "6.0.0" @@ -4755,10 +6397,17 @@ serialize-javascript@6.0.0: dependencies: randombytes "^2.1.0" -setimmediate@1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.4.tgz#20e81de622d4a02588ce0c8da8973cbcf1d3138f" - integrity sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog== +set-function-length@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" setimmediate@^1.0.5: version "1.0.5" @@ -4770,7 +6419,7 @@ setprototypeof@1.2.0: resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== -sha.js@^2.4.0, sha.js@^2.4.8: +sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8: version "2.4.11" resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== @@ -4786,13 +6435,6 @@ sha1@^1.1.1: charenc ">= 0.0.1" crypt ">= 0.0.1" -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== - dependencies: - shebang-regex "^1.0.0" - shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -4800,44 +6442,80 @@ shebang-command@^2.0.0: dependencies: shebang-regex "^3.0.0" -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== - shebang-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== +shelljs@^0.8.3: + version "0.8.5" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c" + integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + side-channel-map "^1.0.1" + +side-channel@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" + es-errors "^1.3.0" + object-inspect "^1.13.3" + side-channel-list "^1.0.0" + side-channel-map "^1.0.1" + side-channel-weakmap "^1.0.2" signal-exit@^3.0.2: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - slice-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" @@ -4847,20 +6525,27 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -solc@0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/solc/-/solc-0.7.3.tgz#04646961bd867a744f63d2b4e3c0701ffdc7d78a" - integrity sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA== +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + +socks-proxy-agent@^8.0.3: + version "8.0.5" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz#b9cdb4e7e998509d7659d689ce7697ac21645bee" + integrity sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw== dependencies: - command-exists "^1.2.8" - commander "3.0.2" - follow-redirects "^1.12.1" - fs-extra "^0.30.0" - js-sha3 "0.8.0" - memorystream "^0.3.1" - require-from-string "^2.0.0" - semver "^5.5.0" - tmp "0.0.33" + agent-base "^7.1.2" + debug "^4.3.4" + socks "^2.8.3" + +socks@^2.8.3: + version "2.8.5" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.5.tgz#bfe18f5ead1efc93f5ec90c79fa8bdccbcee2e64" + integrity sha512-iF+tNDQla22geJdTyJB1wM/qrX9DMRwWrciEPwWLPRWAUEM8sQiyxgckLxWT1f7+9VabJS0jTGGr4QgBuvi6Ww== + dependencies: + ip-address "^9.0.5" + smart-buffer "^4.2.0" solc@0.8.26: version "0.8.26" @@ -4876,26 +6561,59 @@ solc@0.8.26: tmp "0.0.33" solhint@^3.3.6: - version "3.3.7" - resolved "https://registry.yarnpkg.com/solhint/-/solhint-3.3.7.tgz#b5da4fedf7a0fee954cb613b6c55a5a2b0063aa7" - integrity sha512-NjjjVmXI3ehKkb3aNtRJWw55SUVJ8HMKKodwe0HnejA+k0d2kmhw7jvpa+MCTbcEgt8IWSwx0Hu6aCo/iYOZzQ== - dependencies: - "@solidity-parser/parser" "^0.14.1" - ajv "^6.6.1" - antlr4 "4.7.1" - ast-parents "0.0.1" - chalk "^2.4.2" - commander "2.18.0" - cosmiconfig "^5.0.7" - eslint "^5.6.0" - fast-diff "^1.1.2" - glob "^7.1.3" - ignore "^4.0.6" - js-yaml "^3.12.0" - lodash "^4.17.11" - semver "^6.3.0" + version "3.6.2" + resolved "https://registry.yarnpkg.com/solhint/-/solhint-3.6.2.tgz#2b2acbec8fdc37b2c68206a71ba89c7f519943fe" + integrity sha512-85EeLbmkcPwD+3JR7aEMKsVC9YrRSxd4qkXuMzrlf7+z2Eqdfm1wHWq1ffTuo5aDhoZxp2I9yF3QkxZOxOL7aQ== + dependencies: + "@solidity-parser/parser" "^0.16.0" + ajv "^6.12.6" + antlr4 "^4.11.0" + ast-parents "^0.0.1" + chalk "^4.1.2" + commander "^10.0.0" + cosmiconfig "^8.0.0" + fast-diff "^1.2.0" + glob "^8.0.3" + ignore "^5.2.4" + js-yaml "^4.1.0" + lodash "^4.17.21" + pluralize "^8.0.0" + semver "^7.5.2" + strip-ansi "^6.0.1" + table "^6.8.1" + text-table "^0.2.0" optionalDependencies: - prettier "^1.14.3" + prettier "^2.8.3" + +solidity-ast@^0.4.60: + version "0.4.60" + resolved "https://registry.yarnpkg.com/solidity-ast/-/solidity-ast-0.4.60.tgz#7c0324eace040034d6a40edbd85475e4773cbbe8" + integrity sha512-UwhasmQ37ji1ul8cIp0XlrQ/+SVQhy09gGqJH4jnwdo2TgI6YIByzi0PI5QvIGcIdFOs1pbSmJW1pnWB7AVh2w== + +solidity-coverage@^0.8.16: + version "0.8.16" + resolved "https://registry.yarnpkg.com/solidity-coverage/-/solidity-coverage-0.8.16.tgz#ae07bb11ebbd78d488c7e1a3cd15b8210692f1c9" + integrity sha512-qKqgm8TPpcnCK0HCDLJrjbOA2tQNEJY4dHX/LSSQ9iwYFS973MwjtgYn2Iv3vfCEQJTj5xtm4cuUMzlJsJSMbg== + dependencies: + "@ethersproject/abi" "^5.0.9" + "@solidity-parser/parser" "^0.20.1" + chalk "^2.4.2" + death "^1.1.0" + difflib "^0.2.4" + fs-extra "^8.1.0" + ghost-testrpc "^0.0.2" + global-modules "^2.0.0" + globby "^10.0.1" + jsonschema "^1.2.4" + lodash "^4.17.21" + mocha "^10.2.0" + node-emoji "^1.10.0" + pify "^4.0.1" + recursive-readdir "^2.2.2" + sc-istanbul "^0.4.5" + semver "^7.3.4" + shelljs "^0.8.3" + web3-utils "^1.3.6" source-map-support@^0.5.13, source-map-support@^0.5.17: version "0.5.21" @@ -4917,30 +6635,34 @@ source-map@~0.2.0: dependencies: amdefine ">=0.0.4" +split2@^3.0.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" + integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== + dependencies: + readable-stream "^3.0.0" + +sprintf-js@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" + integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== -sshpk@^1.7.0: - version "1.17.0" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" - integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" +ssri@^10.0.0: + version "10.0.6" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-10.0.6.tgz#a8aade2de60ba2bce8688e3fa349bad05c7dc1e5" + integrity sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ== + dependencies: + minipass "^7.0.3" stacktrace-parser@^0.1.10: - version "0.1.10" - resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" - integrity sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg== + version "0.1.11" + resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.11.tgz#c7c08f9b29ef566b9a6f7b255d7db572f66fabc4" + integrity sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg== dependencies: type-fest "^0.7.1" @@ -4949,22 +6671,21 @@ statuses@2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== -stealthy-require@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" - integrity sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g== - -streamsearch@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" - integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== - string-format@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/string-format/-/string-format-2.0.0.tgz#f2df2e7097440d3b65de31b6d40d54c96eaffb9b" integrity sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA== -string-width@^2.1.0, string-width@^2.1.1: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -4972,15 +6693,6 @@ string-width@^2.1.0, string-width@^2.1.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string-width@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -4990,6 +6702,15 @@ string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2 is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -5004,6 +6725,13 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" @@ -5011,13 +6739,6 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -5025,6 +6746,13 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + strip-hex-prefix@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" @@ -5032,15 +6760,15 @@ strip-hex-prefix@1.0.0: dependencies: is-hex-prefixed "1.0.0" -strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@3.1.1, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -strip-json-comments@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== +strnum@^1.0.5: + version "1.1.2" + resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.1.2.tgz#57bca4fbaa6f271081715dbc9ed7cee5493e28e4" + integrity sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA== supports-color@8.1.1: version "8.1.1" @@ -5070,6 +6798,11 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + sync-request@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/sync-request/-/sync-request-6.1.0.tgz#e96217565b5e50bbffe179868ba75532fb597e68" @@ -5096,20 +6829,10 @@ table-layout@^1.0.2: typical "^5.2.0" wordwrapjs "^4.0.0" -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - -table@^6.8.0: - version "6.8.1" - resolved "https://registry.yarnpkg.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf" - integrity sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA== +table@^6.8.0, table@^6.8.1: + version "6.9.0" + resolved "https://registry.yarnpkg.com/table/-/table-6.9.0.tgz#50040afa6264141c7566b3b81d4d82c47a8668f5" + integrity sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A== dependencies: ajv "^8.0.1" lodash.truncate "^4.4.2" @@ -5117,6 +6840,18 @@ table@^6.8.0: string-width "^4.2.3" strip-ansi "^6.0.1" +tar@^6.1.11: + version "6.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" + integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^5.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -5139,18 +6874,37 @@ then-request@^6.0.0: promise "^8.0.0" qs "^6.4.0" -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== +through2@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" + integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== + dependencies: + readable-stream "3" + +tinyglobby@^0.2.6: + version "0.2.14" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.14.tgz#5280b0cf3f972b050e74ae88406c0a6a58f4079d" + integrity sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ== + dependencies: + fdir "^6.4.4" + picomatch "^4.0.2" -tmp@0.0.33, tmp@^0.0.33: +tmp@0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== dependencies: os-tmpdir "~1.0.2" +to-buffer@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.2.1.tgz#2ce650cdb262e9112a18e65dc29dcb513c8155e0" + integrity sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ== + dependencies: + isarray "^2.0.5" + safe-buffer "^5.2.1" + typed-array-buffer "^1.0.3" + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -5163,23 +6917,15 @@ toidentifier@1.0.1: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== -tough-cookie@^2.3.3, tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== ts-command-line-args@^2.2.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/ts-command-line-args/-/ts-command-line-args-2.3.1.tgz#b6188e42efc6cf7a8898e438a873fbb15505ddd6" - integrity sha512-FR3y7pLl/fuUNSmnPhfLArGqRrpojQgIEEOVzYx9DhTmfIN7C9RWSfpkJEF4J+Gk7aVx5pak8I7vWZsaN4N84g== + version "2.5.1" + resolved "https://registry.yarnpkg.com/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz#e64456b580d1d4f6d948824c274cf6fa5f45f7f0" + integrity sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw== dependencies: chalk "^4.1.0" command-line-args "^5.1.1" @@ -5191,10 +6937,10 @@ ts-essentials@^7.0.1: resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-7.0.3.tgz#686fd155a02133eedcc5362dc8b5056cde3e5a38" integrity sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ== -ts-node@^10.4.0: - version "10.9.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" - integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== +ts-node@^10.4.0, ts-node@^10.9.1: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== dependencies: "@cspotcode/source-map-support" "^0.8.0" "@tsconfig/node10" "^1.0.7" @@ -5233,11 +6979,26 @@ ts-node@^9.1.0: source-map-support "^0.5.17" yn "3.1.1" -tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: +tslib@2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== + +tslib@^1.11.1, tslib@^1.8.1, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@^2.3.1, tslib@^2.4.0, tslib@^2.6.2: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +tslog@^4.3.1, tslog@^4.4.0: + version "4.9.3" + resolved "https://registry.yarnpkg.com/tslog/-/tslog-4.9.3.tgz#d4167d5f51748bdeab593945bc2d8f9827ea0dba" + integrity sha512-oDWuGVONxhVEBtschLf2cs/Jy8i7h1T+CpdkTNWQgdAF7DhRo2G8vMCgILKe7ojdEkLhICWgI1LYSSKaJsRgcw== + tsort@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/tsort/-/tsort-0.0.1.tgz#e2280f5e817f8bf4275657fd0f9aebd44f5a2786" @@ -5250,28 +7011,6 @@ tsutils@^3.21.0: dependencies: tslib "^1.8.1" -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== - dependencies: - safe-buffer "^5.0.1" - -tweetnacl-util@^0.15.1: - version "0.15.1" - resolved "https://registry.yarnpkg.com/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz#b80fcdb5c97bcc508be18c44a4be50f022eea00b" - integrity sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw== - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== - -tweetnacl@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" - integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== - type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -5286,10 +7025,10 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-detect@^4.0.0, type-detect@^4.0.5: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== +type-detect@^4.0.0, type-detect@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.1.0.tgz#deb2453e8f08dcae7ae98c626b13dddb0155906c" + integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== type-fest@^0.20.2: version "0.20.2" @@ -5306,15 +7045,10 @@ type-fest@^0.7.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== -type@^1.0.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" - integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== - type@^2.7.2: - version "2.7.2" - resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0" - integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw== + version "2.7.3" + resolved "https://registry.yarnpkg.com/type/-/type-2.7.3.tgz#436981652129285cc3ba94f392886c2637ea0486" + integrity sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ== typechain@^6.0.2: version "6.1.0" @@ -5332,6 +7066,15 @@ typechain@^6.0.2: ts-command-line-args "^2.2.0" ts-essentials "^7.0.1" +typed-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536" + integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-typed-array "^1.1.14" + typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -5345,9 +7088,14 @@ typedarray@^0.0.6: integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== typescript@^4.1.2, typescript@^4.4.4: - version "4.8.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" - integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== + +typescript@^5.5.4: + version "5.8.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" + integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== typescript@~4.0.3: version "4.0.8" @@ -5365,23 +7113,50 @@ typical@^5.2.0: integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg== uglify-js@^3.1.4: - version "3.17.3" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.3.tgz#f0feedf019c4510f164099e8d7e72ff2d7304377" - integrity sha512-JmMFDME3iufZnBpyKL+uS78LRiC+mK55zWfM5f/pWBJfpOttXAqYfdDGRukYhJuyRinvPVAtUhvy7rlDybNtFg== + version "3.19.3" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.3.tgz#82315e9bbc6f2b25888858acd1fff8441035b77f" + integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== + +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + +undici-types@~7.8.0: + version "7.8.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.8.0.tgz#de00b85b710c54122e44fbfd911f8d70174cd294" + integrity sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw== undici@^5.14.0, undici@^5.21.2: - version "5.22.0" - resolved "https://registry.yarnpkg.com/undici/-/undici-5.22.0.tgz#5e205d82a5aecc003fc4388ccd3d2c6e8674a0ad" - integrity sha512-fR9RXCc+6Dxav4P9VV/sp5w3eFiSdOjJYsbtWfd4s5L5C4ogyuVpdKIVHeW0vV1MloM65/f7W45nR9ZxwVdyiA== + version "5.29.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.29.0.tgz#419595449ae3f2cdcba3580a2e8903399bd1f5a3" + integrity sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg== + dependencies: + "@fastify/busboy" "^2.0.0" + +undici@^6.11.1: + version "6.21.3" + resolved "https://registry.yarnpkg.com/undici/-/undici-6.21.3.tgz#185752ad92c3d0efe7a7d1f6854a50f83b552d7a" + integrity sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw== + +unfetch@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be" + integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA== + +unique-filename@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-3.0.0.tgz#48ba7a5a16849f5080d26c760c86cf5cf05770ea" + integrity sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g== dependencies: - busboy "^1.6.0" + unique-slug "^4.0.0" -undici@^5.4.0: - version "5.11.0" - resolved "https://registry.yarnpkg.com/undici/-/undici-5.11.0.tgz#1db25f285821828fc09d3804b9e2e934ae86fc13" - integrity sha512-oWjWJHzFet0Ow4YZBkyiJwiK5vWqEYoH7BINzJAJOLedZ++JpAlCbUktW2GQ2DS2FpKmxD/JMtWUUWl1BtghGw== +unique-slug@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-4.0.0.tgz#6bae6bb16be91351badd24cdce741f892a6532e3" + integrity sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ== dependencies: - busboy "^1.6.0" + imurmurhash "^0.1.4" universalify@^0.1.0: version "0.1.2" @@ -5389,9 +7164,9 @@ universalify@^0.1.0: integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== universalify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" - integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + version "2.0.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" + integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== unpipe@1.0.0: version "1.0.0" @@ -5433,26 +7208,26 @@ util@^0.12.5: is-typed-array "^1.1.3" which-typed-array "^1.1.2" -uuid@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.1.tgz#c2a30dedb3e535d72ccf82e343941a50ba8533ac" - integrity sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg== - -uuid@^3.3.2: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +uuid@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + v8-compile-cache-lib@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== +validate-npm-package-name@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz#a316573e9b49f3ccd90dbb6eb52b3f06c6d604e8" + integrity sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ== + vendoza@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/vendoza/-/vendoza-0.0.4.tgz#636b7eed3240765482fbbf1b7c8c815386592220" @@ -5462,116 +7237,108 @@ vendoza@0.0.4: diff "^5.0.0" node-fetch "2" -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -web3-core-helpers@1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.9.0.tgz#a1ca4ac7b9cec822886643312d2e98b0e4d8f1bc" - integrity sha512-NeJzylAp9Yj9xAt2uTT+kyug3X0DLnfBdnAcGZuY6HhoNPDIfQRA9CkJjLngVRlGTLZGjNp9x9eR+RyZQgUlXg== +web3-core-helpers@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz#bd2b4140df2016d5dd3bb2b925fc29ad8678677c" + integrity sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g== dependencies: - web3-eth-iban "1.9.0" - web3-utils "1.9.0" + web3-eth-iban "1.10.4" + web3-utils "1.10.4" -web3-core-method@1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.9.0.tgz#81da8aa21503b470537c9f075f30adfad194a2d8" - integrity sha512-sswbNsY2xRBBhGeaLt9c/eDc+0yDDhi6keUBAkgIRa9ueSx/VKzUY9HMqiV6bXDcGT2fJyejq74FfEB4lc/+/w== +web3-core-method@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.10.4.tgz#566b52f006d3cbb13b21b72b8d2108999bf5d6bf" + integrity sha512-uZTb7flr+Xl6LaDsyTeE2L1TylokCJwTDrIVfIfnrGmnwLc6bmTWCCrm71sSrQ0hqs6vp/MKbQYIYqUN0J8WyA== dependencies: "@ethersproject/transactions" "^5.6.2" - web3-core-helpers "1.9.0" - web3-core-promievent "1.9.0" - web3-core-subscriptions "1.9.0" - web3-utils "1.9.0" + web3-core-helpers "1.10.4" + web3-core-promievent "1.10.4" + web3-core-subscriptions "1.10.4" + web3-utils "1.10.4" -web3-core-promievent@1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.9.0.tgz#2598a4d91b4edd3607366529f52bc96dee9f6d83" - integrity sha512-PHG1Mn23IGwMZhnPDN8dETKypqsFbHfiyRqP+XsVMPmTHkVfzDQTCBU/c2r6hUktBDoGKut5xZQpGfhFk71KbQ== +web3-core-promievent@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.10.4.tgz#629b970b7934430b03c5033c79f3bb3893027e22" + integrity sha512-2de5WnJQ72YcIhYwV/jHLc4/cWJnznuoGTJGD29ncFQHAfwW/MItHFSVKPPA5v8AhJe+r6y4Y12EKvZKjQVBvQ== dependencies: eventemitter3 "4.0.4" -web3-core-requestmanager@1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.9.0.tgz#9d7d0e7f890cf7a24e9c568b9772c64d57fc4fcd" - integrity sha512-hcJ5PCtTIJpj+8qWxoseqlCovDo94JJjTX7dZOLXgwp8ah7E3WRYozhGyZocerx+KebKyg1mCQIhkDpMwjfo9Q== +web3-core-requestmanager@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.10.4.tgz#eb1f147e6b9df84e3a37e602162f8925bdb4bb9a" + integrity sha512-vqP6pKH8RrhT/2MoaU+DY/OsYK9h7HmEBNCdoMj+4ZwujQtw/Mq2JifjwsJ7gits7Q+HWJwx8q6WmQoVZAWugg== dependencies: util "^0.12.5" - web3-core-helpers "1.9.0" - web3-providers-http "1.9.0" - web3-providers-ipc "1.9.0" - web3-providers-ws "1.9.0" + web3-core-helpers "1.10.4" + web3-providers-http "1.10.4" + web3-providers-ipc "1.10.4" + web3-providers-ws "1.10.4" -web3-core-subscriptions@1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.9.0.tgz#dc67b478875dab1875844df3307a986dd7d468dd" - integrity sha512-MaIo29yz7hTV8X8bioclPDbHFOVuHmnbMv+D3PDH12ceJFJAXGyW8GL5KU1DYyWIj4TD1HM4WknyVA/YWBiiLA== +web3-core-subscriptions@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.10.4.tgz#2f4dcb404237e92802a563265d11a33934dc38e6" + integrity sha512-o0lSQo/N/f7/L76C0HV63+S54loXiE9fUPfHFcTtpJRQNDBVsSDdWRdePbWwR206XlsBqD5VHApck1//jEafTw== dependencies: eventemitter3 "4.0.4" - web3-core-helpers "1.9.0" + web3-core-helpers "1.10.4" web3-core@^1.8.1: - version "1.9.0" - resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.9.0.tgz#9cfafb2f8c01931429108af75205610406a5a1ab" - integrity sha512-DZ+TPmq/ZLlx4LSVzFgrHCP/QFpKDbGWO4HoquZSdu24cjk5SZ+FEU1SZB2OaK3/bgBh+25mRbmv8y56ysUu1w== + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.10.4.tgz#639de68b8b9871d2dc8892e0dd4e380cb1361a98" + integrity sha512-B6elffYm81MYZDTrat7aEhnhdtVE3lDBUZft16Z8awYMZYJDbnykEbJVS+l3mnA7AQTnSDr/1MjWofGDLBJPww== dependencies: "@types/bn.js" "^5.1.1" "@types/node" "^12.12.6" bignumber.js "^9.0.0" - web3-core-helpers "1.9.0" - web3-core-method "1.9.0" - web3-core-requestmanager "1.9.0" - web3-utils "1.9.0" + web3-core-helpers "1.10.4" + web3-core-method "1.10.4" + web3-core-requestmanager "1.10.4" + web3-utils "1.10.4" -web3-eth-iban@1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.9.0.tgz#a8f838e42c20d49ff58aaa9f67ece47a968e40b1" - integrity sha512-jPAm77PuEs1kE/UrrBFJdPD2PN42pwfXA0gFuuw35bZezhskYML9W4QCxcqnUtceyEA4FUn7K2qTMuCk+23fog== +web3-eth-iban@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz#bc61b4a1930d19b1df8762c606d669902558e54d" + integrity sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw== dependencies: bn.js "^5.2.1" - web3-utils "1.9.0" + web3-utils "1.10.4" -web3-providers-http@1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.9.0.tgz#93cd3eb42fff974c9f7634ede1a9795d6435c3fe" - integrity sha512-5+dMNDAE0rRFz6SJpfnBqlVi2J5bB/Ivr2SanMt2YUrkxW5t8betZbzVwRkTbwtUvkqgj3xeUQzqpOttiv+IqQ== +web3-providers-http@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.10.4.tgz#ca7aa58aeaf8123500c24ffe0595896319f830e8" + integrity sha512-m2P5Idc8hdiO0l60O6DSCPw0kw64Zgi0pMjbEFRmxKIck2Py57RQMu4bxvkxJwkF06SlGaEQF8rFZBmuX7aagQ== dependencies: - abortcontroller-polyfill "^1.7.3" - cross-fetch "^3.1.4" + abortcontroller-polyfill "^1.7.5" + cross-fetch "^4.0.0" es6-promise "^4.2.8" - web3-core-helpers "1.9.0" + web3-core-helpers "1.10.4" -web3-providers-ipc@1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.9.0.tgz#db486cb0dde9062ac6055478861e3d37535924d2" - integrity sha512-cPXU93Du40HCylvjaa5x62DbnGqH+86HpK/+kMcFIzF6sDUBhKpag2tSbYhGbj7GMpfkmDTUiiMLdWnFV6+uBA== +web3-providers-ipc@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.10.4.tgz#2e03437909e4e7771d646ff05518efae44b783c3" + integrity sha512-YRF/bpQk9z3WwjT+A6FI/GmWRCASgd+gC0si7f9zbBWLXjwzYAKG73bQBaFRAHex1hl4CVcM5WUMaQXf3Opeuw== dependencies: oboe "2.1.5" - web3-core-helpers "1.9.0" + web3-core-helpers "1.10.4" -web3-providers-ws@1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.9.0.tgz#568330766e8abbb6eb43e1153a72fb24398fcb7e" - integrity sha512-JRVsnQZ7j2k1a2yzBNHe39xqk1ijOv01dfIBFw52VeEkSRzvrOcsPIM/ttSyBuJqt70ntMxXY0ekCrqfleKH/w== +web3-providers-ws@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.10.4.tgz#55d0c3ba36c6a79d105f02e20a707eb3978e7f82" + integrity sha512-j3FBMifyuFFmUIPVQR4pj+t5ILhAexAui0opgcpu9R5LxQrLRUZxHSnU+YO25UycSOa/NAX8A+qkqZNpcFAlxA== dependencies: eventemitter3 "4.0.4" - web3-core-helpers "1.9.0" + web3-core-helpers "1.10.4" websocket "^1.0.32" -web3-utils@1.9.0, web3-utils@^1.8.1: - version "1.9.0" - resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.9.0.tgz#7c5775a47586cefb4ad488831be8f6627be9283d" - integrity sha512-p++69rCNNfu2jM9n5+VD/g26l+qkEOQ1m6cfRQCbH8ZRrtquTmrirJMgTmyOoax5a5XRYOuws14aypCOs51pdQ== +web3-utils@1.10.4, web3-utils@^1.3.6, web3-utils@^1.8.1: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.10.4.tgz#0daee7d6841641655d8b3726baf33b08eda1cbec" + integrity sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A== dependencies: + "@ethereumjs/util" "^8.1.0" bn.js "^5.2.1" ethereum-bloom-filters "^1.0.6" - ethereumjs-util "^7.1.0" + ethereum-cryptography "^2.1.2" ethjs-unit "0.1.6" number-to-bn "1.7.0" randombytes "^2.1.0" @@ -5583,13 +7350,13 @@ webidl-conversions@^3.0.0: integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== websocket@^1.0.32: - version "1.0.34" - resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.34.tgz#2bdc2602c08bf2c82253b730655c0ef7dcab3111" - integrity sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ== + version "1.0.35" + resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.35.tgz#374197207d7d4cc4c36cbf8a1bb886ee52a07885" + integrity sha512-/REy6amwPZl44DDzvRCkaI1q1bIiQB0mEFQLUrhz3z2EK91cp3n72rAjUlrTP0zV22HJIUOVHQGPxhFRjxjt+Q== dependencies: bufferutil "^4.0.1" debug "^2.2.0" - es5-ext "^0.10.50" + es5-ext "^0.10.63" typedarray-to-buffer "^3.1.5" utf-8-validate "^5.0.2" yaeti "^0.0.6" @@ -5602,17 +7369,18 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" -which-typed-array@^1.1.2: - version "1.1.9" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" - integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== +which-typed-array@^1.1.16, which-typed-array@^1.1.2: + version "1.1.19" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.19.tgz#df03842e870b6b88e117524a4b364b6fc689f956" + integrity sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" - is-typed-array "^1.1.10" + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + for-each "^0.3.5" + get-proto "^1.0.1" + gopd "^1.2.0" + has-tostringtag "^1.0.2" which@2.0.2, which@^2.0.1: version "2.0.2" @@ -5621,7 +7389,7 @@ which@2.0.2, which@^2.0.1: dependencies: isexe "^2.0.0" -which@^1.1.1, which@^1.2.9: +which@^1.1.1, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== @@ -5635,10 +7403,10 @@ widest-line@^3.1.0: dependencies: string-width "^4.0.0" -word-wrap@^1.2.3, word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== +word-wrap@^1.2.5, word-wrap@~1.2.3: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== wordwrap@^1.0.0: version "1.0.0" @@ -5658,6 +7426,15 @@ workerpool@6.2.0: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b" integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" @@ -5667,38 +7444,45 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - ws@7.4.6: version "7.4.6" resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== +ws@8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== + +ws@8.18.0: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== + ws@^7.4.6: - version "7.5.9" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" - integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== + version "7.5.10" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" + integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== -xml@^1.0.0: +xml@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" integrity sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw== -xmlhttprequest@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" - integrity sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA== - y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" @@ -5709,11 +7493,6 @@ yaeti@^0.0.6: resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" integrity sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug== -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" @@ -5760,4 +7539,9 @@ yn@3.1.1: yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== \ No newline at end of file + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zksync-web3@^0.14.3: + version "0.14.4" + resolved "https://registry.yarnpkg.com/zksync-web3/-/zksync-web3-0.14.4.tgz#0b70a7e1a9d45cc57c0971736079185746d46b1f" + integrity sha512-kYehMD/S6Uhe1g434UnaMN+sBr9nQm23Ywn0EUP5BfQCsbjcr3ORuS68PosZw8xUTu3pac7G6YMSnNHk+fwzvg== From 7e08ec94dd8364984e27828064671cb5e31c846f Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Fri, 25 Jul 2025 19:33:56 +0300 Subject: [PATCH 02/65] fix: working dev --- contracts/test/Comp.sol | 301 +++++++++++++++++++++++++++++++++++++ scenario/SupplyScenario.ts | 1 + scenario/utils/index.ts | 10 +- src/deploy/Network.ts | 4 +- 4 files changed, 313 insertions(+), 3 deletions(-) create mode 100644 contracts/test/Comp.sol diff --git a/contracts/test/Comp.sol b/contracts/test/Comp.sol new file mode 100644 index 000000000..c999b4de0 --- /dev/null +++ b/contracts/test/Comp.sol @@ -0,0 +1,301 @@ +pragma solidity 0.8.15; +pragma experimental ABIEncoderV2; + +contract Comp { + /// @notice EIP-20 token name for this token + string public constant name = "Compound"; + + /// @notice EIP-20 token symbol for this token + string public constant symbol = "COMP"; + + /// @notice EIP-20 token decimals for this token + uint8 public constant decimals = 18; + + /// @notice Total number of tokens in circulation + uint public constant totalSupply = 10000000e18; // 10 million Comp + + /// @notice Allowance amounts on behalf of others + mapping (address => mapping (address => uint96)) internal allowances; + + /// @notice Official record of token balances for each account + mapping (address => uint96) internal balances; + + /// @notice A record of each accounts delegate + mapping (address => address) public delegates; + + /// @notice A checkpoint for marking number of votes from a given block + struct Checkpoint { + uint32 fromBlock; + uint96 votes; + } + + /// @notice A record of votes checkpoints for each account, by index + mapping (address => mapping (uint32 => Checkpoint)) public checkpoints; + + /// @notice The number of checkpoints for each account + mapping (address => uint32) public numCheckpoints; + + /// @notice The EIP-712 typehash for the contract's domain + bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); + + /// @notice The EIP-712 typehash for the delegation struct used by the contract + bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); + + /// @notice A record of states for signing / validating signatures + mapping (address => uint) public nonces; + + /// @notice An event thats emitted when an account changes its delegate + event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); + + /// @notice An event thats emitted when a delegate account's vote balance changes + event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance); + + /// @notice The standard EIP-20 transfer event + event Transfer(address indexed from, address indexed to, uint256 amount); + + /// @notice The standard EIP-20 approval event + event Approval(address indexed owner, address indexed spender, uint256 amount); + + /** + * @notice Construct a new Comp token + * @param account The initial account to grant all the tokens + */ + constructor(address account) { + balances[account] = uint96(totalSupply); + emit Transfer(address(0), account, totalSupply); + } + + /** + * @notice Get the number of tokens `spender` is approved to spend on behalf of `account` + * @param account The address of the account holding the funds + * @param spender The address of the account spending the funds + * @return The number of tokens approved + */ + function allowance(address account, address spender) external view returns (uint) { + return allowances[account][spender]; + } + + /** + * @notice Approve `spender` to transfer up to `amount` from `src` + * @dev This will overwrite the approval amount for `spender` + * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) + * @param spender The address of the account which may transfer tokens + * @param rawAmount The number of tokens that are approved (2^256-1 means infinite) + * @return Whether or not the approval succeeded + */ + function approve(address spender, uint rawAmount) external returns (bool) { + uint96 amount; + if (rawAmount == type(uint256).max) { + amount = type(uint96).max; + } else { + amount = safe96(rawAmount, "Comp::approve: amount exceeds 96 bits"); + } + + allowances[msg.sender][spender] = amount; + + emit Approval(msg.sender, spender, amount); + return true; + } + + /** + * @notice Get the number of tokens held by the `account` + * @param account The address of the account to get the balance of + * @return The number of tokens held + */ + function balanceOf(address account) external view returns (uint) { + return balances[account]; + } + + /** + * @notice Transfer `amount` tokens from `msg.sender` to `dst` + * @param dst The address of the destination account + * @param rawAmount The number of tokens to transfer + * @return Whether or not the transfer succeeded + */ + function transfer(address dst, uint rawAmount) external returns (bool) { + uint96 amount = safe96(rawAmount, "Comp::transfer: amount exceeds 96 bits"); + _transferTokens(msg.sender, dst, amount); + return true; + } + + /** + * @notice Transfer `amount` tokens from `src` to `dst` + * @param src The address of the source account + * @param dst The address of the destination account + * @param rawAmount The number of tokens to transfer + * @return Whether or not the transfer succeeded + */ + function transferFrom(address src, address dst, uint rawAmount) external returns (bool) { + address spender = msg.sender; + uint96 spenderAllowance = allowances[src][spender]; + uint96 amount = safe96(rawAmount, "Comp::approve: amount exceeds 96 bits"); + + if (spender != src && spenderAllowance != type(uint96).max) { + uint96 newAllowance = sub96(spenderAllowance, amount, "Comp::transferFrom: transfer amount exceeds spender allowance"); + allowances[src][spender] = newAllowance; + + emit Approval(src, spender, newAllowance); + } + + _transferTokens(src, dst, amount); + return true; + } + + /** + * @notice Delegate votes from `msg.sender` to `delegatee` + * @param delegatee The address to delegate votes to + */ + function delegate(address delegatee) public { + return _delegate(msg.sender, delegatee); + } + + /** + * @notice Delegates votes from signatory to `delegatee` + * @param delegatee The address to delegate votes to + * @param nonce The contract state required to match the signature + * @param expiry The time at which to expire the signature + * @param v The recovery byte of the signature + * @param r Half of the ECDSA signature pair + * @param s Half of the ECDSA signature pair + */ + function delegateBySig(address delegatee, uint nonce, uint expiry, uint8 v, bytes32 r, bytes32 s) public { + bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this))); + bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry)); + bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); + address signatory = ecrecover(digest, v, r, s); + require(signatory != address(0), "Comp::delegateBySig: invalid signature"); + require(nonce == nonces[signatory]++, "Comp::delegateBySig: invalid nonce"); + require(block.timestamp <= expiry, "Comp::delegateBySig: signature expired"); + return _delegate(signatory, delegatee); + } + + /** + * @notice Gets the current votes balance for `account` + * @param account The address to get votes balance + * @return The number of current votes for `account` + */ + function getCurrentVotes(address account) external view returns (uint96) { + uint32 nCheckpoints = numCheckpoints[account]; + return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0; + } + + /** + * @notice Determine the prior number of votes for an account as of a block number + * @dev Block number must be a finalized block or else this function will revert to prevent misinformation. + * @param account The address of the account to check + * @param blockNumber The block number to get the vote balance at + * @return The number of votes the account had as of the given block + */ + function getPriorVotes(address account, uint blockNumber) public view returns (uint96) { + require(blockNumber < block.number, "Comp::getPriorVotes: not yet determined"); + + uint32 nCheckpoints = numCheckpoints[account]; + if (nCheckpoints == 0) { + return 0; + } + + // First check most recent balance + if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { + return checkpoints[account][nCheckpoints - 1].votes; + } + + // Next check implicit zero balance + if (checkpoints[account][0].fromBlock > blockNumber) { + return 0; + } + + uint32 lower = 0; + uint32 upper = nCheckpoints - 1; + while (upper > lower) { + uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow + Checkpoint memory cp = checkpoints[account][center]; + if (cp.fromBlock == blockNumber) { + return cp.votes; + } else if (cp.fromBlock < blockNumber) { + lower = center; + } else { + upper = center - 1; + } + } + return checkpoints[account][lower].votes; + } + + function _delegate(address delegator, address delegatee) internal { + address currentDelegate = delegates[delegator]; + uint96 delegatorBalance = balances[delegator]; + delegates[delegator] = delegatee; + + emit DelegateChanged(delegator, currentDelegate, delegatee); + + _moveDelegates(currentDelegate, delegatee, delegatorBalance); + } + + function _transferTokens(address src, address dst, uint96 amount) internal { + require(src != address(0), "Comp::_transferTokens: cannot transfer from the zero address"); + require(dst != address(0), "Comp::_transferTokens: cannot transfer to the zero address"); + + balances[src] = sub96(balances[src], amount, "Comp::_transferTokens: transfer amount exceeds balance"); + balances[dst] = add96(balances[dst], amount, "Comp::_transferTokens: transfer amount overflows"); + emit Transfer(src, dst, amount); + + _moveDelegates(delegates[src], delegates[dst], amount); + } + + function _moveDelegates(address srcRep, address dstRep, uint96 amount) internal { + if (srcRep != dstRep && amount > 0) { + if (srcRep != address(0)) { + uint32 srcRepNum = numCheckpoints[srcRep]; + uint96 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0; + uint96 srcRepNew = sub96(srcRepOld, amount, "Comp::_moveVotes: vote amount underflows"); + _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew); + } + + if (dstRep != address(0)) { + uint32 dstRepNum = numCheckpoints[dstRep]; + uint96 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0; + uint96 dstRepNew = add96(dstRepOld, amount, "Comp::_moveVotes: vote amount overflows"); + _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew); + } + } + } + + function _writeCheckpoint(address delegatee, uint32 nCheckpoints, uint96 oldVotes, uint96 newVotes) internal { + uint32 blockNumber = safe32(block.number, "Comp::_writeCheckpoint: block number exceeds 32 bits"); + + if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) { + checkpoints[delegatee][nCheckpoints - 1].votes = newVotes; + } else { + checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes); + numCheckpoints[delegatee] = nCheckpoints + 1; + } + + emit DelegateVotesChanged(delegatee, oldVotes, newVotes); + } + + function safe32(uint n, string memory errorMessage) internal pure returns (uint32) { + require(n < 2**32, errorMessage); + return uint32(n); + } + + function safe96(uint n, string memory errorMessage) internal pure returns (uint96) { + require(n < 2**96, errorMessage); + return uint96(n); + } + + function add96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) { + uint96 c = a + b; + require(c >= a, errorMessage); + return c; + } + + function sub96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) { + require(b <= a, errorMessage); + return a - b; + } + + function getChainId() internal view returns (uint) { + uint256 chainId; + assembly { chainId := chainid() } + return chainId; + } +} \ No newline at end of file diff --git a/scenario/SupplyScenario.ts b/scenario/SupplyScenario.ts index dac9eae66..fd986bb4d 100644 --- a/scenario/SupplyScenario.ts +++ b/scenario/SupplyScenario.ts @@ -522,6 +522,7 @@ scenario( symbol === 'WPOL' ? /Transaction reverted without a reason string/ : /.^/, symbol === 'sUSDS' ? /SUsds\/insufficient-allowance/ : /.^/, symbol === 'USDC' ? /Transaction reverted without a reason string/ : /.^/, + symbol === 'GOLD' ? /Transaction reverted and Hardhat couldn't infer the reason./ : /.^/, ] ); } diff --git a/scenario/utils/index.ts b/scenario/utils/index.ts index 2d5e8e861..1a7c7b5ec 100644 --- a/scenario/utils/index.ts +++ b/scenario/utils/index.ts @@ -1034,7 +1034,15 @@ export async function executeOpenProposal( // Execute proposal (maybe, w/ gas limit so we see if exec reverts, not a gas estimation error) if ((await governor.state(id)) == ProposalState.Queued) { const block = await dm.hre.ethers.provider.getBlock('latest'); - const eta = await governor.proposalEta(id); + const eta = await (async () => { + try { + return await governor.proposalEta(id); + } + catch (err) { + const proposal = await governor.proposals(id); + return proposal.eta; + } + })(); await setNextBlockTimestamp( dm, Math.max(block.timestamp, eta.toNumber()) + 1 diff --git a/src/deploy/Network.ts b/src/deploy/Network.ts index e20e4c04a..08bbd7b0e 100644 --- a/src/deploy/Network.ts +++ b/src/deploy/Network.ts @@ -25,9 +25,9 @@ export async function cloneGov( const fauceteer = await deploymentManager.deploy('fauceteer', 'test/Fauceteer.sol', []); const timelock = await deploymentManager.deploy('timelock', 'test/SimpleTimelock.sol', [admin.address]); - const COMP = await deploymentManager.clone('COMP', clone.comp, [admin.address]); + const COMP = await deploymentManager.deploy('COMP', 'test/Comp.sol', [admin.address]); - const governorImpl = await deploymentManager.clone('governor:implementation', clone.governorBravoImpl, [], 'mainnet', true); + const governorImpl = await deploymentManager.clone('governor:implementation', clone.governorBravoImpl, []); const governorProxy = await deploymentManager.clone('governor', clone.governorBravo, [ timelock.address, COMP.address, From 2bb3587f94114bd64a52827c93e182e928afc21a Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Mon, 28 Jul 2025 22:17:51 +0300 Subject: [PATCH 03/65] fix: scenarios --- deployments/base/usds/roots.json | 1 - deployments/mainnet/usds/relations.ts | 8 +++++ deployments/mainnet/usdt/relations.ts | 8 +++++ deployments/mainnet/wsteth/relations.ts | 8 +++++ scenario/BulkerScenario.ts | 48 ++++++++++++++----------- scenario/SupplyScenario.ts | 6 ++-- scenario/TransferScenario.ts | 6 ++-- scenario/WithdrawScenario.ts | 6 ++-- scenario/utils/scenarioHelper.ts | 24 ++++++++++--- src/deploy/index.ts | 5 +++ 10 files changed, 82 insertions(+), 38 deletions(-) diff --git a/deployments/base/usds/roots.json b/deployments/base/usds/roots.json index cc230f036..2b01beb8a 100644 --- a/deployments/base/usds/roots.json +++ b/deployments/base/usds/roots.json @@ -2,7 +2,6 @@ "comet": "0x2c776041CCFe903071AF44aa147368a9c8EEA518", "configurator": "0x45939657d1CA34A8FA39A924B71D28Fe8431e581", "rewards": "0x123964802e6ABabBE1Bc9547D72Ef1B69B00A6b1", - "cometFactory": "0x3D0bb1ccaB520A66e607822fC55BC921738fAFE3", "bridgeReceiver": "0x18281dfC4d00905DA1aaA6731414EABa843c468A", "l2CrossDomainMessenger": "0x4200000000000000000000000000000000000007", "l2StandardBridge": "0x4200000000000000000000000000000000000010", diff --git a/deployments/mainnet/usds/relations.ts b/deployments/mainnet/usds/relations.ts index 7b0cc418d..dcc1d9eb2 100644 --- a/deployments/mainnet/usds/relations.ts +++ b/deployments/mainnet/usds/relations.ts @@ -22,4 +22,12 @@ export default { } } }, + 'UUPSProxy': { + artifact: 'contracts/ERC20.sol:ERC20', + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, }; \ No newline at end of file diff --git a/deployments/mainnet/usdt/relations.ts b/deployments/mainnet/usdt/relations.ts index 3bc07940d..6ed54e744 100644 --- a/deployments/mainnet/usdt/relations.ts +++ b/deployments/mainnet/usdt/relations.ts @@ -36,4 +36,12 @@ export default { } } }, + UUPSProxy: { + artifact: 'contracts/ERC20.sol:ERC20', + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, }; \ No newline at end of file diff --git a/deployments/mainnet/wsteth/relations.ts b/deployments/mainnet/wsteth/relations.ts index 4211ead18..24d4d08e6 100644 --- a/deployments/mainnet/wsteth/relations.ts +++ b/deployments/mainnet/wsteth/relations.ts @@ -30,5 +30,13 @@ export default { } } }, + ERC1967Proxy: { + artifact: 'contracts/ERC20.sol:ERC20', + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, }; diff --git a/scenario/BulkerScenario.ts b/scenario/BulkerScenario.ts index 76f38720a..de108bf0c 100644 --- a/scenario/BulkerScenario.ts +++ b/scenario/BulkerScenario.ts @@ -5,11 +5,10 @@ import { expectBase, isRewardSupported, isBulkerSupported, getExpectedBaseBalanc import { exp } from '../test/helpers'; import { getConfigForScenario } from './utils/scenarioHelper'; -async function hasNativeAsCollateralOrBase(ctx: CometContext): Promise { +async function hasNativeAsCollateral(ctx: CometContext): Promise { const comet = await ctx.getComet(); const bulker = await ctx.getBulker(); const wrappedNativeToken = await bulker.wrappedNativeToken(); - if ((await comet.baseToken()).toLowerCase() === wrappedNativeToken.toLowerCase()) return true; const numAssets = await comet.numAssets(); for (let i = 0; i < numAssets; i++) { const { asset } = await comet.getAssetInfo(i); @@ -19,8 +18,15 @@ async function hasNativeAsCollateralOrBase(ctx: CometContext): Promise } } +async function hasNativeAsBase(ctx: CometContext): Promise { + const comet = await ctx.getComet(); + const bulker = await ctx.getBulker(); + const wrappedNativeToken = await bulker.wrappedNativeToken(); + if ((await comet.baseToken()).toLowerCase() === wrappedNativeToken.toLowerCase()) return true; +} + scenario( - 'Comet#bulker > (non-WETH base) all non-reward actions in one txn for single asset', + 'Comet#bulker > WRON base all non-reward actions in one txn for single asset', { filter: async (ctx) => await isBulkerSupported(ctx) && matchesDeployment(ctx, [{ network: 'ronin', deployment: 'wron'}]), supplyCaps: async (ctx) => ( @@ -51,8 +57,8 @@ scenario( const toSupplyCollateral = BigInt(getConfigForScenario(context).bulkerAsset) * collateralScale; const toBorrowBase = BigInt(getConfigForScenario(context).bulkerBorrowBase) * baseScale; const toTransferBase = BigInt(getConfigForScenario(context).bulkerBorrowAsset) * baseScale; - const toSupplyEth = exp(0.01, 18); - const toWithdrawEth = exp(0.005, 18); + const toSupplyWron = exp(0.01, 18); + const toWithdrawWron = exp(0.005, 18); // Approvals await collateralAsset.approve(albert, comet.address); @@ -67,13 +73,13 @@ scenario( // 1. Supplies 3000 units of collateral // 2. Borrows 1000 base // 3. Transfers 500 base to Betty - // 4. Supplies 0.01 ETH - // 5. Withdraws 0.005 ETH + // 4. Supplies 0.01 RON + // 5. Withdraws 0.005 RON const supplyAssetCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'address', 'uint'], [comet.address, albert.address, collateralAsset.address, toSupplyCollateral]); const withdrawAssetCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'address', 'uint'], [comet.address, albert.address, baseAsset.address, toBorrowBase]); const transferAssetCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'address', 'uint'], [comet.address, betty.address, baseAsset.address, toTransferBase]); - const supplyEthCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint'], [comet.address, albert.address, toSupplyEth]); - const withdrawEthCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint'], [comet.address, albert.address, toWithdrawEth]); + const supplyEthCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint'], [comet.address, albert.address, toSupplyWron]); + const withdrawEthCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint'], [comet.address, albert.address, toWithdrawWron]); const calldata = [ supplyAssetCalldata, withdrawAssetCalldata, @@ -85,24 +91,24 @@ scenario( await bulker.ACTION_TRANSFER_ASSET(), ]; - if (await hasNativeAsCollateralOrBase(context)) { + if (await hasNativeAsCollateral(context) || await hasNativeAsBase(context)) { calldata.push(supplyEthCalldata); calldata.push(withdrawEthCalldata); actions.push(await bulker.ACTION_SUPPLY_NATIVE_TOKEN()); actions.push(await bulker.ACTION_WITHDRAW_NATIVE_TOKEN()); } - const txn = await albert.invoke({ actions, calldata }, { value: toSupplyEth }); + const txn = await albert.invoke({ actions, calldata }, { value: toSupplyWron }); // Final expectations const baseIndexScale = (await comet.baseIndexScale()).toBigInt(); const baseSupplyIndex = (await comet.totalsBasic()).baseSupplyIndex.toBigInt(); const baseTransferred = getExpectedBaseBalance(toTransferBase, baseIndexScale, baseSupplyIndex); expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(toSupplyCollateral); - if (await hasNativeAsCollateralOrBase(context)) expect(await comet.collateralBalanceOf(albert.address, wrappedNativeToken)).to.be.equal(toSupplyEth - toWithdrawEth); + if (await hasNativeAsCollateral(context)) expect(await comet.collateralBalanceOf(albert.address, wrappedNativeToken)).to.be.equal(toSupplyWron - toWithdrawWron); expect(await baseAsset.balanceOf(albert.address)).to.be.equal(toBorrowBase); expectBase((await comet.balanceOf(betty.address)).toBigInt(), baseTransferred); - expectBase((await comet.borrowBalanceOf(albert.address)).toBigInt(), toBorrowBase + toTransferBase); + expectBase((await comet.borrowBalanceOf(albert.address)).toBigInt(), toBorrowBase + toTransferBase - toWithdrawWron); return txn; // return txn to measure gas } @@ -179,7 +185,7 @@ scenario( await bulker.ACTION_TRANSFER_ASSET() ]; - if (await hasNativeAsCollateralOrBase(context)) { + if (await hasNativeAsCollateral(context) || await hasNativeAsBase(context)) { calldata.push(supplyEthCalldata); calldata.push(withdrawEthCalldata); actions.push(await bulker.ACTION_SUPPLY_NATIVE_TOKEN()); @@ -193,7 +199,7 @@ scenario( const baseSupplyIndex = (await comet.totalsBasic()).baseSupplyIndex.toBigInt(); const baseTransferred = getExpectedBaseBalance(toTransferBase, baseIndexScale, baseSupplyIndex); expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(toSupplyCollateral); - if (await hasNativeAsCollateralOrBase(context)) expect(await comet.collateralBalanceOf(albert.address, wrappedNativeToken)).to.be.equal(toSupplyEth - toWithdrawEth); + if (await hasNativeAsCollateral(context)) expect(await comet.collateralBalanceOf(albert.address, wrappedNativeToken)).to.be.equal(toSupplyEth - toWithdrawEth); expect(await baseAsset.balanceOf(albert.address)).to.be.equal(toBorrowBase); expectBase((await comet.balanceOf(betty.address)).toBigInt(), baseTransferred); expectBase((await comet.borrowBalanceOf(albert.address)).toBigInt(), toBorrowBase + toTransferBase); @@ -369,7 +375,7 @@ scenario( await bulker.ACTION_CLAIM_REWARD(), ]; - if (await hasNativeAsCollateralOrBase(context)) { + if (await hasNativeAsCollateral(context) || await hasNativeAsBase(context)) { calldata.push(supplyEthCalldata); calldata.push(withdrawEthCalldata); actions.push(await bulker.ACTION_SUPPLY_NATIVE_TOKEN()); @@ -384,7 +390,7 @@ scenario( const baseTransferred = getExpectedBaseBalance(toTransferBase, baseIndexScale, baseSupplyIndex); expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(toSupplyCollateral); expect(await baseAsset.balanceOf(albert.address)).to.be.equal(toBorrowBase); - if (await hasNativeAsCollateralOrBase(context)) expect(await comet.collateralBalanceOf(albert.address, wrappedNativeToken)).to.be.equal(toSupplyEth - toWithdrawEth); + if (await hasNativeAsCollateral(context)) expect(await comet.collateralBalanceOf(albert.address, wrappedNativeToken)).to.be.equal(toSupplyEth - toWithdrawEth); expect(await albert.getErc20Balance(rewardTokenAddress)).to.be.equal(expectedFinalRewardBalance); expectBase((await comet.balanceOf(betty.address)).toBigInt(), baseTransferred); expectBase((await comet.borrowBalanceOf(albert.address)).toBigInt(), toBorrowBase + toTransferBase); @@ -481,7 +487,7 @@ scenario( await bulker.ACTION_CLAIM_REWARD(), ]; - if (await hasNativeAsCollateralOrBase(context)) { + if (await hasNativeAsCollateral(context) || await hasNativeAsBase(context)) { calldata.push(supplyEthCalldata); calldata.push(withdrawEthCalldata); actions.push(await bulker.ACTION_SUPPLY_NATIVE_TOKEN()); @@ -496,7 +502,7 @@ scenario( const baseTransferred = getExpectedBaseBalance(toTransferBase, baseIndexScale, baseSupplyIndex); expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(toSupplyCollateral); expect(await baseAsset.balanceOf(albert.address)).to.be.equal(toBorrowBase); - if (await hasNativeAsCollateralOrBase(context)) expect(await comet.collateralBalanceOf(albert.address, wrappedNativeToken)).to.be.equal(toSupplyEth - toWithdrawEth); + if (await hasNativeAsCollateral(context)) expect(await comet.collateralBalanceOf(albert.address, wrappedNativeToken)).to.be.equal(toSupplyEth - toWithdrawEth); expect(await albert.getErc20Balance(rewardTokenAddress)).to.be.equal(expectedFinalRewardBalance); expectBase((await comet.balanceOf(betty.address)).toBigInt(), baseTransferred); expectBase((await comet.borrowBalanceOf(albert.address)).toBigInt(), toBorrowBase + toTransferBase); @@ -593,7 +599,7 @@ scenario( await bulker.ACTION_CLAIM_REWARD(), ]; - if (await hasNativeAsCollateralOrBase(context)) { + if (await hasNativeAsCollateral(context) || await hasNativeAsBase(context)) { calldata.push(supplyEthCalldata); calldata.push(withdrawEthCalldata); actions.push(await bulker.ACTION_SUPPLY_NATIVE_TOKEN()); @@ -608,7 +614,7 @@ scenario( const baseTransferred = getExpectedBaseBalance(toTransferBase, baseIndexScale, baseSupplyIndex); expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(toSupplyCollateral); expect(await baseAsset.balanceOf(albert.address)).to.be.equal(toBorrowBase); - if (await hasNativeAsCollateralOrBase(context)) expect(await comet.collateralBalanceOf(albert.address, wrappedNativeToken)).to.be.equal(toSupplyEth - toWithdrawEth); + if (await hasNativeAsCollateral(context)) expect(await comet.collateralBalanceOf(albert.address, wrappedNativeToken)).to.be.equal(toSupplyEth - toWithdrawEth); expect(await albert.getErc20Balance(rewardTokenAddress)).to.be.equal(expectedFinalRewardBalance); expectBase((await comet.balanceOf(betty.address)).toBigInt(), baseTransferred); expectBase((await comet.borrowBalanceOf(albert.address)).toBigInt(), toBorrowBase + toTransferBase); diff --git a/scenario/SupplyScenario.ts b/scenario/SupplyScenario.ts index fd986bb4d..51dffa286 100644 --- a/scenario/SupplyScenario.ts +++ b/scenario/SupplyScenario.ts @@ -77,14 +77,13 @@ async function testSupplyFromCollateral(context: CometContext, assetNum: number) } for (let i = 0; i < MAX_ASSETS; i++) { - const amountToSupply = 100; // in units of asset, not wei scenario( `Comet#supply > collateral asset ${i}`, { // XXX Unfortunately, the filtering step happens before solutions are run, so this will filter out // hypothetical assets added during the migration/proposal constraint because those assets don't exist // yet - filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, amountToSupply), + filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, getConfigForScenario(ctx).supplyCollateral), tokenBalances: async (ctx) => ( { albert: { [`$asset${i}`]: getConfigForScenario(ctx).supplyCollateral } @@ -98,11 +97,10 @@ for (let i = 0; i < MAX_ASSETS; i++) { } for (let i = 0; i < MAX_ASSETS; i++) { - const amountToSupply = 100; // in units of asset, not wei scenario( `Comet#supplyFrom > collateral asset ${i}`, { - filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, amountToSupply), + filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, getConfigForScenario(ctx).supplyCollateral), tokenBalances: async (ctx) => ( { albert: { [`$asset${i}`]: getConfigForScenario(ctx).supplyCollateral } diff --git a/scenario/TransferScenario.ts b/scenario/TransferScenario.ts index 028ee93ad..9c4cfc390 100644 --- a/scenario/TransferScenario.ts +++ b/scenario/TransferScenario.ts @@ -39,11 +39,10 @@ async function testTransferFromCollateral(context: CometContext, assetNum: numbe } for (let i = 0; i < MAX_ASSETS; i++) { - const amountToTransfer = 100; // in units of asset, not wei scenario( `Comet#transfer > collateral asset ${i}, enough balance`, { - filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, amountToTransfer), + filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, getConfigForScenario(ctx).transferCollateral), cometBalances: async (ctx) => ( { albert: { [`$asset${i}`]: getConfigForScenario(ctx).transferCollateral } @@ -57,11 +56,10 @@ for (let i = 0; i < MAX_ASSETS; i++) { } for (let i = 0; i < MAX_ASSETS; i++) { - const amountToTransfer = 100; // in units of asset, not wei scenario( `Comet#transferFrom > collateral asset ${i}, enough balance`, { - filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, amountToTransfer), + filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, getConfigForScenario(ctx).transferCollateral), cometBalances: async (ctx) => ( { albert: { [`$asset${i}`]: getConfigForScenario(ctx).transferCollateral } diff --git a/scenario/WithdrawScenario.ts b/scenario/WithdrawScenario.ts index e6ee2f8d5..dba5ef6d6 100644 --- a/scenario/WithdrawScenario.ts +++ b/scenario/WithdrawScenario.ts @@ -45,11 +45,10 @@ async function testWithdrawFromCollateral(context: CometContext, assetNum: numbe } for (let i = 0; i < MAX_ASSETS; i++) { - const amountToWithdraw = 100; // in units of asset, not wei scenario( `Comet#withdraw > collateral asset ${i}`, { - filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, amountToWithdraw), + filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, getConfigForScenario(ctx).withdrawCollateral), cometBalances: async (ctx) => ( { albert: { [`$asset${i}`]: getConfigForScenario(ctx).withdrawCollateral } @@ -63,11 +62,10 @@ for (let i = 0; i < MAX_ASSETS; i++) { } for (let i = 0; i < MAX_ASSETS; i++) { - const amountToWithdraw = 100; // in units of asset, not wei scenario( `Comet#withdrawFrom > collateral asset ${i}`, { - filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, amountToWithdraw), + filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, getConfigForScenario(ctx).withdrawCollateral), cometBalances: async (ctx) => ( { albert: { [`$asset${i}`]: getConfigForScenario(ctx).withdrawCollateral } diff --git a/scenario/utils/scenarioHelper.ts b/scenario/utils/scenarioHelper.ts index cc5d9fee4..3e26d3e7b 100644 --- a/scenario/utils/scenarioHelper.ts +++ b/scenario/utils/scenarioHelper.ts @@ -44,8 +44,8 @@ export function getConfigForScenario(ctx: CometContext) { config.liquidationBase = 1000; config.liquidationBase1 = 500; config.liquidationAsset = 100; - config.rewardsAsset = 10000; - config.rewardsBase = 100; + config.rewardsAsset = 100; + config.rewardsBase = 10; config.transferBase = 100; config.transferAsset = 500; config.transferAsset1 = 500; @@ -78,6 +78,14 @@ export function getConfigForScenario(ctx: CometContext) { config.liquidationAsset1 = 99; } + if (ctx.world.base.network === 'base' && ctx.world.base.deployment === 'weth') { + config.liquidationBase = 1000; + } + + if (ctx.world.base.network === 'optimism' && ctx.world.base.deployment === 'weth') { + config.liquidationBase = 1000; + } + if (ctx.world.base.network === 'arbitrum' && ctx.world.base.deployment === 'usdc') { config.withdrawAsset = 3500; } @@ -98,6 +106,10 @@ export function getConfigForScenario(ctx: CometContext) { config.liquidationAsset = 10000; } + if (ctx.world.base.network === 'arbitrum' && ctx.world.base.deployment === 'weth') { + config.liquidationBase = 1000; + } + if (ctx.world.base.network === 'ronin' && ctx.world.base.deployment === 'weth') { config.transferBase = 10; config.transferAsset = 200000; @@ -131,8 +143,8 @@ export function getConfigForScenario(ctx: CometContext) { } if (ctx.world.base.network === 'scroll' && ctx.world.base.deployment === 'usdc') { - config.bulkerAsset = 500; - config.bulkerAsset1 = 500; + config.bulkerAsset = 200; + config.bulkerAsset1 = 200; } if (ctx.world.base.network === 'sepolia' && ctx.world.base.deployment === 'usdc') { @@ -172,5 +184,9 @@ export function getConfigForScenario(ctx: CometContext) { config.rewardsBase = 100; } + if (ctx.world.base.network === 'fuji' && ctx.world.base.deployment === 'usdc') { + config.liquidationAsset = 100; + } + return config; } \ No newline at end of file diff --git a/src/deploy/index.ts b/src/deploy/index.ts index cf185678a..f33fe36a4 100644 --- a/src/deploy/index.ts +++ b/src/deploy/index.ts @@ -110,6 +110,9 @@ export const WHALES = { '0x3154Cf16ccdb4C6d922629664174b904d80F2C35', // cbETH whale '0x5f556Cc5C294D7D3EfFaFFeb0B1195256a7A19D7', // EIGEN whale '0xdCa0A2341ed5438E06B9982243808A76B9ADD6d0', // woETH whale + '0x34C0bD5877A5Ee7099D0f5688D65F4bB9158BDE2', // sFRAX whale + '0x9152e9C04e8fE8373EDaa8f5841E25d4015658B7', // pumpBTC whale + '0x65906988ADEe75306021C417a1A3458040239602', // LBTC whale ], polygon: [ '0xF977814e90dA44bFA03b6295A0616a897441aceC', // USDT whale @@ -139,6 +142,7 @@ export const WHALES = { '0xd93f76944e870900779c09ddf1c46275f9d8bf9b', // COMP whale '0xe68ee8a12c611fd043fb05d65e1548dc1383f2b9', // native USDC whale '0x56CC5A9c0788e674f17F7555dC8D3e2F1C0313C0', // wUSDM whale + '0x8437d7C167dFB82ED4Cb79CD44B7a32A1dd95c77', // weETH whale ], base: [ '0x6D3c5a4a7aC4B1428368310E4EC3bB1350d01455', // USDbC whale @@ -158,6 +162,7 @@ export const WHALES = { '0x8af3827a41c26c7f32c81e93bb66e837e0210d5c', // USDC whale '0xc45A479877e1e9Dfe9FcD4056c699575a1045dAA', // wstETH whale '0x6e57181D6b4b7c138a6F956AD16DAF4f27FC5E04', // COMP whale + '0xE36A30D249f7761327fd973001A32010b521b6Fd', // ezETH whale ], mantle: [ '0x588846213A30fd36244e0ae0eBB2374516dA836C', // USDe whale From 9f5564c89d5ddf947e6b05a4abeb0d452d131d90 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Tue, 29 Jul 2025 00:40:31 +0300 Subject: [PATCH 04/65] fix --- deployments/base/usds/deploy.ts | 2 ++ scenario/LiquidationScenario.ts | 35 +++++++++++++++++++------------- scenario/utils/scenarioHelper.ts | 2 ++ 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/deployments/base/usds/deploy.ts b/deployments/base/usds/deploy.ts index 23c2f7809..f43db73ac 100644 --- a/deployments/base/usds/deploy.ts +++ b/deployments/base/usds/deploy.ts @@ -53,6 +53,7 @@ async function deployContracts( // Import shared contracts from cUSDbCv3 // We do not import cometFactory, because we will deploy the new one with 24 collaterals + const cometFactory = await deploymentManager.fromDep('cometFactory', 'base', 'usdbc'); const _cometAdmin = await deploymentManager.fromDep('cometAdmin', 'base', 'usdbc'); const _configurator = await deploymentManager.fromDep('configurator', 'base', 'usdbc'); const _rewards = await deploymentManager.fromDep('rewards', 'base', 'usdbc'); @@ -69,6 +70,7 @@ async function deployContracts( return { ...deployed, + cometFactory, bridgeReceiver, l2CrossDomainMessenger, // TODO: don't have to part of roots. can be pulled via relations l2StandardBridge, diff --git a/scenario/LiquidationScenario.ts b/scenario/LiquidationScenario.ts index 0bce55b74..e13612569 100644 --- a/scenario/LiquidationScenario.ts +++ b/scenario/LiquidationScenario.ts @@ -23,13 +23,16 @@ scenario( const baseToken = await comet.baseToken(); const baseScale = await comet.baseScale(); - await world.increaseTime( - await timeUntilUnderwater({ - comet, - actor: albert, - fudgeFactor: 6000n * 6000n // 1 hour past when position is underwater - }) - ); + const timeBeforeLiquidation = await timeUntilUnderwater({ + comet, + actor: albert, + fudgeFactor: 6000n * 6000n // 1 hour past when position is underwater + }); + + while(!(await comet.isLiquidatable(albert.address))) { + await comet.accrueAccount(albert.address); + await world.increaseTime(timeBeforeLiquidation); + } await betty.withdrawAsset({ asset: baseToken, amount: BigInt(getConfigForScenario(context).liquidationBase) / 100n * baseScale.toBigInt() }); // force accrue @@ -165,13 +168,17 @@ scenario( async ({ comet, actors }, context, world) => { const { albert, betty } = actors; - await world.increaseTime( - await timeUntilUnderwater({ - comet, - actor: albert, - fudgeFactor: 60n * 10n // 10 minutes past when position is underwater - }) - ); + + const timeBeforeLiquidation = await timeUntilUnderwater({ + comet, + actor: albert, + fudgeFactor: 6000n * 6000n // 1 hour past when position is underwater + }); + + while(!(await comet.isLiquidatable(albert.address))) { + await comet.accrueAccount(albert.address); + await world.increaseTime(timeBeforeLiquidation); + } const lp0 = await comet.liquidatorPoints(betty.address); diff --git a/scenario/utils/scenarioHelper.ts b/scenario/utils/scenarioHelper.ts index 3e26d3e7b..9ece2b402 100644 --- a/scenario/utils/scenarioHelper.ts +++ b/scenario/utils/scenarioHelper.ts @@ -15,6 +15,7 @@ const config = { liquidationAsset: 200, liquidationAsset1: 1000, liquidationDenominator: 90, + liquidationDenominator1: 100, liquidationNumerator: 90, rewardsAsset: 10000, rewardsBase: 1000, @@ -182,6 +183,7 @@ export function getConfigForScenario(ctx: CometContext) { config.liquidationBase1 = 350; config.liquidationAsset = 100; config.rewardsBase = 100; + config.rewardsAsset = 1000; } if (ctx.world.base.network === 'fuji' && ctx.world.base.deployment === 'usdc') { From 88fe803ee4f55bbae0c5f7f4153a844059280318 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Tue, 29 Jul 2025 01:03:57 +0300 Subject: [PATCH 05/65] fix --- plugins/deployment_manager/Import.ts | 2 +- scenario/SupplyScenario.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/deployment_manager/Import.ts b/plugins/deployment_manager/Import.ts index bdc14c1f0..2431acc89 100644 --- a/plugins/deployment_manager/Import.ts +++ b/plugins/deployment_manager/Import.ts @@ -4,7 +4,7 @@ import { getBuildFile, storeBuildFile } from './ContractMap'; import { Cache } from './Cache'; import { loadContract } from '../import/import'; -const DEFAULT_RETRIES = 5; +const DEFAULT_RETRIES = 7; const DEFAULT_RETRY_DELAY = 10_000; /** diff --git a/scenario/SupplyScenario.ts b/scenario/SupplyScenario.ts index 51dffa286..80da7b978 100644 --- a/scenario/SupplyScenario.ts +++ b/scenario/SupplyScenario.ts @@ -257,7 +257,7 @@ scenario( const utilization = await comet.getUtilization(); const borrowRate = (await comet.getBorrowRate(utilization)).toBigInt(); - expectApproximately(await albert.getCometBaseBalance(), -1000n * scale, getInterest(1000n * scale, borrowRate, 1n) + 1n); + expectApproximately(await albert.getCometBaseBalance(), -1000n * scale, getInterest(1000n * scale, borrowRate, 1n) + 2n); // Albert repays 1000 units of base borrow await baseAsset.approve(albert, comet.address); From 8b5ee7694d6e25d88f2a3f57f83ac9a326b00bb2 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Tue, 29 Jul 2025 01:27:22 +0300 Subject: [PATCH 06/65] Update index.ts --- src/deploy/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/deploy/index.ts b/src/deploy/index.ts index f33fe36a4..8d8fb9efa 100644 --- a/src/deploy/index.ts +++ b/src/deploy/index.ts @@ -143,6 +143,7 @@ export const WHALES = { '0xe68ee8a12c611fd043fb05d65e1548dc1383f2b9', // native USDC whale '0x56CC5A9c0788e674f17F7555dC8D3e2F1C0313C0', // wUSDM whale '0x8437d7C167dFB82ED4Cb79CD44B7a32A1dd95c77', // weETH whale + '0x6b030Ff3FB9956B1B69f475B77aE0d3Cf2CC5aFa', // rsETH whale ], base: [ '0x6D3c5a4a7aC4B1428368310E4EC3bB1350d01455', // USDbC whale From 700a4c6c8d398d6844d0605ccd5bb6f7351d1e32 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Tue, 29 Jul 2025 13:06:33 +0300 Subject: [PATCH 07/65] Update DeploymentManager.ts --- plugins/deployment_manager/DeploymentManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/deployment_manager/DeploymentManager.ts b/plugins/deployment_manager/DeploymentManager.ts index afe2cbd8b..b3f099c31 100644 --- a/plugins/deployment_manager/DeploymentManager.ts +++ b/plugins/deployment_manager/DeploymentManager.ts @@ -204,7 +204,7 @@ export class DeploymentManager { [].concat(addresses).map(async (address) => { let buildFile; if (artifact !== undefined) { - buildFile = await readContract(this.cache, this.hre, artifact, network, address, !this.cache); + buildFile = await readContract(this.cache, this.hre, artifact, network, address, !this.cache || (artifact.length > 0)); } else { buildFile = await this.import(address, network); } From 4cbf863898d7394eb43339d86955bf41c787f490 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Thu, 14 Aug 2025 14:27:16 +0300 Subject: [PATCH 08/65] fix: unit tests --- scripts/liquidation_bot/liquidateUnderwaterBorrowers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/liquidation_bot/liquidateUnderwaterBorrowers.ts b/scripts/liquidation_bot/liquidateUnderwaterBorrowers.ts index 7eb638bbc..e0b2c3cc3 100644 --- a/scripts/liquidation_bot/liquidateUnderwaterBorrowers.ts +++ b/scripts/liquidation_bot/liquidateUnderwaterBorrowers.ts @@ -472,7 +472,7 @@ async function attemptLiquidationViaOnChainLiquidator( async function getUniqueAddresses(comet: CometInterface): Promise> { const endBlock = await hre.ethers.provider.getBlockNumber(); - const maxBlockRange = 90000; // Adjust based on provider limits + const maxBlockRange = 10000; // Adjust based on provider limits const startBlock = endBlock - maxBlockRange; const withdrawEvents = await comet.queryFilter(comet.filters.Withdraw(), startBlock, endBlock); return new Set(withdrawEvents.map(event => event.args.src)); From 2bc2dbf62269a9131ef128bd8ebb13418de83e73 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Wed, 20 Aug 2025 15:26:18 +0300 Subject: [PATCH 09/65] fix: working linea scenarios and prepare workflow fix --- .github/workflows/prepare-migration.yaml | 26 +++++- .../1737020138_configurate_and_ens.ts | 21 ++++- scenario/utils/relayLineaMessage.ts | 84 ++++++++++++------- 3 files changed, 101 insertions(+), 30 deletions(-) diff --git a/.github/workflows/prepare-migration.yaml b/.github/workflows/prepare-migration.yaml index afe6ae5ac..9f42b2577 100644 --- a/.github/workflows/prepare-migration.yaml +++ b/.github/workflows/prepare-migration.yaml @@ -45,18 +45,40 @@ jobs: MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} + GOV_NETWORK: ${{ vars.GOV_NETWORK }} steps: + - name: Get governance network + run: | + case ${{ github.event.inputs.network }} in + polygon | arbitrum | base | optimism | mantle | scroll | linea | ronin | unichain) + echo "GOV_NETWORK=mainnet" >> $GITHUB_ENV ;; + sepolia) + echo "GOV_NETWORK=sepolia" >> $GITHUB_ENV ;; + *) + echo "No governance network for selected network" ;; + esac - name: Seacrest uses: hayesgm/seacrest@af229b0a00b73cb6fa9940a836a62fa3b918fd77 with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"linea\":\"https://rpc.ankr.com/linea/${ANKR_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/$_TENDERLY_KEY_RONIN\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://mantle-mainnet.infura.io/v3/$INFURA_KEY\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/$INFURA_KEY\",\"sepolia\":\"https://sepolia.infura.io/v3/$INFURA_KEY\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://arbitrum-mainnet.infura.io/v3/$INFURA_KEY\",\"base\":\"https://rpc.ankr.com/base/$ANKR_KEY\",\"scroll\":\"https://rpc.scroll.io\"}')[inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"https://rpc.ankr.com/linea/${ANKR_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/$_TENDERLY_KEY_RONIN\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://rpc.ankr.com/mantle/$ANKR_KEY\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://rpc.ankr.com/eth/$ANKR_KEY\",\"sepolia\":\"https://sepolia.infura.io/v3/$INFURA_KEY\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://rpc.ankr.com/arbitrum/$ANKR_KEY\",\"base\":\"https://rpc.ankr.com/base/$ANKR_KEY\",\"scroll\":\"https://rpc.scroll.io\"}')[inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' + - name: Seacrest (governance network) + uses: hayesgm/seacrest@af229b0a00b73cb6fa9940a836a62fa3b918fd77 + with: + wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} + requested_network: "${{ vars.GOV_NETWORK }}" + ethereum_url: "${{ fromJSON('{\"mainnet\":\"https://rpc.ankr.com/eth/$ANKR_KEY\",\"sepolia\":\"https://sepolia.infura.io/v3/$INFURA_KEY\"}')[vars.GOV_NETWORK] }}" + port: 8685 + if: github.event.inputs.eth_pk == '' && vars.GOV_NETWORK != '' && github.event.inputs.network != vars.GOV_NETWORK + - name: Checkout repository uses: actions/checkout@v4 + with: + submodules: recursive - uses: actions/setup-node@v4 with: @@ -79,6 +101,8 @@ jobs: ETH_PK: "${{ inputs.eth_pk }}" NETWORK_PROVIDER: ${{ fromJSON('["", "http://localhost:8585"]')[github.event.inputs.eth_pk == ''] }} REMOTE_ACCOUNTS: ${{ fromJSON('["", "true"]')[github.event.inputs.eth_pk == ''] }} + GOV_NETWORK_PROVIDER: ${{ github.event.inputs.network != vars.GOV_NETWORK && github.event.inputs.eth_pk == '' && vars.GOV_NETWORK != '' && 'http://localhost:8685' || '' }} + GOV_NETWORK: ${{ github.event.inputs.network != vars.GOV_NETWORK && vars.GOV_NETWORK || '' }} - uses: actions/upload-artifact@v4 # upload test results if: success() || failure() # run this step even if previous step failed diff --git a/deployments/linea/weth/migrations/1737020138_configurate_and_ens.ts b/deployments/linea/weth/migrations/1737020138_configurate_and_ens.ts index dc66fd371..6224b3dfe 100644 --- a/deployments/linea/weth/migrations/1737020138_configurate_and_ens.ts +++ b/deployments/linea/weth/migrations/1737020138_configurate_and_ens.ts @@ -125,7 +125,26 @@ export default migration('1737020138_configurate_and_ens', { } ]; - const description = '# Initialize cWETHv3 on Linea network\n\n## Proposal summary\n\nWOOF! proposes the deployment of Compound III to the Linea network. This proposal takes the governance steps recommended and necessary to initialize a Compound III WETH market on Linea; upon execution, cWETHv3 will be ready for use. Simulations have confirmed the market’s readiness, as much as possible, using the [Comet scenario suite](https://github.com/compound-finance/comet/tree/main/scenario). The new parameters include setting the risk parameters based off of the [recommendations from Gauntlet](https://www.comp.xyz/t/deploy-compound-iii-on-linea/4460/20).\n\nFurther detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/982), [deploy market GitHub action run](https://github.com/woof-software/comet/actions/runs/15211470652) and [forum discussion](https://www.comp.xyz/t/deploy-compound-iii-on-linea/4460).\n\n\n## wrsETH Price Feed\n\n[wrsETH/ETH exchange rate](https://lineascan.build/address/0xEEDF0B095B5dfe75F3881Cb26c19DA209A27463a#readContract) price oracle has a wrong label. The information is confirmed with ChainLink and Kelp teams internally.\n\n\n## Proposal Actions\n\nThe first proposal action sends ether to the Linea Timelock so it can be wrapped and used to seed the reserves, sets the Comet configuration and deploys a new Comet implementation on Linea. This sends the encoded `setFactory`, `setConfiguration`, `deployAndUpgradeTo` calls across the bridge to the governance receiver on Linea.\n\nThe second action updates the ENS TXT record `v3-official-markets` on `v3-additional-grants.compound-community-licenses.eth`, updating the official markets JSON to include the new Linea cWETHv3 market.'; + const description = `# Initialize cWETHv3 on Linea network + +## Proposal summary + +WOOF! proposes the deployment of Compound III to the Linea network. This proposal takes the governance steps recommended and necessary to initialize a Compound III WETH market on Linea; upon execution, cWETHv3 will be ready for use. Simulations have confirmed the market’s readiness, as much as possible, using the [Comet scenario suite](https://github.com/compound-finance/comet/tree/main/scenario). The new parameters include setting the risk parameters based off of the [recommendations from Gauntlet](https://www.comp.xyz/t/deploy-compound-iii-on-linea/4460/20). + +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/982), [deploy market GitHub action run](https://github.com/woof-software/comet/actions/runs/15211470652) and [forum discussion](https://www.comp.xyz/t/deploy-compound-iii-on-linea/4460). + + +## wrsETH Price Feed + +[wrsETH/ETH exchange rate](https://lineascan.build/address/0xEEDF0B095B5dfe75F3881Cb26c19DA209A27463a#readContract) price oracle has a wrong label. The information is confirmed with ChainLink and Kelp teams internally. + + +## Proposal Actions + +The first proposal action sends ether to the Linea Timelock so it can be wrapped and used to seed the reserves, sets the Comet configuration and deploys a new Comet implementation on Linea. This sends the encoded 'setFactory', 'setConfiguration', 'deployAndUpgradeTo' calls across the bridge to the governance receiver on Linea. + +The second action updates the ENS TXT record 'v3-official-markets' on 'v3-additional-grants.compound-community-licenses.eth', updating the official markets JSON to include the new Linea cWETHv3 market.`; + const txn = await govDeploymentManager.retry(async () => trace(await governor.propose(...(await proposal(mainnetActions, description)))) ); diff --git a/scenario/utils/relayLineaMessage.ts b/scenario/utils/relayLineaMessage.ts index b807d2469..e4bac63b0 100644 --- a/scenario/utils/relayLineaMessage.ts +++ b/scenario/utils/relayLineaMessage.ts @@ -57,37 +57,47 @@ export default async function relayLineaMessage( ); // getLogs version: - const realMsgEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: (startingBlockNumber - 50000), - toBlock: 'latest', - address: lineaMessageService.address, - topics: filter.topics! - }); - - const realHashEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: (startingBlockNumber - 50000), - toBlock: 'latest', - address: lineaMessageService.address, - topics: filterRollingHash.topics! - }); - + const fromBlock = Math.max(0, startingBlockNumber - 50000); + const toBlock = await governanceDeploymentManager.hre.ethers.provider.getBlockNumber(); + + const realMsgEvents = await fetchLogsInChunks( + governanceDeploymentManager.hre.ethers.provider, + filter, + fromBlock, + toBlock, + lineaMessageService.address + ); + + const realHashEvents = await fetchLogsInChunks( + governanceDeploymentManager.hre.ethers.provider, + filterRollingHash, + fromBlock, + toBlock, + lineaMessageService.address + ); + messageSentEvents = [...realMsgEvents, ...tenderlyMsgEvents]; rollingHashUpdatedEvents = [...realHashEvents, ...tenderlyHashEvents]; } else { - messageSentEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: (startingBlockNumber - 50000), - toBlock: 'latest', - address: lineaMessageService.address, - topics: filter.topics! - }); - - rollingHashUpdatedEvents = await governanceDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: (startingBlockNumber - 50000), - toBlock: 'latest', - address: lineaMessageService.address, - topics: filterRollingHash.topics! - }); - } + const fromBlock = Math.max(0, startingBlockNumber - 50000); + const toBlock = await governanceDeploymentManager.hre.ethers.provider.getBlockNumber(); + + messageSentEvents = await fetchLogsInChunks( + governanceDeploymentManager.hre.ethers.provider, + filter, + fromBlock, + toBlock, + lineaMessageService.address + ); + + rollingHashUpdatedEvents = await fetchLogsInChunks( + governanceDeploymentManager.hre.ethers.provider, + filterRollingHash, + fromBlock, + toBlock, + lineaMessageService.address + ); + } for (let i = 0; i < messageSentEvents.length; i++) { const messageSentEvent = messageSentEvents[i]; @@ -272,3 +282,21 @@ export default async function relayLineaMessage( } return openBridgedProposals; } + + +// Helper to fetch logs in chunks of 10,000 blocks +async function fetchLogsInChunks(provider: any, filter: any, fromBlock: number, toBlock: number, address: string) { + const chunkSize = 10000; + let logs: Log[] = []; + for (let start = fromBlock; start <= toBlock; start += chunkSize) { + const end = Math.min(start + chunkSize - 1, toBlock); + const chunkLogs = await provider.getLogs({ + fromBlock: start, + toBlock: end, + address, + topics: filter.topics! + }); + logs = logs.concat(chunkLogs); + } + return logs; +} From 688d515e1b9760bab3ae34c20483a1c934ecd2d4 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Tue, 16 Sep 2025 13:12:19 +0300 Subject: [PATCH 10/65] fix: remove linea markets from dev --- deployments/linea/usdt/configuration.json | 55 --- deployments/linea/usdt/deploy.ts | 100 ----- .../1736946439_configurate_and_ens.ts | 340 ----------------- deployments/linea/usdt/relations.ts | 33 -- deployments/linea/usdt/roots.json | 11 - deployments/linea/weth/configuration.json | 68 ---- deployments/linea/weth/deploy.ts | 158 -------- .../1737020138_configurate_and_ens.ts | 344 ------------------ deployments/linea/weth/relations.ts | 33 -- deployments/linea/weth/roots.json | 11 - 10 files changed, 1153 deletions(-) delete mode 100644 deployments/linea/usdt/configuration.json delete mode 100644 deployments/linea/usdt/deploy.ts delete mode 100644 deployments/linea/usdt/migrations/1736946439_configurate_and_ens.ts delete mode 100644 deployments/linea/usdt/relations.ts delete mode 100644 deployments/linea/usdt/roots.json delete mode 100644 deployments/linea/weth/configuration.json delete mode 100644 deployments/linea/weth/deploy.ts delete mode 100644 deployments/linea/weth/migrations/1737020138_configurate_and_ens.ts delete mode 100644 deployments/linea/weth/relations.ts delete mode 100644 deployments/linea/weth/roots.json diff --git a/deployments/linea/usdt/configuration.json b/deployments/linea/usdt/configuration.json deleted file mode 100644 index 8084bd338..000000000 --- a/deployments/linea/usdt/configuration.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "Compound USDT", - "symbol": "cUSDTv3", - "baseToken": "USDT", - "baseTokenAddress": "0xA219439258ca9da29E9Cc4cE5596924745e12B93", - "baseTokenPriceFeed": "0xefCA2bbe0EdD0E22b2e0d2F8248E99F4bEf4A7dB", - "pauseGuardian": "0x5A1e5d7E09cA94506084a26304d53A138145bF52", - "borrowMin": "1e6", - "storeFrontPriceFactor": 0.6, - "targetReserves": "20_000_000e6", - "rates": { - "borrowBase": 0.015, - "borrowSlopeLow": 0.02778, - "borrowKink": 0.9, - "borrowSlopeHigh": 3.6, - "supplyBase": 0, - "supplySlopeLow": 0.036, - "supplyKink": 0.9, - "supplySlopeHigh": 3.196 - }, - "tracking": { - "indexScale": "1e15", - "baseSupplySpeed": "23148148148e0", - "baseBorrowSpeed": "11574074074e0", - "baseMinForRewards": "1000e6" - }, - "assets": { - "WETH": { - "address": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f", - "priceFeed": "0x3c6Cd9Cc7c7a4c2Cf5a82734CD249D7D593354dA", - "decimals": "18", - "borrowCF": 0.83, - "liquidateCF": 0.90, - "liquidationFactor": 0.95, - "supplyCap": "270e18" - }, - "wstETH": { - "address": "0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F", - "decimals": "18", - "borrowCF": 0.82, - "liquidateCF": 0.87, - "liquidationFactor": 0.95, - "supplyCap": "60e18" - }, - "WBTC": { - "address": "0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4", - "priceFeed": "0x7A99092816C8BD5ec8ba229e3a6E6Da1E628E1F9", - "decimals": "8", - "borrowCF": 0.8, - "liquidateCF": 0.85, - "liquidationFactor": 0.9, - "supplyCap": "4e8" - } - } -} \ No newline at end of file diff --git a/deployments/linea/usdt/deploy.ts b/deployments/linea/usdt/deploy.ts deleted file mode 100644 index 15eb512b4..000000000 --- a/deployments/linea/usdt/deploy.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { - Deployed, - DeploymentManager, -} from '../../../plugins/deployment_manager'; -import { DeploySpec, deployComet } from '../../../src/deploy'; - -const WSTETH_TO_STETH_PRICE_FEED = '0x3C8A95F2264bB3b52156c766b738357008d87cB7'; -const ETH_TO_USD_PRICE_FEED = '0x3c6Cd9Cc7c7a4c2Cf5a82734CD249D7D593354dA'; - -const L2MESSAGE_SERVICE_ADDRESS = '0x508Ca82Df566dCD1B0DE8296e70a96332cD644ec'; -const L2STANDARD_BRIDGE_ADDRESS = '0x353012dc4a9A6cF55c941bADC267f82004A8ceB9'; -const L2USDC_BRIDGE_ADDRESS = '0xA2Ee6Fce4ACB62D95448729cDb781e3BEb62504A'; - -export default async function deploy( - deploymentManager: DeploymentManager, - deploySpec: DeploySpec -): Promise { - const deployed = await deployContracts(deploymentManager, deploySpec); - return deployed; -} - -async function deployContracts( - deploymentManager: DeploymentManager, - deploySpec: DeploySpec -): Promise { - // Pull in existing assets - const _USDT = await deploymentManager.existing( - 'USDT', - '0xA219439258ca9da29E9Cc4cE5596924745e12B93', - 'linea' - ); - const _WETH = await deploymentManager.existing( - 'WETH', - '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f', - 'linea' - ); - const _WBTC = await deploymentManager.existing( - 'WBTC', - '0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4', - 'linea' - ); - - const _wstETH = await deploymentManager.existing( - 'wstETH', - '0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F', - 'linea' - ); - - const _wstETHtoUsdPriceFeed = await deploymentManager.deploy( - 'wstETH:priceFeed', - 'pricefeeds/MultiplicativePriceFeed.sol', - [ - WSTETH_TO_STETH_PRICE_FEED, // wstETH / stETH price feed - ETH_TO_USD_PRICE_FEED, // ETH / USD price feed (we consider stETH / ETH as 1:1) - 8, // decimals - 'wstETH / USD price feed' // description - ] - ); - - const l2MessageService = await deploymentManager.existing( - 'l2MessageService', - L2MESSAGE_SERVICE_ADDRESS, - 'linea' - ); - - const l2StandardBridge = await deploymentManager.existing( - 'l2StandardBridge', - L2STANDARD_BRIDGE_ADDRESS, - 'linea' - ); - - const l2USDCBridge = await deploymentManager.existing( - 'l2USDCBridge', - L2USDC_BRIDGE_ADDRESS, - 'linea' - ); - - // Import shared contracts from cUSDCv3 - const _cometAdmin = await deploymentManager.fromDep('cometAdmin', 'linea', 'usdc'); - const _assetListFactory = await deploymentManager.fromDep('assetListFactory', 'linea', 'usdc'); - const _cometFactory = await deploymentManager.fromDep('cometFactory', 'linea', 'usdc'); - const _$configuratorImpl = await deploymentManager.fromDep('configurator:implementation', 'linea', 'usdc'); - const _configurator = await deploymentManager.fromDep('configurator', 'linea', 'usdc'); - const _rewards = await deploymentManager.fromDep('rewards', 'linea', 'usdc'); - const bulker = await deploymentManager.fromDep('bulker', 'linea', 'usdc'); - const _localTimelock = await deploymentManager.fromDep('timelock', 'linea', 'usdc'); - const bridgeReceiver = await deploymentManager.fromDep('bridgeReceiver', 'linea', 'usdc'); - - // Deploy Comet - const deployed = await deployComet(deploymentManager, deploySpec, {}, true); - - return { - ...deployed, - bridgeReceiver, - l2MessageService, - l2StandardBridge, - l2USDCBridge, - bulker, - }; -} diff --git a/deployments/linea/usdt/migrations/1736946439_configurate_and_ens.ts b/deployments/linea/usdt/migrations/1736946439_configurate_and_ens.ts deleted file mode 100644 index 998d59bbf..000000000 --- a/deployments/linea/usdt/migrations/1736946439_configurate_and_ens.ts +++ /dev/null @@ -1,340 +0,0 @@ -import { utils } from 'ethers'; -import { expect } from 'chai'; -import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; -import { diffState, getCometConfig } from '../../../../plugins/deployment_manager/DiffState'; -import { migration } from '../../../../plugins/deployment_manager/Migration'; -import { calldata, exp, getConfigurationStruct, proposal } from '../../../../src/deploy'; - -const ENSName = 'compound-community-licenses.eth'; -const ENSResolverAddress = '0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41'; -const ENSSubdomainLabel = 'v3-additional-grants'; -const ENSSubdomain = `${ENSSubdomainLabel}.${ENSName}`; -const ENSTextRecordKey = 'v3-official-markets'; - -const lineaCOMPAddress = '0x0ECE76334Fb560f2b1a49A60e38Cf726B02203f0'; -const mainnetUsdtAddress = '0xdAC17F958D2ee523a2206206994597C13D831ec7'; -const cUSDTAddress = '0xf650c3d88d12db855b8bf7d11be6c55a4e07dcc9'; - -const USDTAmountToBridge = exp(100_000, 6); - -export default migration('1736946439_configurate_and_ens', { - prepare: async (_deploymentManager: DeploymentManager) => { - return {}; - }, - - enact: async (deploymentManager: DeploymentManager, govDeploymentManager: DeploymentManager) => { - const trace = deploymentManager.tracer(); - - const cometFactory = await deploymentManager.fromDep('cometFactory', 'linea', 'usdc'); - const { - bridgeReceiver, - comet, - cometAdmin, - configurator, - rewards, - } = await deploymentManager.getContracts(); - - const { - lineaMessageService, - lineaL1TokenBridge, - governor - } = await govDeploymentManager.getContracts(); - - const configuration = await getConfigurationStruct(deploymentManager); - - const _reduceReservesCalldata = utils.defaultAbiCoder.encode( - ['uint256'], - [USDTAmountToBridge] - ); - - const zeroApproveCalldata = utils.defaultAbiCoder.encode( - ['address', 'uint256'], - [lineaL1TokenBridge.address, 0] - ); - - const approveCalldata = utils.defaultAbiCoder.encode( - ['address', 'uint256'], - [lineaL1TokenBridge.address, USDTAmountToBridge] - ); - - const setFactoryCalldata = await calldata( - configurator.populateTransaction.setFactory(comet.address, cometFactory.address) - ); - const setConfigurationCalldata = await calldata( - configurator.populateTransaction.setConfiguration(comet.address, configuration) - ); - const deployAndUpgradeToCalldata = utils.defaultAbiCoder.encode( - ['address', 'address'], - [configurator.address, comet.address] - ); - const setRewardConfigCalldata = utils.defaultAbiCoder.encode( - ['address', 'address'], - [comet.address, lineaCOMPAddress] - ); - const l2ProposalData = utils.defaultAbiCoder.encode( - ['address[]', 'uint256[]', 'string[]', 'bytes[]'], - [ - [configurator.address, configurator.address, cometAdmin.address, rewards.address], - [0, 0, 0, 0], - [ - 'setFactory(address,address)', - 'setConfiguration(address,(address,address,address,address,address,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint104,uint104,uint104,(address,address,uint8,uint64,uint64,uint64,uint128)[]))', - 'deployAndUpgradeTo(address,address)', - 'setRewardConfig(address,address)' - ], - [ - setFactoryCalldata, - setConfigurationCalldata, - deployAndUpgradeToCalldata, - setRewardConfigCalldata - ] - ] - ); - - const ENSResolver = await govDeploymentManager.existing('ENSResolver', ENSResolverAddress); - const subdomainHash = utils.namehash(ENSSubdomain); - const officialMarketsJSON = JSON.parse(await ENSResolver.text(subdomainHash, ENSTextRecordKey)); - const newMarketObject = { baseSymbol: 'USDT', cometAddress: comet.address }; - - if (officialMarketsJSON[59144]) { - officialMarketsJSON[59144].push(newMarketObject); - } else { - officialMarketsJSON[59144] = [newMarketObject]; - } - - const mainnetActions = [ - // 1. Set Comet configuration and deployAndUpgradeTo new Comet on Linea. - { - contract: lineaMessageService, - signature: 'sendMessage(address,uint256,bytes)', - args: [bridgeReceiver.address, 0, l2ProposalData], - }, - // 2. Get USDT reserves from cUSDT contract - { - target: cUSDTAddress, - signature: '_reduceReserves(uint256)', - calldata: _reduceReservesCalldata - }, - // 3. Reset approve of USDT from Timelock's to Gateway - { - target: mainnetUsdtAddress, - signature: 'approve(address,uint256)', - calldata: zeroApproveCalldata - }, - // 4. Approve the USDT gateway to take Timelock's USDT for bridging - { - target: mainnetUsdtAddress, - signature: 'approve(address,uint256)', - calldata: approveCalldata - }, - // 5. Bridge USDT from mainnet to Linea Comet - { - contract: lineaL1TokenBridge, - signature: 'bridgeToken(address,uint256,address)', - args: [mainnetUsdtAddress, USDTAmountToBridge, comet.address] - }, - // 6. Update the list of official markets - { - target: ENSResolverAddress, - signature: 'setText(bytes32,string,string)', - calldata: utils.defaultAbiCoder.encode( - ['bytes32', 'string', 'string'], - [subdomainHash, ENSTextRecordKey, JSON.stringify(officialMarketsJSON)] - ) - } - ]; - - const description = '# Initialize cUSDTv3 on Linea network\n\n## Proposal summary\n\nWOOF! proposes the deployment of Compound III to the Linea network. This proposal takes the governance steps recommended and necessary to initialize a Compound III USDT market on Linea; upon execution, cUSDTv3 will be ready for use. Simulations have confirmed the market’s readiness, as much as possible, using the [Comet scenario suite](https://github.com/compound-finance/comet/tree/main/scenario). The new parameters include setting the risk parameters based off of the [recommendations from Gauntlet](https://www.comp.xyz/t/deploy-compound-iii-on-linea/4460/19).\n\nFurther detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/982), [deploy market GitHub action run](https://github.com/woof-software/comet/actions/runs/15211082351) and [forum discussion](https://www.comp.xyz/t/deploy-compound-iii-on-linea/4460).\n\n\n## Proposal Actions\n\nThe first proposal action sets the Comet configuration and deploys a new Comet implementation on Linea. This sends the encoded `setFactory`, `setConfiguration`, `deployAndUpgradeTo` calls across the bridge to the governance receiver on Linea.\n\nThe second action reduces Compound’s [cUSDT](https://etherscan.io/address/0xf650c3d88d12db855b8bf7d11be6c55a4e07dcc9) reserves and transfers it to Timelock, in order to seed the market reserves for the Linea cUSDTv3 Comet.\n\nThe third action approves 0 USDT from Timelock to [LineaL1TokenBridge](https://etherscan.io/address/0x051F1D88f0aF5763fB888eC4378b4D8B29ea3319) to reset potential previous approves.\n\nThe fourth action approves 100K USDT to [LineaL1TokenBridge](https://etherscan.io/address/0x051F1D88f0aF5763fB888eC4378b4D8B29ea3319) to take Timelock\'s USDT on Mainnet, in order to seed the market reserves through the bridge.\n\nThe fifth action bridges USDT from mainnet via Linea`s bridge contract and sends it to Comet on Linea.\n\nThe sixth action updates the ENS TXT record `v3-official-markets` on `v3-additional-grants.compound-community-licenses.eth`, updating the official markets JSON to include the new Linea cUSDTv3 market.'; - const txn = await govDeploymentManager.retry(async () => - trace(await governor.propose(...(await proposal(mainnetActions, description)))) - ); - - const event = txn.events.find(event => event.event === 'ProposalCreated'); - const [proposalId] = event.args; - - trace(`Created proposal ${proposalId}.`); - }, - - async enacted(): Promise { - return false; - }, - - async verify(deploymentManager: DeploymentManager, govDeploymentManager: DeploymentManager, preMigrationBlockNumber: number) { - await deploymentManager.spider(); // Pull in Linea COMP now that reward config has been set - - const { - comet, - rewards, - } = await deploymentManager.getContracts(); - - // 1. - const stateChanges = await diffState(comet, getCometConfig, preMigrationBlockNumber); - - const secondsPerYear = 31_536_000; // 365 * 24 * 60 * 60 - expect(stateChanges).to.deep.equal({ - WETH: { - supplyCap: exp(270, 18) - }, - wstETH: { - supplyCap: exp(60, 18) - }, - WBTC: { - supplyCap: exp(4, 8) - }, - baseTrackingSupplySpeed: exp(2 / 86400, 15, 18), // 23148148148 - baseTrackingBorrowSpeed: exp(1 / 86400, 15, 18), // 11574074074 - supplyPerSecondRateSlopeLow: exp(0.036 / secondsPerYear, 18, 18), // 11415525114 - supplyPerSecondInterestRateSlopeHigh: exp(3.196 / secondsPerYear, 18, 18), // 101344495180 - borrowPerSecondInterestRateSlopeLow: exp(0.02778 / secondsPerYear, 18, 18), // 880898021 - borrowPerSecondInterestRateSlopeHigh: exp(3.6 / secondsPerYear, 18, 18), // 114155251141 - }); - - const config = await rewards.rewardConfig(comet.address); - expect(config.token).to.be.equal(lineaCOMPAddress); - expect(config.rescaleFactor).to.be.equal(exp(1, 12)); - expect(config.shouldUpscale).to.be.equal(true); - - // 2. & 3. - expect(await comet.getReserves()).to.be.equal(USDTAmountToBridge); - - // 6. - const ENSResolver = await govDeploymentManager.existing('ENSResolver', ENSResolverAddress); - const subdomainHash = utils.namehash(ENSSubdomain); - const officialMarketsJSON = await ENSResolver.text(subdomainHash, ENSTextRecordKey); - const officialMarkets = JSON.parse(officialMarketsJSON); - expect(officialMarkets).to.deep.equal({ - 1: [ - { - baseSymbol: 'USDC', - cometAddress: '0xc3d688B66703497DAA19211EEdff47f25384cdc3' - }, - { - baseSymbol: 'WETH', - cometAddress: '0xA17581A9E3356d9A858b789D68B4d866e593aE94' - }, - { - baseSymbol: 'USDT', - cometAddress: '0x3Afdc9BCA9213A35503b077a6072F3D0d5AB0840' - }, - { - baseSymbol: 'wstETH', - cometAddress: '0x3D0bb1ccaB520A66e607822fC55BC921738fAFE3' - }, - { - baseSymbol: 'USDS', - cometAddress: '0x5D409e56D886231aDAf00c8775665AD0f9897b56' - }, - { - baseSymbol: 'WBTC', - cometAddress: '0xe85Dc543813B8c2CFEaAc371517b925a166a9293' - } - ], - 10: [ - { - baseSymbol: 'USDC', - cometAddress: '0x2e44e174f7D53F0212823acC11C01A11d58c5bCB' - }, - { - baseSymbol: 'USDT', - cometAddress: '0x995E394b8B2437aC8Ce61Ee0bC610D617962B214' - }, - { - baseSymbol: 'WETH', - cometAddress: '0xE36A30D249f7761327fd973001A32010b521b6Fd' - } - ], - 130: [ - { - baseSymbol: 'USDC', - cometAddress: '0x2c7118c4C88B9841FCF839074c26Ae8f035f2921' - }, - { - baseSymbol: 'WETH', - cometAddress: '0x6C987dDE50dB1dcDd32Cd4175778C2a291978E2a' - } - ], - 137: [ - { - baseSymbol: 'USDC', - cometAddress: '0xF25212E676D1F7F89Cd72fFEe66158f541246445' - }, - { - baseSymbol: 'USDT', - cometAddress: '0xaeB318360f27748Acb200CE616E389A6C9409a07' - } - ], - 2020: [ - { - baseSymbol: 'WETH', - cometAddress: '0x4006eD4097Ee51c09A04c3B0951D28CCf19e6DFE' - }, - { - baseSymbol: 'WRON', - cometAddress: '0xc0Afdbd1cEB621Ef576BA969ce9D4ceF78Dbc0c0' - } - ], - 5000: [ - { - baseSymbol: 'USDe', - cometAddress: '0x606174f62cd968d8e684c645080fa694c1D7786E' - } - ], - 8453: [ - { - baseSymbol: 'USDbC', - cometAddress: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf' - }, - { - baseSymbol: 'WETH', - cometAddress: '0x46e6b214b524310239732D51387075E0e70970bf' - }, - { - baseSymbol: 'USDC', - cometAddress: '0xb125E6687d4313864e53df431d5425969c15Eb2F' - }, - { - baseSymbol: 'AERO', - cometAddress: '0x784efeB622244d2348d4F2522f8860B96fbEcE89' - }, - { - baseSymbol: 'USDS', - cometAddress: '0x2c776041CCFe903071AF44aa147368a9c8EEA518' - } - ], - 42161: [ - { - baseSymbol: 'USDC.e', - cometAddress: '0xA5EDBDD9646f8dFF606d7448e414884C7d905dCA' - }, - { - baseSymbol: 'USDC', - cometAddress: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf' - }, - { - baseSymbol: 'WETH', - cometAddress: '0x6f7D514bbD4aFf3BcD1140B7344b32f063dEe486' - }, - { - baseSymbol: 'USDT', - cometAddress: '0xd98Be00b5D27fc98112BdE293e487f8D4cA57d07' - } - ], - 59144: [ - { - baseSymbol: 'USDC', - cometAddress: '0x8D38A3d6B3c3B7d96D6536DA7Eef94A9d7dbC991' - }, - { - baseSymbol: 'USDT', - cometAddress: comet.address - } - ], - 534352: [ - { - baseSymbol: 'USDC', - cometAddress: '0xB2f97c1Bd3bf02f5e74d13f02E3e26F93D77CE44' - } - ] - }); - } -}); diff --git a/deployments/linea/usdt/relations.ts b/deployments/linea/usdt/relations.ts deleted file mode 100644 index 57b3392f0..000000000 --- a/deployments/linea/usdt/relations.ts +++ /dev/null @@ -1,33 +0,0 @@ -import baseRelationConfig from '../../relations'; - -export default { - ...baseRelationConfig, - governor: { - artifact: - 'contracts/bridges/linea/LineaBridgeReceiver.sol:LineaBridgeReceiver', - }, - l2MessageService: { - delegates: { - field: { - slot: - '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc', - }, - }, - }, - l2StandardBridge: { - delegates: { - field: { - slot: - '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc', - }, - }, - }, - 'TransparentUpgradeableProxy': { - artifact: 'contracts/ERC20.sol:ERC20', - delegates: { - field: { - slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' - } - } - }, -}; diff --git a/deployments/linea/usdt/roots.json b/deployments/linea/usdt/roots.json deleted file mode 100644 index 10c660ce4..000000000 --- a/deployments/linea/usdt/roots.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "comet": "0x2D86D6456682E0932e65869416c89fF8DB76381f", - "configurator": "0x970FfD8E335B8fa4cd5c869c7caC3a90671d5Dc3", - "rewards": "0x2c7118c4C88B9841FCF839074c26Ae8f035f2921", - "cometFactory": "0xaeB318360f27748Acb200CE616E389A6C9409a07", - "bridgeReceiver": "0x1F71901daf98d70B4BAF40DE080321e5C2676856", - "l2MessageService": "0x508Ca82Df566dCD1B0DE8296e70a96332cD644ec", - "l2StandardBridge": "0x353012dc4a9A6cF55c941bADC267f82004A8ceB9", - "l2USDCBridge": "0xA2Ee6Fce4ACB62D95448729cDb781e3BEb62504A", - "bulker": "0x023ee795361B28cDbB94e302983578486A0A5f1B" -} \ No newline at end of file diff --git a/deployments/linea/weth/configuration.json b/deployments/linea/weth/configuration.json deleted file mode 100644 index 8a8a4b5c9..000000000 --- a/deployments/linea/weth/configuration.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "name": "Compound WETH", - "symbol": "cWETHv3", - "baseToken": "WETH", - "baseTokenAddress": "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f", - "pauseGuardian": "0x5A1e5d7E09cA94506084a26304d53A138145bF52", - "borrowMin": "0.01e18", - "storeFrontPriceFactor": 0.7, - "targetReserves": "5_000e18", - "rates": { - "borrowBase": 0.01, - "borrowSlopeLow": 0.0155, - "borrowKink": 0.9, - "borrowSlopeHigh": 1.26, - "supplyBase": 0, - "supplySlopeLow": 0.0216, - "supplyKink": 0.9, - "supplySlopeHigh": 1.125 - }, - "tracking": { - "indexScale": "1e15", - "baseSupplySpeed": "69444444444e0", - "baseBorrowSpeed": "46296296296e0", - "baseMinForRewards": "10e18" - }, - "assets": { - "ezETH": { - "address": "0x2416092f143378750bb29b79eD961ab195CcEea5", - "decimals": "18", - "borrowCF": 0.90, - "liquidateCF": 0.93, - "liquidationFactor": 0.94, - "supplyCap": "4830e18" - }, - "wstETH": { - "address": "0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F", - "decimals": "18", - "borrowCF": 0.90, - "liquidateCF": 0.93, - "liquidationFactor": 0.97, - "supplyCap": "260e18" - }, - "WBTC": { - "address": "0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4", - "decimals": "8", - "borrowCF": 0.8, - "liquidateCF": 0.85, - "liquidationFactor": 0.9, - "supplyCap": "5e8" - }, - "weETH": { - "address": "0x1Bf74C010E6320bab11e2e5A532b5AC15e0b8aA6", - "decimals": "18", - "borrowCF": 0.90, - "liquidateCF": 0.93, - "liquidationFactor": 0.96, - "supplyCap": "3550e18" - }, - "wrsETH": { - "address": "0xD2671165570f41BBB3B0097893300b6EB6101E6C", - "decimals": "18", - "borrowCF": 0.90, - "liquidateCF": 0.93, - "liquidationFactor": 0.96, - "supplyCap": "500e18" - } - } -} \ No newline at end of file diff --git a/deployments/linea/weth/deploy.ts b/deployments/linea/weth/deploy.ts deleted file mode 100644 index 78ae844f3..000000000 --- a/deployments/linea/weth/deploy.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { - Deployed, - DeploymentManager, -} from '../../../plugins/deployment_manager'; -import { DeploySpec, deployComet, exp } from '../../../src/deploy'; - -const L2MESSAGE_SERVICE_ADDRESS = '0x508Ca82Df566dCD1B0DE8296e70a96332cD644ec'; -const L2STANDARD_BRIDGE_ADDRESS = '0x353012dc4a9A6cF55c941bADC267f82004A8ceB9'; -const L2USDC_BRIDGE_ADDRESS = '0xA2Ee6Fce4ACB62D95448729cDb781e3BEb62504A'; - -export default async function deploy( - deploymentManager: DeploymentManager, - deploySpec: DeploySpec -): Promise { - const deployed = await deployContracts(deploymentManager, deploySpec); - return deployed; -} - -async function deployContracts( - deploymentManager: DeploymentManager, - deploySpec: DeploySpec -): Promise { - const _WETH = await deploymentManager.existing( - 'WETH', - '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f', - 'linea' - ); - - const _wethConstantPriceFeed = await deploymentManager.deploy( - 'WETH:priceFeed', - 'pricefeeds/ConstantPriceFeed.sol', - [ - 8, // decimals - exp(1, 8) // constantPrice - ] - ); - - // Pull in existing assets - const _ezETH = await deploymentManager.existing( - 'ezETH', - '0x2416092f143378750bb29b79eD961ab195CcEea5', - 'linea' - ); - - const _ezETHPriceFeed = await deploymentManager.deploy( - 'ezETH:priceFeed', - 'pricefeeds/ScalingPriceFeed.sol', - [ - '0xb71F79770BA599940F454c70e63d4DE0E8606731', // ezETH / ETH price feed - 8 // decimals - ] - ); - - const _wstETH = await deploymentManager.existing( - 'wstETH', - '0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F', - 'linea' - ); - - const _wstETHPriceFeed = await deploymentManager.deploy( - 'wstETH:priceFeed', - 'pricefeeds/ScalingPriceFeed.sol', - [ - '0x3C8A95F2264bB3b52156c766b738357008d87cB7', // wstETH / stETH (we consider stETH / ETH as 1:1) price feed - 8 // decimals - ] - ); - - const _WBTC = await deploymentManager.existing( - 'WBTC', - '0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4', - 'linea' - ); - - const _wbtcPriceFeed = await deploymentManager.deploy( - 'WBTC:priceFeed', - 'pricefeeds/ReverseMultiplicativePriceFeed.sol', - [ - '0x7A99092816C8BD5ec8ba229e3a6E6Da1E628E1F9', // WBTC / USD price feed - '0x3c6Cd9Cc7c7a4c2Cf5a82734CD249D7D593354dA', // USD / ETH price feed - 8, // decimals - 'WBTC / ETH price feed' // description - ] - ); - - const _weETH = await deploymentManager.existing( - 'weETH', - '0x1Bf74C010E6320bab11e2e5A532b5AC15e0b8aA6', - 'linea' - ); - - const _weETHPriceFeed = await deploymentManager.deploy( - 'weETH:priceFeed', - 'pricefeeds/ScalingPriceFeed.sol', - [ - '0x1FBc7d24654b10c71fd74d3730d9Df17836181EF', // weETH / eETH (we consider eETH / ETH as 1:1) price feed - 8 // decimals - ] - ); - - const _wrsETH = await deploymentManager.existing( - 'wrsETH', - '0xD2671165570f41BBB3B0097893300b6EB6101E6C', - 'linea' - ); - - const _wrsETHPriceFeed = await deploymentManager.deploy( - 'wrsETH:priceFeed', - 'pricefeeds/ScalingPriceFeedWithCustomDescription.sol', - [ - '0xEEDF0B095B5dfe75F3881Cb26c19DA209A27463a', // wrsETH / ETH price feed - 8, // decimals - 'wrsETH / ETH price feed' // description - ], - true - ); - - const l2MessageService = await deploymentManager.existing( - 'l2MessageService', - L2MESSAGE_SERVICE_ADDRESS, - 'linea' - ); - - const l2StandardBridge = await deploymentManager.existing( - 'l2StandardBridge', - L2STANDARD_BRIDGE_ADDRESS, - 'linea' - ); - - const l2USDCBridge = await deploymentManager.existing( - 'l2USDCBridge', - L2USDC_BRIDGE_ADDRESS, - 'linea' - ); - - // Import shared contracts from cUSDCv3 - const _cometAdmin = await deploymentManager.fromDep('cometAdmin', 'linea', 'usdc'); - const _assetListFactory = await deploymentManager.fromDep('assetListFactory', 'linea', 'usdc'); - const _cometFactory = await deploymentManager.fromDep('cometFactory', 'linea', 'usdc'); - const _$configuratorImpl = await deploymentManager.fromDep('configurator:implementation', 'linea', 'usdc'); - const _configurator = await deploymentManager.fromDep('configurator', 'linea', 'usdc'); - const _rewards = await deploymentManager.fromDep('rewards', 'linea', 'usdc'); - const bulker = await deploymentManager.fromDep('bulker', 'linea', 'usdc'); - const _localTimelock = await deploymentManager.fromDep('timelock', 'linea', 'usdc'); - const bridgeReceiver = await deploymentManager.fromDep('bridgeReceiver', 'linea', 'usdc'); - - // Deploy Comet - const deployed = await deployComet(deploymentManager, deploySpec, {}, true); - - return { - ...deployed, - bridgeReceiver, - l2MessageService, - l2StandardBridge, - l2USDCBridge, - bulker, - }; -} diff --git a/deployments/linea/weth/migrations/1737020138_configurate_and_ens.ts b/deployments/linea/weth/migrations/1737020138_configurate_and_ens.ts deleted file mode 100644 index 6224b3dfe..000000000 --- a/deployments/linea/weth/migrations/1737020138_configurate_and_ens.ts +++ /dev/null @@ -1,344 +0,0 @@ -import { utils } from 'ethers'; -import { expect } from 'chai'; -import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; -import { diffState, getCometConfig } from '../../../../plugins/deployment_manager/DiffState'; -import { migration } from '../../../../plugins/deployment_manager/Migration'; -import { calldata, exp, getConfigurationStruct, proposal } from '../../../../src/deploy'; - -const ENSName = 'compound-community-licenses.eth'; -const ENSResolverAddress = '0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41'; -const ENSSubdomainLabel = 'v3-additional-grants'; -const ENSSubdomain = `${ENSSubdomainLabel}.${ENSName}`; -const ENSTextRecordKey = 'v3-official-markets'; - -const lineaCOMPAddress = '0x0ECE76334Fb560f2b1a49A60e38Cf726B02203f0'; - -const WETHAmountToBridge = exp(25, 18); - -export default migration('1737020138_configurate_and_ens', { - prepare: async (_deploymentManager: DeploymentManager) => { - return {}; - }, - - enact: async ( - deploymentManager: DeploymentManager, - govDeploymentManager: DeploymentManager - ) => { - const trace = deploymentManager.tracer(); - - const cometFactory = await deploymentManager.fromDep('cometFactory', 'linea', 'usdc'); - const { - bridgeReceiver, - comet, - cometAdmin, - configurator, - rewards, - timelock: l2Timelock, - WETH - } = await deploymentManager.getContracts(); - - const { - lineaMessageService, - governor - } = await govDeploymentManager.getContracts(); - - const configuration = await getConfigurationStruct(deploymentManager); - - const setFactoryCalldata = await calldata( - configurator.populateTransaction.setFactory(comet.address, cometFactory.address) - ); - const setConfigurationCalldata = await calldata( - configurator.populateTransaction.setConfiguration(comet.address, configuration) - ); - const deployAndUpgradeToCalldata = utils.defaultAbiCoder.encode( - ['address', 'address'], - [configurator.address, comet.address] - ); - const setRewardConfigCalldata = utils.defaultAbiCoder.encode( - ['address', 'address'], - [comet.address, lineaCOMPAddress] - ); - const sweepNativeTokenCalldata = await calldata(bridgeReceiver.populateTransaction.sweepNativeToken(l2Timelock.address)); - const transferCalldata = await calldata(WETH.populateTransaction.transfer(comet.address, WETHAmountToBridge)); - - const l2ProposalData = utils.defaultAbiCoder.encode( - ['address[]', 'uint256[]', 'string[]', 'bytes[]'], - [ - [ - configurator.address, - configurator.address, - cometAdmin.address, - rewards.address, - bridgeReceiver.address, - WETH.address, - WETH.address - ], - [0, 0, 0, 0, 0, WETHAmountToBridge, 0], - [ - 'setFactory(address,address)', - 'setConfiguration(address,(address,address,address,address,address,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint104,uint104,uint104,(address,address,uint8,uint64,uint64,uint64,uint128)[]))', - 'deployAndUpgradeTo(address,address)', - 'setRewardConfig(address,address)', - 'sweepNativeToken(address)', - 'deposit()', - 'transfer(address,uint256)' - ], - [ - setFactoryCalldata, - setConfigurationCalldata, - deployAndUpgradeToCalldata, - setRewardConfigCalldata, - sweepNativeTokenCalldata, - '0x', - transferCalldata - ] - ] - ); - - const ENSResolver = await govDeploymentManager.existing('ENSResolver', ENSResolverAddress); - const subdomainHash = utils.namehash(ENSSubdomain); - const officialMarketsJSON = JSON.parse(await ENSResolver.text(subdomainHash, ENSTextRecordKey)); - const newMarketObject = { baseSymbol: 'WETH', cometAddress: comet.address }; - - if (officialMarketsJSON[59144]) { - officialMarketsJSON[59144].push(newMarketObject); - } else { - officialMarketsJSON[59144] = [newMarketObject]; - } - - const mainnetActions = [ - // 1. Set Comet configuration and deployAndUpgradeTo new Comet on Linea. - { - contract: lineaMessageService, - signature: 'sendMessage(address,uint256,bytes)', - args: [bridgeReceiver.address, 0, l2ProposalData], - value: WETHAmountToBridge - }, - // 2. Update the list of official markets - { - target: ENSResolverAddress, - signature: 'setText(bytes32,string,string)', - calldata: utils.defaultAbiCoder.encode( - ['bytes32', 'string', 'string'], - [subdomainHash, ENSTextRecordKey, JSON.stringify(officialMarketsJSON)] - ) - } - ]; - - const description = `# Initialize cWETHv3 on Linea network - -## Proposal summary - -WOOF! proposes the deployment of Compound III to the Linea network. This proposal takes the governance steps recommended and necessary to initialize a Compound III WETH market on Linea; upon execution, cWETHv3 will be ready for use. Simulations have confirmed the market’s readiness, as much as possible, using the [Comet scenario suite](https://github.com/compound-finance/comet/tree/main/scenario). The new parameters include setting the risk parameters based off of the [recommendations from Gauntlet](https://www.comp.xyz/t/deploy-compound-iii-on-linea/4460/20). - -Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/982), [deploy market GitHub action run](https://github.com/woof-software/comet/actions/runs/15211470652) and [forum discussion](https://www.comp.xyz/t/deploy-compound-iii-on-linea/4460). - - -## wrsETH Price Feed - -[wrsETH/ETH exchange rate](https://lineascan.build/address/0xEEDF0B095B5dfe75F3881Cb26c19DA209A27463a#readContract) price oracle has a wrong label. The information is confirmed with ChainLink and Kelp teams internally. - - -## Proposal Actions - -The first proposal action sends ether to the Linea Timelock so it can be wrapped and used to seed the reserves, sets the Comet configuration and deploys a new Comet implementation on Linea. This sends the encoded 'setFactory', 'setConfiguration', 'deployAndUpgradeTo' calls across the bridge to the governance receiver on Linea. - -The second action updates the ENS TXT record 'v3-official-markets' on 'v3-additional-grants.compound-community-licenses.eth', updating the official markets JSON to include the new Linea cWETHv3 market.`; - - const txn = await govDeploymentManager.retry(async () => - trace(await governor.propose(...(await proposal(mainnetActions, description)))) - ); - - const event = txn.events.find(event => event.event === 'ProposalCreated'); - const [proposalId] = event.args; - - trace(`Created proposal ${proposalId}.`); - }, - - async enacted(): Promise { - return false; - }, - - async verify( - deploymentManager: DeploymentManager, - govDeploymentManager: DeploymentManager, - preMigrationBlockNumber: number - ) { - await deploymentManager.spider(); // Pull in Linea COMP now that reward config has been set - - const { - comet, - rewards, - } = await deploymentManager.getContracts(); - - // 1. - const stateChanges = await diffState(comet, getCometConfig, preMigrationBlockNumber); - expect(stateChanges).to.deep.equal({ - ezETH: { - supplyCap: exp(4830, 18) - }, - wstETH: { - supplyCap: exp(260, 18) - }, - WBTC: { - supplyCap: exp(5, 8) - }, - weETH: { - supplyCap: exp(3550, 18) - }, - wrsETH: { - supplyCap: exp(500, 18) - }, - baseTrackingSupplySpeed: exp(6 / 86400, 15, 18), // 69444444444 - baseTrackingBorrowSpeed: exp(4 / 86400, 15, 18), // 46296296296 - }); - - const config = await rewards.rewardConfig(comet.address); - expect(config.token).to.be.equal(lineaCOMPAddress); - expect(config.rescaleFactor).to.be.equal(exp(1, 12)); - expect(config.shouldUpscale).to.be.equal(true); - - // 2. & 3. - expect(await comet.getReserves()).to.be.equal(WETHAmountToBridge); - - // 6. - const ENSResolver = await govDeploymentManager.existing('ENSResolver', ENSResolverAddress); - const subdomainHash = utils.namehash(ENSSubdomain); - const officialMarketsJSON = await ENSResolver.text(subdomainHash, ENSTextRecordKey); - const officialMarkets = JSON.parse(officialMarketsJSON); - expect(officialMarkets).to.deep.equal({ - 1: [ - { - baseSymbol: 'USDC', - cometAddress: '0xc3d688B66703497DAA19211EEdff47f25384cdc3' - }, - { - baseSymbol: 'WETH', - cometAddress: '0xA17581A9E3356d9A858b789D68B4d866e593aE94' - }, - { - baseSymbol: 'USDT', - cometAddress: '0x3Afdc9BCA9213A35503b077a6072F3D0d5AB0840' - }, - { - baseSymbol: 'wstETH', - cometAddress: '0x3D0bb1ccaB520A66e607822fC55BC921738fAFE3' - }, - { - baseSymbol: 'USDS', - cometAddress: '0x5D409e56D886231aDAf00c8775665AD0f9897b56' - }, - { - baseSymbol: 'WBTC', - cometAddress: '0xe85Dc543813B8c2CFEaAc371517b925a166a9293' - } - ], - 10: [ - { - baseSymbol: 'USDC', - cometAddress: '0x2e44e174f7D53F0212823acC11C01A11d58c5bCB' - }, - { - baseSymbol: 'USDT', - cometAddress: '0x995E394b8B2437aC8Ce61Ee0bC610D617962B214' - }, - { - baseSymbol: 'WETH', - cometAddress: '0xE36A30D249f7761327fd973001A32010b521b6Fd' - } - ], - 130: [ - { - baseSymbol: 'USDC', - cometAddress: '0x2c7118c4C88B9841FCF839074c26Ae8f035f2921' - }, - { - baseSymbol: 'WETH', - cometAddress: '0x6C987dDE50dB1dcDd32Cd4175778C2a291978E2a' - } - ], - 137: [ - { - baseSymbol: 'USDC', - cometAddress: '0xF25212E676D1F7F89Cd72fFEe66158f541246445' - }, - { - baseSymbol: 'USDT', - cometAddress: '0xaeB318360f27748Acb200CE616E389A6C9409a07' - } - ], - 2020: [ - { - baseSymbol: 'WETH', - cometAddress: '0x4006eD4097Ee51c09A04c3B0951D28CCf19e6DFE' - }, - { - baseSymbol: 'WRON', - cometAddress: '0xc0Afdbd1cEB621Ef576BA969ce9D4ceF78Dbc0c0' - } - ], - 5000: [ - { - baseSymbol: 'USDe', - cometAddress: '0x606174f62cd968d8e684c645080fa694c1D7786E' - } - ], - 8453: [ - { - baseSymbol: 'USDbC', - cometAddress: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf' - }, - { - baseSymbol: 'WETH', - cometAddress: '0x46e6b214b524310239732D51387075E0e70970bf' - }, - { - baseSymbol: 'USDC', - cometAddress: '0xb125E6687d4313864e53df431d5425969c15Eb2F' - }, - { - baseSymbol: 'AERO', - cometAddress: '0x784efeB622244d2348d4F2522f8860B96fbEcE89' - }, - { - baseSymbol: 'USDS', - cometAddress: '0x2c776041CCFe903071AF44aa147368a9c8EEA518' - } - ], - 42161: [ - { - baseSymbol: 'USDC.e', - cometAddress: '0xA5EDBDD9646f8dFF606d7448e414884C7d905dCA' - }, - { - baseSymbol: 'USDC', - cometAddress: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf' - }, - { - baseSymbol: 'WETH', - cometAddress: '0x6f7D514bbD4aFf3BcD1140B7344b32f063dEe486' - }, - { - baseSymbol: 'USDT', - cometAddress: '0xd98Be00b5D27fc98112BdE293e487f8D4cA57d07' - } - ], - 59144: [ - { - baseSymbol: 'USDC', - cometAddress: '0x8D38A3d6B3c3B7d96D6536DA7Eef94A9d7dbC991' - }, - { - baseSymbol: 'WETH', - cometAddress: comet.address - } - ], - 534352: [ - { - baseSymbol: 'USDC', - cometAddress: '0xB2f97c1Bd3bf02f5e74d13f02E3e26F93D77CE44' - } - ] - }); - } -}); diff --git a/deployments/linea/weth/relations.ts b/deployments/linea/weth/relations.ts deleted file mode 100644 index 57b3392f0..000000000 --- a/deployments/linea/weth/relations.ts +++ /dev/null @@ -1,33 +0,0 @@ -import baseRelationConfig from '../../relations'; - -export default { - ...baseRelationConfig, - governor: { - artifact: - 'contracts/bridges/linea/LineaBridgeReceiver.sol:LineaBridgeReceiver', - }, - l2MessageService: { - delegates: { - field: { - slot: - '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc', - }, - }, - }, - l2StandardBridge: { - delegates: { - field: { - slot: - '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc', - }, - }, - }, - 'TransparentUpgradeableProxy': { - artifact: 'contracts/ERC20.sol:ERC20', - delegates: { - field: { - slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' - } - } - }, -}; diff --git a/deployments/linea/weth/roots.json b/deployments/linea/weth/roots.json deleted file mode 100644 index c774096d0..000000000 --- a/deployments/linea/weth/roots.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "comet": "0x60F2058379716A64a7A5d29219397e79bC552194", - "configurator": "0x970FfD8E335B8fa4cd5c869c7caC3a90671d5Dc3", - "rewards": "0x2c7118c4C88B9841FCF839074c26Ae8f035f2921", - "cometFactory": "0xaeB318360f27748Acb200CE616E389A6C9409a07", - "bridgeReceiver": "0x1F71901daf98d70B4BAF40DE080321e5C2676856", - "l2MessageService": "0x508Ca82Df566dCD1B0DE8296e70a96332cD644ec", - "l2StandardBridge": "0x353012dc4a9A6cF55c941bADC267f82004A8ceB9", - "l2USDCBridge": "0xA2Ee6Fce4ACB62D95448729cDb781e3BEb62504A", - "bulker": "0x023ee795361B28cDbB94e302983578486A0A5f1B" -} \ No newline at end of file From df8d7240a4c4bc4767f92bab929f6c854ce02f2d Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Fri, 19 Sep 2025 16:22:13 +0300 Subject: [PATCH 11/65] fix: remove localhost deployment --- deployments/localhost/dai/configuration.json | 26 - deployments/localhost/dai/deploy.ts | 604 ------------------- 2 files changed, 630 deletions(-) delete mode 100644 deployments/localhost/dai/configuration.json delete mode 100644 deployments/localhost/dai/deploy.ts diff --git a/deployments/localhost/dai/configuration.json b/deployments/localhost/dai/configuration.json deleted file mode 100644 index 61cbcd5db..000000000 --- a/deployments/localhost/dai/configuration.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "Compound DAI", - "symbol": "cDAIv3", - "baseToken": "DAI", - "borrowMin": "1000e6", - "storeFrontPriceFactor": 0.5, - "targetReserves": "5000000e6", - "rates": { - "supplyKink": 0.8, - "supplySlopeLow": 0.0325, - "supplySlopeHigh": 0.4, - "supplyBase": 0, - "borrowKink": 0.8, - "borrowSlopeLow": 0.035, - "borrowSlopeHigh": 0.25, - "borrowBase": 0.015 - }, - "tracking": { - "indexScale": "1e15", - "baseSupplySpeed": "0.000011574074074074073e15", - "baseBorrowSpeed": "0.0011458333333333333e15", - "baseMinForRewards": "1000000e6" - }, - "rewardToken": "GOLD", - "assets": {} -} diff --git a/deployments/localhost/dai/deploy.ts b/deployments/localhost/dai/deploy.ts deleted file mode 100644 index af92db1a0..000000000 --- a/deployments/localhost/dai/deploy.ts +++ /dev/null @@ -1,604 +0,0 @@ -import { Deployed, DeploymentManager } from '../../../plugins/deployment_manager'; -import {Comet, FaucetToken, SimplePriceFeed, MarketUpdateProposer, CometProxyAdmin, SimpleTimelock, CometProxyAdminOld, MarketUpdateTimelock, CometFactory, ConfiguratorProxy, Configurator__factory} from '../../../build/types'; -import { - DeploySpec, - exp, - wait, - getConfiguration, - sameAddress, - getConfigurationStruct -} from '../../../src/deploy'; -import '@nomiclabs/hardhat-ethers'; -import { ethers } from 'hardhat'; - -async function makeToken( - deploymentManager: DeploymentManager, - amount: number, - name: string, - decimals: number, - symbol: string -): Promise { - const mint = (BigInt(amount) * 10n ** BigInt(decimals)).toString(); - return deploymentManager.deploy(symbol, 'test/FaucetToken.sol', [mint, name, decimals, symbol]); -} - -async function makePriceFeed( - deploymentManager: DeploymentManager, - alias: string, - initialPrice: number, - decimals: number -): Promise { - return deploymentManager.deploy(alias, 'test/SimplePriceFeed.sol', [initialPrice * 1e8, decimals]); -} - -async function advanceTimeAndMineBlock(delay: number) { - await ethers.provider.send('evm_increaseTime', [delay + 10]); - await ethers.provider.send('evm_mine', []); // Mine a new block to apply the time increase -} - -// TODO: Support configurable assets as well? -export default async function deploy(deploymentManager: DeploymentManager, deploySpec: DeploySpec): Promise { - const trace = deploymentManager.tracer(); - const signer = await deploymentManager.getSigner(); - const ethers = deploymentManager.hre.ethers; - const admin = signer; - - // Deploy governance contracts - const clone = { - comp: '0xc00e94cb662c3520282e6f5717214004a7f26888', - governorBravoImpl: '0xef3b6e9e13706a8f01fe98fdcf66335dc5cfdeed', - governorBravo: '0xc0da02939e1441f497fd74f78ce7decb17b66529', - }; - - const fauceteer = await deploymentManager.deploy('fauceteer', 'test/Fauceteer.sol', []); - const timelock = await deploymentManager.deploy('timelock', 'test/SimpleTimelock.sol', [admin.address]) as SimpleTimelock; - const COMP = await deploymentManager.clone('COMP', clone.comp, [admin.address]); - - const governorImpl = await deploymentManager.clone( - 'governor:implementation', - clone.governorBravoImpl, - [] - ); - const governorProxy = await deploymentManager.clone( - 'governor', - clone.governorBravo, - [ - timelock.address, - COMP.address, - admin.address, - governorImpl.address, - await governorImpl.MIN_VOTING_PERIOD(), - await governorImpl.MIN_VOTING_DELAY(), - await governorImpl.MIN_PROPOSAL_THRESHOLD(), - ] - ); - const governorBravo = governorImpl.attach(governorProxy.address); - await deploymentManager.idempotent( - async () => (await governorBravo.proposalCount()).eq(0), - async () => { - trace(`Initiating Governor using patched Timelock`); - trace(await wait(governorBravo.connect(admin)._initiate(timelock.address))); - } - ); - await timelock.connect(admin).setAdmin(governorBravo.address); - - await deploymentManager.idempotent( - async () => (await COMP.balanceOf(admin.address)).gte((await COMP.totalSupply()).div(3)), - async () => { - trace(`Sending 1/4 of COMP to fauceteer, 1/4 to timelock`); - const amount = (await COMP.balanceOf(admin.address)).div(4); - trace(await wait(COMP.connect(admin).transfer(fauceteer.address, amount))); - trace(await wait(COMP.connect(admin).transfer(timelock.address, amount))); - trace(`COMP.balanceOf(${fauceteer.address}): ${await COMP.balanceOf(fauceteer.address)}`); - trace(`COMP.balanceOf(${timelock.address}): ${await COMP.balanceOf(timelock.address)}`); - } - ); - - await deploymentManager.idempotent( - async () => (await COMP.getCurrentVotes(admin.address)).eq(0), - async () => { - trace(`Delegating COMP votes to ${admin.address}`); - trace(await wait(COMP.connect(admin).delegate(admin.address))); - trace(`COMP.getCurrentVotes(${admin.address}): ${await COMP.getCurrentVotes(admin.address)}`); - } - ); - - const DAI = await makeToken(deploymentManager, 10000000, 'DAI', 18, 'DAI'); - const GOLD = await makeToken(deploymentManager, 20000000, 'GOLD', 8, 'GOLD'); - const SILVER = await makeToken(deploymentManager, 30000000, 'SILVER', 10, 'SILVER'); - - const daiPriceFeed = await makePriceFeed(deploymentManager, 'DAI:priceFeed', 1, 8); - const goldPriceFeed = await makePriceFeed(deploymentManager, 'GOLD:priceFeed', 0.5, 8); - const silverPriceFeed = await makePriceFeed(deploymentManager, 'SILVER:priceFeed', 0.05, 8); - - const assetConfig0 = { - asset: GOLD.address, - priceFeed: goldPriceFeed.address, - decimals: (8).toString(), - borrowCollateralFactor: (0.9e18).toString(), - liquidateCollateralFactor: (0.91e18).toString(), - liquidationFactor: (0.95e18).toString(), - supplyCap: (1000000e8).toString(), - }; - - const assetConfig1 = { - asset: SILVER.address, - priceFeed: silverPriceFeed.address, - decimals: (10).toString(), - borrowCollateralFactor: (0.4e18).toString(), - liquidateCollateralFactor: (0.5e18).toString(), - liquidationFactor: (0.9e18).toString(), - supplyCap: (500000e10).toString(), - }; - - const configOverrides = { - baseTokenPriceFeed: daiPriceFeed.address, - assetConfigs: [assetConfig0, assetConfig1], - }; - - const rewards = await deploymentManager.deploy( - 'rewards', - 'CometRewards.sol', - [admin.address], - maybeForce(deploySpec.rewards) - ); - - await deploymentManager.idempotent( - async () => (await GOLD.balanceOf(rewards.address)).eq(0), - async () => { - trace(`Sending some GOLD to CometRewards`); - const amount = exp(2_000_000, 8); - trace(await wait(GOLD.connect(signer).transfer(rewards.address, amount))); - trace(`GOLD.balanceOf(${rewards.address}): ${await GOLD.balanceOf(rewards.address)}`); - } - ); - - function maybeForce(flag?: boolean): boolean { - return deploySpec.all || flag; - } - - - const { - name, - symbol, - governor, // NB: generally 'timelock' alias, not 'governor' - pauseGuardian, - baseToken, - baseTokenPriceFeed, - supplyKink, - supplyPerYearInterestRateSlopeLow, - supplyPerYearInterestRateSlopeHigh, - supplyPerYearInterestRateBase, - borrowKink, - borrowPerYearInterestRateSlopeLow, - borrowPerYearInterestRateSlopeHigh, - borrowPerYearInterestRateBase, - storeFrontPriceFactor, - trackingIndexScale, - baseTrackingSupplySpeed, - baseTrackingBorrowSpeed, - baseMinForRewards, - baseBorrowMin, - targetReserves, - assetConfigs, - } = await getConfiguration(deploymentManager, configOverrides); - - /* Deploy contracts */ - - const cometProxyAdminOld = await deploymentManager.deploy( - 'cometAdminOld', - 'marketupdates/CometProxyAdminOld.sol', - [], - maybeForce() - ) as CometProxyAdminOld; - - - - const extConfiguration = { - name32: ethers.utils.formatBytes32String(name), - symbol32: ethers.utils.formatBytes32String(symbol) - }; - const cometExt = await deploymentManager.deploy( - 'comet:implementation:implementation', - 'CometExt.sol', - [extConfiguration], - maybeForce(deploySpec.cometExt) - ); - - const cometFactory = await deploymentManager.deploy( - 'cometFactory', - 'CometFactory.sol', - [], - maybeForce(deploySpec.cometMain) - ) as CometFactory; - - const configuration = { - governor, - pauseGuardian, - baseToken, - baseTokenPriceFeed, - extensionDelegate: cometExt.address, - supplyKink, - supplyPerYearInterestRateSlopeLow, - supplyPerYearInterestRateSlopeHigh, - supplyPerYearInterestRateBase, - borrowKink, - borrowPerYearInterestRateSlopeLow, - borrowPerYearInterestRateSlopeHigh, - borrowPerYearInterestRateBase, - storeFrontPriceFactor, - trackingIndexScale, - baseTrackingSupplySpeed, - baseTrackingBorrowSpeed, - baseMinForRewards, - baseBorrowMin, - targetReserves, - assetConfigs, - }; - trace('Timelock address:', timelock.address); - trace('Governor address:', governor); - - const tmpCometImpl = await deploymentManager.deploy( - 'comet:implementation', - 'Comet.sol', - [configuration], - maybeForce(), - ) as Comet; - - trace('Checking tmpCometImpl:supplyKink'); - console.log('tmpCometImpl:supplyKink', await tmpCometImpl.supplyKink()); - const cometProxyContract = await deploymentManager.deploy( - 'comet', - 'vendor/proxy/transparent/TransparentUpgradeableProxy.sol', - [tmpCometImpl.address, cometProxyAdminOld.address, []], // NB: temporary implementation contract - maybeForce() - ); - const factory= await ethers.getContractFactory('Comet'); - const cometProxy= factory.attach(cometProxyContract.address) as Comet; - - trace('tmpCometImpl', tmpCometImpl.address); - - trace('Checking CometProxy:supplyKink'); - console.log('CometProxy:supplyKink', await cometProxy.supplyKink()); - - - const configuratorImpl = await deploymentManager.deploy( - 'configurator-old:implementation', - 'marketupdates/ConfiguratorOld.sol', - [], - maybeForce(deploySpec.cometMain) - ); - - // If we deploy a new proxy, we initialize it to the current/new impl - // If its an existing proxy, the impl we got for the alias must already be current - // In other words, we shan't have deployed an impl in the last step unless there was no proxy too - const configuratorProxyContract = await deploymentManager.deploy( - 'configurator', - 'ConfiguratorProxy.sol', - [configuratorImpl.address, signer.address, (await configuratorImpl.populateTransaction.initialize(admin.address)).data], - maybeForce() - ) as ConfiguratorProxy; - - const configuratorFactory = await ethers.getContractFactory('Configurator') as Configurator__factory; - const configuratorProxy = configuratorFactory.attach(configuratorProxyContract.address); - trace(`Setting factory in Configurator to ${cometFactory.address}`); - await configuratorProxy.connect(admin).setFactory(cometProxy.address, cometFactory.address); - - - const configurationStr = await getConfigurationStruct(deploymentManager); - trace(`Setting configuration in Configurator for ${cometProxy.address}`); - await configuratorProxy.connect(admin).setConfiguration(cometProxy.address, configurationStr); - // await txSetConfiguration.wait(); - - - trace(`Upgrading implementation of Comet...`); - - await configuratorProxyContract.changeAdmin(cometProxyAdminOld.address); - - await cometProxyAdminOld.deployAndUpgradeTo(configuratorProxy.address, cometProxy.address); - - await cometProxyAdminOld.transferOwnership(timelock.address); - - /* Wire things up */ - - // Now configure the configurator and actually deploy comet - // Note: the success of these calls is dependent on who the admin is and if/when its been transferred - // scenarios can pass in an impersonated signer, but real deploys may require proposals for some states - const configurator = configuratorImpl.attach(configuratorProxyContract.address); - - // Also get a handle for Comet, although it may not *actually* support the interface yet - const comet = await deploymentManager.cast(cometProxy.address, 'contracts/CometInterface.sol:CometInterface'); - - // Call initializeStorage if storage not initialized - // Note: we now rely on the fact that anyone may call, which helps separate the proposal - await deploymentManager.idempotent( - async () => (await comet.totalsBasic()).lastAccrualTime == 0, - async () => { - trace(`Initializing Comet at ${comet.address}`); - trace(await wait(comet.connect(admin).initializeStorage())); - } - ); - - // If we aren't admin, we'll need proposals to configure things - const amAdmin = sameAddress(await cometProxyAdminOld.owner(), admin.address); - trace(`Am I admin? ${amAdmin}`); - - // Get the current impl addresses for the proxies, and determine if we've configurated - const $cometImpl = await cometProxyAdminOld.getProxyImplementation(comet.address); - const isTmpImpl = sameAddress($cometImpl, tmpCometImpl.address); - trace(`isTmpImpl ${isTmpImpl} deploySpec.all ${deploySpec.all} deploySpec.cometMain ${deploySpec.cometMain} deploySpec.cometExt ${deploySpec.cometExt}`); - - - /* Transfer to Gov */ - - await deploymentManager.idempotent( - async () => !sameAddress(await configurator.governor(), governor), - async () => { - trace(`Transferring governor of Configurator to ${governor}`); - trace(await wait(configurator.connect(admin).transferGovernor(governor))); - } - ); - - await deploymentManager.idempotent( - async () => !sameAddress(await cometProxyAdminOld.owner(), governor), - async () => { - trace(`Transferring ownership of CometProxyAdmin to ${governor}`); - trace(await wait(cometProxyAdminOld.connect(admin).transferOwnership(governor))); - } - ); - - await deploymentManager.idempotent( - async () => !sameAddress(await rewards.governor(), governor), - async () => { - trace(`Transferring governor of CometRewards to ${governor}`); - trace(await wait(rewards.connect(admin).transferGovernor(governor))); - } - ); - - - // Mint some tokens - trace(`Attempting to mint as ${signer.address}...`); - - await Promise.all( - [[DAI, 1e8], [GOLD, 2e6], [SILVER, 1e7]].map(([faucetToken, unitOfToken]) => { - const asset = faucetToken as FaucetToken; - const units = unitOfToken as number; - - return deploymentManager.idempotent( - async () => (await asset.balanceOf(fauceteer.address)).eq(0), - async () => { - trace(`Minting ${units} ${await asset.symbol()} to fauceteer`); - const amount = exp(units, await asset.decimals()); - trace(await wait(asset.connect(signer).allocateTo(fauceteer.address, amount))); - trace(`asset.balanceOf(${signer.address}): ${await asset.balanceOf(signer.address)}`); - } - ); - }) - ); - - const supplyKinkOld = await comet.supplyKink(); - trace(`supplyKink:`, supplyKinkOld); - - const signers = await ethers.getSigners(); - - const marketUpdateTimelock = (await deploymentManager.deploy( - 'marketUpdateTimelock', - 'marketupdates/MarketUpdateTimelock.sol', - [governor, 2 * 24 * 60 * 60], - maybeForce() - )) as MarketUpdateTimelock; - - // 1) Deploy the address of MarketAdminMultiSig - const marketUpdateMultiSig = signers[3]; - const proposalGuardian = signers[11]; - - const marketUpdateProposer = await deploymentManager.deploy( - 'marketUpdateProposer', - 'marketupdates/MarketUpdateProposer.sol', - [governor, marketUpdateMultiSig.address, proposalGuardian.address, marketUpdateTimelock.address], - maybeForce() - ) as MarketUpdateProposer; - - const cometProxyAdminNew = await deploymentManager.deploy( - 'cometProxyAdminNew', - 'CometProxyAdmin.sol', - [], - maybeForce() - ) as CometProxyAdmin; - - await cometProxyAdminNew.transferOwnership(governor); - - const configuratorNew = await deploymentManager.deploy( - 'configuratorNew', - 'Configurator.sol', - [], - maybeForce() - ); - - const marketAdminPermissionChecker = await deploymentManager.deploy( - 'marketAdminPermissionChecker', - 'marketupdates/MarketAdminPermissionChecker.sol', - [ethers.constants.AddressZero, ethers.constants.AddressZero], - maybeForce() - ); - - await marketAdminPermissionChecker.transferOwnership( - governor - ); - - const newSupplyKinkByGovernorTimelock = 300n; - - trace('Trigger updates to enable market admin'); - const firstProposalTxn = await governorBravo - .connect(admin) - .propose( - [ - cometProxyAdminOld.address, - cometProxyAdminOld.address, - cometProxyAdminNew.address, - marketAdminPermissionChecker.address, - configuratorProxyContract.address, - cometProxyAdminNew.address, - marketUpdateTimelock.address, - ], - [0, 0, 0, 0, 0, 0, 0], - [ - 'changeProxyAdmin(address,address)', - 'changeProxyAdmin(address,address)', - 'upgrade(address,address)', - 'setMarketAdmin(address)', - 'setMarketAdminPermissionChecker(address)', - 'setMarketAdminPermissionChecker(address)', - 'setMarketUpdateProposer(address)', - ], - [ - ethers.utils.defaultAbiCoder.encode( - ['address', 'address'], - [configuratorProxyContract.address, cometProxyAdminNew.address] - ), - ethers.utils.defaultAbiCoder.encode( - ['address', 'address'], - [cometProxy.address, cometProxyAdminNew.address] - ), - ethers.utils.defaultAbiCoder.encode( - ['address', 'address'], - [configuratorProxyContract.address, configuratorNew.address] - ), - ethers.utils.defaultAbiCoder.encode( - ['address'], - [marketUpdateTimelock.address] - ), - ethers.utils.defaultAbiCoder.encode( - ['address'], - [marketAdminPermissionChecker.address] - ), - ethers.utils.defaultAbiCoder.encode( - ['address'], - [marketAdminPermissionChecker.address] - ), - ethers.utils.defaultAbiCoder.encode( - ['address'], - [marketUpdateProposer.address] - ), - ], - 'Proposal to trigger updates for market admin' - ); - const firstProposalReceipt = await firstProposalTxn.wait(); - - const firstProposalID = firstProposalReceipt.events.find( - (event) => event.event === 'ProposalCreated' - ).args.id; - console.log('first proposal id: ', firstProposalID); - - const stateBeforeStart = await governorBravo.state(firstProposalID); - console.log('Proposal State before start block forwarding:', stateBeforeStart); - - const votingDelay = await governorBravo.votingDelay(); - // Fast-forward by votingDelay blocks to reach the start of the voting period - for (let i = 0; i < votingDelay.toNumber(); i++) { - await ethers.provider.send('evm_mine', []); - } - const stateAfterStart = await governorBravo.state(firstProposalID); - console.log('Proposal State after start block forwarding:', stateAfterStart); - - await governorBravo.connect(admin).castVote(firstProposalID, 1); - - const votingPeriod = await governorBravo.votingPeriod(); - // Fast-forward to the end of the voting period - for (let i = 0; i <= votingPeriod.toNumber(); i++) { - await ethers.provider.send('evm_mine', []); // fast-forward remaining blocks - } - - const stateAfter = await governorBravo.state(firstProposalID); - console.log('Proposal State after fast-forward:', stateAfter); - - trace('Queue from Governor Bravo'); - await governorBravo.connect(admin).queue(firstProposalID); - trace('Execute from Governor Bravo'); - await governorBravo.connect(admin).execute(firstProposalID); - - trace('Update supply kink through GovernorBravo'); - const secondProposalTxn = await governorBravo.connect(admin).propose( - [ - configuratorProxyContract.address, - cometProxyAdminNew.address - ], - [0,0], - [ - 'setSupplyKink(address,uint64)', - 'deployAndUpgradeTo(address,address)' - ], - [ - ethers.utils.defaultAbiCoder.encode(['address', 'uint64'], [cometProxy.address, newSupplyKinkByGovernorTimelock]), - ethers.utils.defaultAbiCoder.encode(['address', 'address'], [configuratorProxyContract.address, cometProxy.address]) - ], - 'Proposal to update supply kink' - ); - const secondProposalReceipt = await secondProposalTxn.wait(); - - const secondProposalID = secondProposalReceipt.events.find( - (event) => event.event === 'ProposalCreated' - ).args.id; - console.log('second proposal id: ', secondProposalID); - - const stateBeforeStart2 = await governorBravo.state(secondProposalID); - console.log('Proposal State before start block forwarding #2:', stateBeforeStart2); - - const votingDelay2 = await governorBravo.votingDelay(); - // Fast-forward by votingDelay blocks to reach the start of the voting period - for (let i = 0; i < votingDelay2.toNumber(); i++) { - await ethers.provider.send('evm_mine', []); - } - const stateAfterStart2 = await governorBravo.state(secondProposalID); - console.log('Proposal State after start block forwarding #2:', stateAfterStart2); - - await governorBravo.connect(admin).castVote(secondProposalID, 1); - - const votingPeriod2 = await governorBravo.votingPeriod(); - // Fast-forward to the end of the voting period - for (let i = 0; i <= votingPeriod2.toNumber(); i++) { - await ethers.provider.send('evm_mine', []); // fast-forward remaining blocks - } - - const stateAfter2 = await governorBravo.state(secondProposalID); - console.log('Proposal State after fast-forward #2:', stateAfter2); - - trace('Queue from Governor Bravo #2'); - await governorBravo.connect(admin).queue(secondProposalID); - trace('Execute from Governor Bravo #2'); - await governorBravo.connect(admin).execute(secondProposalID); - - const supplyKinkByGovernorTimelock = await (comet).supplyKink(); - trace(`supplyKinkByGovernorTimelock:`, supplyKinkByGovernorTimelock); - - trace('MarketAdmin: Setting new supplyKink in Configurator and deploying Comet'); - const newSupplyKinkByMarketAdmin = 100n; - await marketUpdateProposer.connect(marketUpdateMultiSig).propose( - [ - configuratorProxyContract.address, - cometProxyAdminNew.address - ], - [0, 0], - [ - 'setSupplyKink(address,uint64)', - 'deployAndUpgradeTo(address,address)' - ], - [ - ethers.utils.defaultAbiCoder.encode(['address', 'uint64'], [cometProxy.address, newSupplyKinkByMarketAdmin]), - ethers.utils.defaultAbiCoder.encode(['address', 'address'], [configuratorProxyContract.address, cometProxy.address]) - ], - 'Test market update' - ); - - await advanceTimeAndMineBlock(2 * 24 * 60 * 60 + 10); // Fast forwarding by 2 days and a few seconds - - trace('Executing market update proposal'); - - await marketUpdateProposer.connect(marketUpdateMultiSig).execute(1); - - trace('checking supplyKink after market update'); - const supplyKinkByMarketAdmin = await (cometProxy).supplyKink(); - trace(`supplyKinkByMarketAdmin:`, supplyKinkByMarketAdmin); - - return { comet, configurator, rewards, fauceteer }; -} From 0001bd6b62a9b7643c3c5e0b8b777a36c128d8b8 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Mon, 22 Sep 2025 16:02:25 +0300 Subject: [PATCH 12/65] fix: unify import --- scenario/utils/index.ts | 9 +++++++++ scenario/utils/relayArbitrumMessage.ts | 5 +---- scenario/utils/relayBaseMessage.ts | 9 +-------- scenario/utils/relayLineaMessage.ts | 5 +---- scenario/utils/relayMantleMessage.ts | 10 +--------- scenario/utils/relayOptimismMessage.ts | 10 +--------- scenario/utils/relayPolygonMessage.ts | 5 +---- scenario/utils/relayRoninMessage.ts | 5 +---- scenario/utils/relayScrollMessage.ts | 9 +-------- scenario/utils/relayUnichainMessage.ts | 10 +--------- 10 files changed, 18 insertions(+), 59 deletions(-) diff --git a/scenario/utils/index.ts b/scenario/utils/index.ts index 1a7c7b5ec..7160b7355 100644 --- a/scenario/utils/index.ts +++ b/scenario/utils/index.ts @@ -1475,3 +1475,12 @@ export async function timeUntilUnderwater({ fudgeFactor ); } + +export function applyL1ToL2Alias(address: string) { + const offset = BigInt('0x1111000000000000000000000000000000001111'); + return `0x${(BigInt(address) + offset).toString(16)}`; +} + +export function isTenderlyLog(log: any): log is { raw: { topics: string[], data: string } } { + return !!log?.raw?.topics && !!log?.raw?.data; +} diff --git a/scenario/utils/relayArbitrumMessage.ts b/scenario/utils/relayArbitrumMessage.ts index 857342aea..550979448 100644 --- a/scenario/utils/relayArbitrumMessage.ts +++ b/scenario/utils/relayArbitrumMessage.ts @@ -5,10 +5,7 @@ import { utils, BigNumber } from 'ethers'; import { Log } from '@ethersproject/abstract-provider'; import { sourceTokens } from '../../plugins/scenario/utils/TokenSourcer'; import { OpenBridgedProposal } from '../context/Gov'; - -function isTenderlyLog(log: any): log is { raw: { topics: string[], data: string } } { - return !!log?.raw?.topics && !!log?.raw?.data; -} +import { isTenderlyLog } from './index'; export async function relayArbitrumMessage( governanceDeploymentManager: DeploymentManager, diff --git a/scenario/utils/relayBaseMessage.ts b/scenario/utils/relayBaseMessage.ts index 955086e40..1e5418c11 100644 --- a/scenario/utils/relayBaseMessage.ts +++ b/scenario/utils/relayBaseMessage.ts @@ -4,6 +4,7 @@ import { setNextBaseFeeToZero, setNextBlockTimestamp } from './hreUtils'; import { BigNumber, ethers } from 'ethers'; import { Log } from '@ethersproject/abstract-provider'; import { OpenBridgedProposal } from '../context/Gov'; +import { applyL1ToL2Alias, isTenderlyLog } from './index'; /* The Base relayer applies an offset to the message sender. @@ -12,14 +13,6 @@ an L1 address to its offset, L2 equivalent. https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000007#code */ -function applyL1ToL2Alias(address: string) { - const offset = BigInt('0x1111000000000000000000000000000000001111'); - return `0x${(BigInt(address) + offset).toString(16)}`; -} - -function isTenderlyLog(log: any): log is { raw: { topics: string[], data: string } } { - return !!log?.raw?.topics && !!log?.raw?.data; -} export default async function relayBaseMessage( governanceDeploymentManager: DeploymentManager, diff --git a/scenario/utils/relayLineaMessage.ts b/scenario/utils/relayLineaMessage.ts index a48df9500..6307d3ab6 100644 --- a/scenario/utils/relayLineaMessage.ts +++ b/scenario/utils/relayLineaMessage.ts @@ -4,13 +4,10 @@ import { constants, ethers } from 'ethers'; import { Log } from '@ethersproject/abstract-provider'; import { OpenBridgedProposal } from '../context/Gov'; import { impersonateAddress } from '../../plugins/scenario/utils'; +import { isTenderlyLog } from './index'; const LINEA_SETTER_ROLE_ACCOUNT = '0xc1C6B09D1eB6fCA0fF3cA11027E5Bc4AeDb47F67'; -function isTenderlyLog(log: any): log is { raw: { topics: string[], data: string } } { - return !!log?.raw?.topics && !!log?.raw?.data; -} - export default async function relayLineaMessage( governanceDeploymentManager: DeploymentManager, bridgeDeploymentManager: DeploymentManager, diff --git a/scenario/utils/relayMantleMessage.ts b/scenario/utils/relayMantleMessage.ts index 3e56a17aa..812255b75 100644 --- a/scenario/utils/relayMantleMessage.ts +++ b/scenario/utils/relayMantleMessage.ts @@ -4,15 +4,7 @@ import { setNextBaseFeeToZero, setNextBlockTimestamp } from './hreUtils'; import { BigNumber, ethers } from 'ethers'; import { Log } from '@ethersproject/abstract-provider'; import { OpenBridgedProposal } from '../context/Gov'; - -function applyL1ToL2Alias(address: string) { - const offset = BigInt('0x1111000000000000000000000000000000001111'); - return `0x${(BigInt(address) + offset).toString(16)}`; -} - -function isTenderlyLog(log: any): log is { raw: { topics: string[], data: string } } { - return !!log?.raw?.topics && !!log?.raw?.data; -} +import { applyL1ToL2Alias, isTenderlyLog } from './index'; export default async function relayMantleMessage( governanceDeploymentManager: DeploymentManager, diff --git a/scenario/utils/relayOptimismMessage.ts b/scenario/utils/relayOptimismMessage.ts index f39c105ce..5ce1d076d 100644 --- a/scenario/utils/relayOptimismMessage.ts +++ b/scenario/utils/relayOptimismMessage.ts @@ -4,15 +4,7 @@ import { setNextBaseFeeToZero, setNextBlockTimestamp } from './hreUtils'; import { BigNumber, ethers } from 'ethers'; import { Log } from '@ethersproject/abstract-provider'; import { OpenBridgedProposal } from '../context/Gov'; - -function isTenderlyLog(log: any): log is { raw: { topics: string[], data: string } } { - return !!log?.raw?.topics && !!log?.raw?.data; -} - -function applyL1ToL2Alias(address: string) { - const offset = BigInt('0x1111000000000000000000000000000000001111'); - return `0x${(BigInt(address) + offset).toString(16)}`; -} +import { applyL1ToL2Alias, isTenderlyLog } from './index'; export default async function relayOptimismMessage( governanceDeploymentManager: DeploymentManager, diff --git a/scenario/utils/relayPolygonMessage.ts b/scenario/utils/relayPolygonMessage.ts index 5d05ff2e4..67d10d8cc 100644 --- a/scenario/utils/relayPolygonMessage.ts +++ b/scenario/utils/relayPolygonMessage.ts @@ -5,10 +5,7 @@ import { setNextBaseFeeToZero } from './hreUtils'; import { Contract, ethers } from 'ethers'; import { Log } from '@ethersproject/abstract-provider'; import { OpenBridgedProposal } from '../context/Gov'; - -function isTenderlyLog(log: any): log is { raw: { topics: string[], data: string } } { - return !!log?.raw?.topics && !!log?.raw?.data; -} +import { isTenderlyLog } from './index'; type BridgeERC20Data = { syncData: string; diff --git a/scenario/utils/relayRoninMessage.ts b/scenario/utils/relayRoninMessage.ts index 2c61ea1ae..4a72cee87 100644 --- a/scenario/utils/relayRoninMessage.ts +++ b/scenario/utils/relayRoninMessage.ts @@ -4,13 +4,10 @@ import { setNextBaseFeeToZero, setNextBlockTimestamp } from './hreUtils'; import { BigNumber, ethers } from 'ethers'; import { Log } from '@ethersproject/abstract-provider'; import { OpenBridgedProposal } from '../context/Gov'; +import { isTenderlyLog } from './index'; const roninChainSelector = '6916147374840168594'; -function isTenderlyLog(log: any): log is { raw: { topics: string[], data: string } } { - return !!log?.raw?.topics && !!log?.raw?.data; -} - export default async function relayRoninMessage( governanceDeploymentManager: DeploymentManager, bridgeDeploymentManager: DeploymentManager, diff --git a/scenario/utils/relayScrollMessage.ts b/scenario/utils/relayScrollMessage.ts index d4555a765..686658cd0 100644 --- a/scenario/utils/relayScrollMessage.ts +++ b/scenario/utils/relayScrollMessage.ts @@ -4,6 +4,7 @@ import { Log } from '@ethersproject/abstract-provider'; import { impersonateAddress } from '../../plugins/scenario/utils'; import { OpenBridgedProposal } from '../context/Gov'; import { BigNumber, ethers } from 'ethers'; +import { applyL1ToL2Alias, isTenderlyLog } from './index'; /* The Scroll relayer applies an offset to the message sender. @@ -11,14 +12,6 @@ The Scroll relayer applies an offset to the message sender. applyL1ToL2Alias mimics the AddressAliasHelper.applyL1ToL2Alias fn that converts an L1 address to its offset, L2 equivalent. */ -function applyL1ToL2Alias(address: string) { - const offset = BigInt('0x1111000000000000000000000000000000001111'); - return `0x${(BigInt(address) + offset).toString(16)}`; -} - -function isTenderlyLog(log: any): log is { raw: { topics: string[], data: string } } { - return !!log?.raw?.topics && !!log?.raw?.data; -} export default async function relayScrollMessage( governanceDeploymentManager: DeploymentManager, diff --git a/scenario/utils/relayUnichainMessage.ts b/scenario/utils/relayUnichainMessage.ts index 818f17f53..5b3db9b5b 100644 --- a/scenario/utils/relayUnichainMessage.ts +++ b/scenario/utils/relayUnichainMessage.ts @@ -4,15 +4,7 @@ import { setNextBaseFeeToZero, setNextBlockTimestamp } from './hreUtils'; import { BigNumber, ethers, utils } from 'ethers'; import { Log } from '@ethersproject/abstract-provider'; import { OpenBridgedProposal } from '../context/Gov'; - -function applyL1ToL2Alias(address: string) { - const offset = BigInt('0x1111000000000000000000000000000000001111'); - return `0x${(BigInt(address) + offset).toString(16)}`; -} - -function isTenderlyLog(log: any): log is { raw: { topics: string[], data: string } } { - return !!log?.raw?.topics && !!log?.raw?.data; -} +import { applyL1ToL2Alias, isTenderlyLog } from './index'; export async function relayUnichainMessage( governanceDeploymentManager: DeploymentManager, From aceaf43815a30d32a022e6847b4f38381a6c6ccf Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Tue, 11 Nov 2025 12:19:33 +0200 Subject: [PATCH 13/65] fixes from recent prs --- .github/workflows/deploy-market.yaml | 12 ++++++- .github/workflows/enact-migration.yaml | 5 +-- .github/workflows/prepare-migration.yaml | 5 +-- .github/workflows/run-contract-linter.yaml | 1 + .github/workflows/run-coverage.yaml | 1 + .github/workflows/run-eslint.yaml | 1 + .github/workflows/run-forge-tests.yaml | 1 + .github/workflows/run-gas-profiler.yaml | 1 + .github/workflows/run-scenarios.yaml | 1 + .github/workflows/run-semgrep.yaml | 1 + .github/workflows/run-unit-tests.yaml | 1 + contracts/test/CometModified.sol | 6 ++-- deployments/hardhat/dai/deploy.ts | 2 +- deployments/mainnet/weth/deploy.ts | 2 +- deployments/mainnet/wsteth/deploy.ts | 2 +- deployments/sepolia/usdc/deploy.ts | 2 +- deployments/sepolia/weth/deploy.ts | 2 +- hardhat.config.ts | 34 +++++++++++++----- plugins/scenario/utils/hreForBase.ts | 15 ++++++-- scenario/SupplyScenario.ts | 14 ++++---- scenario/TransferScenario.ts | 20 +++++------ scenario/WithdrawScenario.ts | 12 +++---- .../constraints/TokenBalanceConstraint.ts | 1 + scenario/constraints/UtilizationConstraint.ts | 6 ++++ scenario/utils/index.ts | 15 +++++--- scenario/utils/isBridgeProposal.ts | 1 + scenario/utils/relayLineaMessage.ts | 12 +++---- scenario/utils/relayMessage.ts | 1 + scenario/utils/scenarioHelper.ts | 36 +++++++++++++++++-- src/deploy/index.ts | 3 ++ tasks/deployment_manager/task.ts | 7 ++-- test/configurator-test.ts | 2 +- test/helpers.ts | 26 ++++++++++++++ 33 files changed, 187 insertions(+), 64 deletions(-) diff --git a/.github/workflows/deploy-market.yaml b/.github/workflows/deploy-market.yaml index 21faa47c6..bb1c424dc 100644 --- a/.github/workflows/deploy-market.yaml +++ b/.github/workflows/deploy-market.yaml @@ -42,16 +42,26 @@ jobs: SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} + LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} steps: - name: Seacrest uses: hayesgm/seacrest@af229b0a00b73cb6fa9940a836a62fa3b918fd77 with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"linea\":\"https://rpc.ankr.com/linea/${ANKR_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/$_TENDERLY_KEY_RONIN\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://mantle-mainnet.infura.io/v3/$INFURA_KEY\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/$INFURA_KEY\",\"sepolia\":\"https://sepolia.infura.io/v3/$INFURA_KEY\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://arbitrum-mainnet.infura.io/v3/$INFURA_KEY\",\"base\":\"https://rpc.ankr.com/base/$ANKR_KEY\",\"scroll\":\"https://rpc.scroll.io\"}')[inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"https://omniscient-hardworking-gas.linea-mainnet.quiknode.pro/${LINEA_QUICKNODE_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://rpc.ankr.com/mantle/${ANKR_KEY}\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://rpc.ankr.com/arbitrum/$ANKR_KEY\",\"base\":\"https://rpc.ankr.com/base/$ANKR_KEY\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' + - name: Seacrest (governance network) + uses: hayesgm/seacrest@af229b0a00b73cb6fa9940a836a62fa3b918fd77 + with: + wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} + requested_network: "${{ vars.GOV_NETWORK }}" + ethereum_url: "${{ fromJSON('{\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\"}')[vars.GOV_NETWORK] }}" + port: 8685 + if: github.event.inputs.eth_pk == '' && vars.GOV_NETWORK != '' && github.event.inputs.network != vars.GOV_NETWORK + - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/enact-migration.yaml b/.github/workflows/enact-migration.yaml index dfb3d812a..67468c57c 100644 --- a/.github/workflows/enact-migration.yaml +++ b/.github/workflows/enact-migration.yaml @@ -65,6 +65,7 @@ jobs: _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} _TENDERLY_KEY_POLYGON: ${{ secrets._TENDERLY_KEY_POLYGON }} UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} + LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} GOV_NETWORK: ${{ vars.GOV_NETWORK }} steps: - name: Get governance network @@ -92,7 +93,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"linea\":\"https://rpc.ankr.com/linea/${ANKR_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://mantle-mainnet.infura.io/v3/$INFURA_KEY\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/$INFURA_KEY\",\"sepolia\":\"https://sepolia.infura.io/v3/$INFURA_KEY\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://arbitrum-mainnet.infura.io/v3/$INFURA_KEY\",\"base\":\"https://rpc.ankr.com/base/$ANKR_KEY\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"https://omniscient-hardworking-gas.linea-mainnet.quiknode.pro/${LINEA_QUICKNODE_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://rpc.ankr.com/mantle/${ANKR_KEY}\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://rpc.ankr.com/arbitrum/$ANKR_KEY\",\"base\":\"https://rpc.ankr.com/base/$ANKR_KEY\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' @@ -101,7 +102,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ vars.GOV_NETWORK }}" - ethereum_url: "${{ fromJSON('{\"linea\":\"https://rpc.ankr.com/linea/${ANKR_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://mantle-mainnet.infura.io/v3/$INFURA_KEY\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/$INFURA_KEY\",\"sepolia\":\"https://sepolia.infura.io/v3/$INFURA_KEY\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://arbitrum-mainnet.infura.io/v3/$INFURA_KEY\"}')[vars.GOV_NETWORK] }}" + ethereum_url: "${{ fromJSON('{\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\"}')[vars.GOV_NETWORK] }}" port: 8685 if: github.event.inputs.eth_pk == '' && vars.GOV_NETWORK != '' && github.event.inputs.network != vars.GOV_NETWORK diff --git a/.github/workflows/prepare-migration.yaml b/.github/workflows/prepare-migration.yaml index 9f42b2577..152c7d125 100644 --- a/.github/workflows/prepare-migration.yaml +++ b/.github/workflows/prepare-migration.yaml @@ -45,6 +45,7 @@ jobs: MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} + LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} GOV_NETWORK: ${{ vars.GOV_NETWORK }} steps: - name: Get governance network @@ -62,7 +63,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"linea\":\"https://rpc.ankr.com/linea/${ANKR_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/$_TENDERLY_KEY_RONIN\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://rpc.ankr.com/mantle/$ANKR_KEY\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://rpc.ankr.com/eth/$ANKR_KEY\",\"sepolia\":\"https://sepolia.infura.io/v3/$INFURA_KEY\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://rpc.ankr.com/arbitrum/$ANKR_KEY\",\"base\":\"https://rpc.ankr.com/base/$ANKR_KEY\",\"scroll\":\"https://rpc.scroll.io\"}')[inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"https://omniscient-hardworking-gas.linea-mainnet.quiknode.pro/${LINEA_QUICKNODE_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://rpc.ankr.com/mantle/${ANKR_KEY}\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://rpc.ankr.com/arbitrum/$ANKR_KEY\",\"base\":\"https://rpc.ankr.com/base/$ANKR_KEY\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' @@ -71,7 +72,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ vars.GOV_NETWORK }}" - ethereum_url: "${{ fromJSON('{\"mainnet\":\"https://rpc.ankr.com/eth/$ANKR_KEY\",\"sepolia\":\"https://sepolia.infura.io/v3/$INFURA_KEY\"}')[vars.GOV_NETWORK] }}" + ethereum_url: "${{ fromJSON('{\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\"}')[vars.GOV_NETWORK] }}" port: 8685 if: github.event.inputs.eth_pk == '' && vars.GOV_NETWORK != '' && github.event.inputs.network != vars.GOV_NETWORK diff --git a/.github/workflows/run-contract-linter.yaml b/.github/workflows/run-contract-linter.yaml index cc327d696..ed0e23eee 100644 --- a/.github/workflows/run-contract-linter.yaml +++ b/.github/workflows/run-contract-linter.yaml @@ -17,6 +17,7 @@ jobs: MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} + LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/run-coverage.yaml b/.github/workflows/run-coverage.yaml index 56daa7969..484362254 100644 --- a/.github/workflows/run-coverage.yaml +++ b/.github/workflows/run-coverage.yaml @@ -19,6 +19,7 @@ jobs: MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} + LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/run-eslint.yaml b/.github/workflows/run-eslint.yaml index c9424d91f..a9f542aa0 100644 --- a/.github/workflows/run-eslint.yaml +++ b/.github/workflows/run-eslint.yaml @@ -17,6 +17,7 @@ jobs: MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} + LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/run-forge-tests.yaml b/.github/workflows/run-forge-tests.yaml index 93f26c75b..f30fa465c 100644 --- a/.github/workflows/run-forge-tests.yaml +++ b/.github/workflows/run-forge-tests.yaml @@ -34,6 +34,7 @@ jobs: MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} + LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} - name: Build Comet with older solc versions run: | diff --git a/.github/workflows/run-gas-profiler.yaml b/.github/workflows/run-gas-profiler.yaml index 615b39383..821a8dafd 100644 --- a/.github/workflows/run-gas-profiler.yaml +++ b/.github/workflows/run-gas-profiler.yaml @@ -18,6 +18,7 @@ jobs: MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} + LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/run-scenarios.yaml b/.github/workflows/run-scenarios.yaml index b06e687dc..2132d38e9 100644 --- a/.github/workflows/run-scenarios.yaml +++ b/.github/workflows/run-scenarios.yaml @@ -24,6 +24,7 @@ jobs: MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} + LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} runs-on: ubuntu-latest steps: - name: Checkout repository diff --git a/.github/workflows/run-semgrep.yaml b/.github/workflows/run-semgrep.yaml index 433522f48..9259901a6 100644 --- a/.github/workflows/run-semgrep.yaml +++ b/.github/workflows/run-semgrep.yaml @@ -24,6 +24,7 @@ jobs: MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} + LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} container: # A Docker image with Semgrep installed. Do not change this. image: returntocorp/semgrep diff --git a/.github/workflows/run-unit-tests.yaml b/.github/workflows/run-unit-tests.yaml index b9cb8fe63..4f4da3c4c 100644 --- a/.github/workflows/run-unit-tests.yaml +++ b/.github/workflows/run-unit-tests.yaml @@ -21,6 +21,7 @@ jobs: MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} + LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/contracts/test/CometModified.sol b/contracts/test/CometModified.sol index 9639c5692..ddf138a5c 100644 --- a/contracts/test/CometModified.sol +++ b/contracts/test/CometModified.sol @@ -1,16 +1,16 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; -import "../Comet.sol"; +import "../CometWithExtendedAssetList.sol"; /** * @title A modified version of Compound Comet * @notice This is solely used for testing upgrades * @author Compound */ -contract CometModified is Comet { +contract CometModified is CometWithExtendedAssetList { - constructor(Configuration memory config) Comet(config) {} + constructor(Configuration memory config) CometWithExtendedAssetList(config) {} /** * @notice Initialize storage for a liquidator diff --git a/deployments/hardhat/dai/deploy.ts b/deployments/hardhat/dai/deploy.ts index bdc4548d7..0d6bde034 100644 --- a/deployments/hardhat/dai/deploy.ts +++ b/deployments/hardhat/dai/deploy.ts @@ -63,7 +63,7 @@ export default async function deploy(deploymentManager: DeploymentManager, deplo const deployed = await deployComet(deploymentManager, deploySpec, { baseTokenPriceFeed: daiPriceFeed.address, assetConfigs: [assetConfig0, assetConfig1], - }); + }, true); const { rewards } = deployed; await deploymentManager.idempotent( diff --git a/deployments/mainnet/weth/deploy.ts b/deployments/mainnet/weth/deploy.ts index e0bbd2f34..5be4d6c89 100644 --- a/deployments/mainnet/weth/deploy.ts +++ b/deployments/mainnet/weth/deploy.ts @@ -38,7 +38,7 @@ export default async function deploy(deploymentManager: DeploymentManager, deplo // Import shared contracts from cUSDCv3 const cometAdmin = await deploymentManager.fromDep('cometAdmin', 'mainnet', 'usdc'); - const cometFactory = await deploymentManager.fromDep('cometFactory', 'mainnet', 'usdc'); + // const cometFactory = await deploymentManager.fromDep('cometFactory', 'mainnet', 'usdc'); const $configuratorImpl = await deploymentManager.fromDep('configurator:implementation', 'mainnet', 'usdc'); const configurator = await deploymentManager.fromDep('configurator', 'mainnet', 'usdc'); const rewards = await deploymentManager.fromDep('rewards', 'mainnet', 'usdc'); diff --git a/deployments/mainnet/wsteth/deploy.ts b/deployments/mainnet/wsteth/deploy.ts index dfb9e1977..a9874eb9d 100644 --- a/deployments/mainnet/wsteth/deploy.ts +++ b/deployments/mainnet/wsteth/deploy.ts @@ -48,7 +48,7 @@ export default async function deploy(deploymentManager: DeploymentManager, deplo // Import shared contracts from cUSDCv3 const cometAdmin = await deploymentManager.fromDep('cometAdmin', 'mainnet', 'usdc'); - const cometFactory = await deploymentManager.fromDep('cometFactory', 'mainnet', 'usdt'); + // const cometFactory = await deploymentManager.fromDep('cometFactory', 'mainnet', 'usdt'); const $configuratorImpl = await deploymentManager.fromDep('configurator:implementation', 'mainnet', 'usdc'); const configurator = await deploymentManager.fromDep('configurator', 'mainnet', 'usdc'); const rewards = await deploymentManager.fromDep('rewards', 'mainnet', 'usdc'); diff --git a/deployments/sepolia/usdc/deploy.ts b/deployments/sepolia/usdc/deploy.ts index 039afb96b..c61cffd82 100644 --- a/deployments/sepolia/usdc/deploy.ts +++ b/deployments/sepolia/usdc/deploy.ts @@ -24,7 +24,7 @@ async function deployContracts(deploymentManager: DeploymentManager, deploySpec: const WETH = await deploymentManager.clone('WETH', clone.weth, []); // Deploy all Comet-related contracts - const deployed = await deployComet(deploymentManager, deploySpec); + const deployed = await deployComet(deploymentManager, deploySpec, {}, true); const { rewards } = deployed; // Deploy Bulker diff --git a/deployments/sepolia/weth/deploy.ts b/deployments/sepolia/weth/deploy.ts index e7a0d15cb..beabff24c 100644 --- a/deployments/sepolia/weth/deploy.ts +++ b/deployments/sepolia/weth/deploy.ts @@ -106,7 +106,7 @@ async function deployContracts(deploymentManager: DeploymentManager, deploySpec: ); // Deploy all Comet-related contracts - const deployed = await deployComet(deploymentManager, deploySpec); + const deployed = await deployComet(deploymentManager, deploySpec, {}, true); const { comet } = deployed; // Deploy Bulker diff --git a/hardhat.config.ts b/hardhat.config.ts index a1a361dc4..53398d315 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -69,6 +69,7 @@ const { GOV_NETWORK_PROVIDER = '', GOV_NETWORK = '', UNICHAIN_QUICKNODE_KEY = '', + LINEA_QUICKNODE_KEY = '', REMOTE_ACCOUNTS = '' } = process.env; @@ -93,7 +94,8 @@ export function requireEnv(varName, msg?: string): string { 'SNOWTRACE_KEY', 'INFURA_KEY', 'ANKR_KEY', - 'UNICHAIN_QUICKNODE_KEY' + 'UNICHAIN_QUICKNODE_KEY', + 'LINEA_QUICKNODE_KEY' ].map((v) => requireEnv(v)); // Networks @@ -160,7 +162,7 @@ export const networkConfigs: NetworkConfig[] = [ { network: 'linea', chainId: 59144, - url: `https://rpc.ankr.com/linea/${ANKR_KEY}`, + url: `https://omniscient-hardworking-gas.linea-mainnet.quiknode.pro/${LINEA_QUICKNODE_KEY}/`, }, { network: 'base', @@ -187,11 +189,6 @@ export const networkConfigs: NetworkConfig[] = [ chainId: 534352, url: 'https://rpc.scroll.io', }, - { - network: 'linea', - chainId: 59144, - url: `https://rpc.ankr.com/linea/${ANKR_KEY}`, - }, ]; function getDefaultProviderURL(network: string) { @@ -267,12 +264,33 @@ const config: HardhatUserConfig = { allowUnlimitedContractSize: true, //hardfork: 'london', chains: networkConfigs.reduce((acc, { chainId }) => { - if (chainId === 1) return acc; + if (chainId === 1) { + acc[chainId] = { + hardforkHistory: { + berlin: 1, + london: 2, + shanghai: 3, + cancun: 4, + } + }; + return acc; + } + if (chainId === 10) { + acc[chainId] = { + hardforkHistory: { + berlin: 1, + london: 2, + } + }; + return acc; + } if (chainId === 59144) { acc[chainId] = { hardforkHistory: { berlin: 1, london: 2, + shanghai: 3, + cancun: 4, } }; return acc; diff --git a/plugins/scenario/utils/hreForBase.ts b/plugins/scenario/utils/hreForBase.ts index 03665c3d4..2328074c7 100644 --- a/plugins/scenario/utils/hreForBase.ts +++ b/plugins/scenario/utils/hreForBase.ts @@ -62,10 +62,11 @@ export async function nonForkedHreForBase(base: ForkSpec): Promise { @@ -97,6 +104,8 @@ export async function forkedHreForBase(base: ForkSpec): Promise await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, getConfigForScenario(ctx).supplyCollateral), - tokenBalances: async (ctx) => ( + filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, getConfigForScenario(ctx, i).supplyCollateral), + tokenBalances: async (ctx) => ( { - albert: { [`$asset${i}`]: getConfigForScenario(ctx).supplyCollateral } + albert: { [`$asset${i}`]: getConfigForScenario(ctx, i).supplyCollateral } } ), }, @@ -100,10 +100,10 @@ for (let i = 0; i < MAX_ASSETS; i++) { scenario( `Comet#supplyFrom > collateral asset ${i}`, { - filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, getConfigForScenario(ctx).supplyCollateral), + filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, getConfigForScenario(ctx, i).supplyCollateral), tokenBalances: async (ctx) => ( { - albert: { [`$asset${i}`]: getConfigForScenario(ctx).supplyCollateral } + albert: { [`$asset${i}`]: getConfigForScenario(ctx, i).supplyCollateral } } ), }, diff --git a/scenario/TransferScenario.ts b/scenario/TransferScenario.ts index 9c4cfc390..e5c94310b 100644 --- a/scenario/TransferScenario.ts +++ b/scenario/TransferScenario.ts @@ -11,11 +11,11 @@ async function testTransferCollateral(context: CometContext, assetNum: number): const collateralAsset = context.getAssetByAddress(assetAddress); // Albert transfers 50 units of collateral to Betty - const toTransfer = scale.toBigInt() * BigInt(getConfigForScenario(context).supplyCollateral) / 2n; + const toTransfer = scale.toBigInt() * BigInt(getConfigForScenario(context, assetNum).transferCollateral) / 2n; const txn = await albert.transferAsset({ dst: betty.address, asset: collateralAsset.address, amount: toTransfer }); - expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(scale.mul(BigInt(getConfigForScenario(context).supplyCollateral) / 2n)); - expect(await comet.collateralBalanceOf(betty.address, collateralAsset.address)).to.be.equal(scale.mul(BigInt(getConfigForScenario(context).supplyCollateral) / 2n)); + expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(scale.mul(BigInt(getConfigForScenario(context, assetNum).transferCollateral) / 2n)); + expect(await comet.collateralBalanceOf(betty.address, collateralAsset.address)).to.be.equal(scale.mul(BigInt(getConfigForScenario(context, assetNum).transferCollateral) / 2n)); return txn; // return txn to measure gas } @@ -29,11 +29,11 @@ async function testTransferFromCollateral(context: CometContext, assetNum: numbe await albert.allow(charles, true); // Charles transfers 50 units of collateral from Albert to Betty - const toTransfer = scale.toBigInt() * BigInt(getConfigForScenario(context).supplyCollateral) / 2n; + const toTransfer = scale.toBigInt() * BigInt(getConfigForScenario(context, assetNum).transferCollateral) / 2n; const txn = await charles.transferAssetFrom({ src: albert.address, dst: betty.address, asset: collateralAsset.address, amount: toTransfer }); - expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(scale.mul(BigInt(getConfigForScenario(context).supplyCollateral) / 2n)); - expect(await comet.collateralBalanceOf(betty.address, collateralAsset.address)).to.be.equal(scale.mul(BigInt(getConfigForScenario(context).supplyCollateral) / 2n)); + expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(scale.mul(BigInt(getConfigForScenario(context, assetNum).transferCollateral) / 2n)); + expect(await comet.collateralBalanceOf(betty.address, collateralAsset.address)).to.be.equal(scale.mul(BigInt(getConfigForScenario(context, assetNum).transferCollateral) / 2n)); return txn; // return txn to measure gas } @@ -42,10 +42,10 @@ for (let i = 0; i < MAX_ASSETS; i++) { scenario( `Comet#transfer > collateral asset ${i}, enough balance`, { - filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, getConfigForScenario(ctx).transferCollateral), + filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, getConfigForScenario(ctx, i).transferCollateral), cometBalances: async (ctx) => ( { - albert: { [`$asset${i}`]: getConfigForScenario(ctx).transferCollateral } + albert: { [`$asset${i}`]: getConfigForScenario(ctx, i).transferCollateral } } ), }, @@ -59,10 +59,10 @@ for (let i = 0; i < MAX_ASSETS; i++) { scenario( `Comet#transferFrom > collateral asset ${i}, enough balance`, { - filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, getConfigForScenario(ctx).transferCollateral), + filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, getConfigForScenario(ctx, i).transferCollateral), cometBalances: async (ctx) => ( { - albert: { [`$asset${i}`]: getConfigForScenario(ctx).transferCollateral } + albert: { [`$asset${i}`]: getConfigForScenario(ctx, i).transferCollateral } } ), }, diff --git a/scenario/WithdrawScenario.ts b/scenario/WithdrawScenario.ts index dba5ef6d6..d04b2d02e 100644 --- a/scenario/WithdrawScenario.ts +++ b/scenario/WithdrawScenario.ts @@ -12,12 +12,12 @@ async function testWithdrawCollateral(context: CometContext, assetNum: number): const scale = scaleBN.toBigInt(); expect(await collateralAsset.balanceOf(albert.address)).to.be.equal(0n); - expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(BigInt(getConfigForScenario(context).supplyCollateral) * scale); + expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(BigInt(getConfigForScenario(context, assetNum).withdrawCollateral) * scale); // Albert withdraws 100 units of collateral from Comet - const txn = await albert.withdrawAsset({ asset: collateralAsset.address, amount: BigInt(getConfigForScenario(context).supplyCollateral) * scale }); + const txn = await albert.withdrawAsset({ asset: collateralAsset.address, amount: BigInt(getConfigForScenario(context, assetNum).withdrawCollateral) * scale }); - expect(await collateralAsset.balanceOf(albert.address)).to.be.equal(BigInt(getConfigForScenario(context).supplyCollateral) * scale); + expect(await collateralAsset.balanceOf(albert.address)).to.be.equal(BigInt(getConfigForScenario(context, assetNum).withdrawCollateral) * scale); expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(0n); return txn; // return txn to measure gas @@ -31,14 +31,14 @@ async function testWithdrawFromCollateral(context: CometContext, assetNum: numbe const scale = scaleBN.toBigInt(); expect(await collateralAsset.balanceOf(betty.address)).to.be.equal(0n); - expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(BigInt(getConfigForScenario(context).supplyCollateral) * scale); + expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(BigInt(getConfigForScenario(context, assetNum).withdrawCollateral) * scale); await albert.allow(betty, true); // Betty withdraws 1000 units of collateral from Albert - const txn = await betty.withdrawAssetFrom({ src: albert.address, dst: betty.address, asset: collateralAsset.address, amount: BigInt(getConfigForScenario(context).supplyCollateral) * scale }); + const txn = await betty.withdrawAssetFrom({ src: albert.address, dst: betty.address, asset: collateralAsset.address, amount: BigInt(getConfigForScenario(context, assetNum).withdrawCollateral) * scale }); - expect(await collateralAsset.balanceOf(betty.address)).to.be.equal(BigInt(getConfigForScenario(context).supplyCollateral) * scale); + expect(await collateralAsset.balanceOf(betty.address)).to.be.equal(BigInt(getConfigForScenario(context, assetNum).withdrawCollateral) * scale); expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(0n); return txn; // return txn to measure gas diff --git a/scenario/constraints/TokenBalanceConstraint.ts b/scenario/constraints/TokenBalanceConstraint.ts index 6dd422999..f540fdcea 100644 --- a/scenario/constraints/TokenBalanceConstraint.ts +++ b/scenario/constraints/TokenBalanceConstraint.ts @@ -34,6 +34,7 @@ export class TokenBalanceConstraint ${governanceDeploymentManager.network}`); let proposal; switch (bridgeNetwork) { case 'base': diff --git a/scenario/utils/scenarioHelper.ts b/scenario/utils/scenarioHelper.ts index 2f4589b5c..ff61bf055 100644 --- a/scenario/utils/scenarioHelper.ts +++ b/scenario/utils/scenarioHelper.ts @@ -32,7 +32,7 @@ const config = { supplyCollateral: 100 }; -export function getConfigForScenario(ctx: CometContext) { +export function getConfigForScenario(ctx: CometContext, i?: number) { if (ctx.world.base.network === 'mainnet' && ctx.world.base.deployment === 'wbtc') { config.bulkerBase = 200; config.bulkerAsset = 400; @@ -74,6 +74,15 @@ export function getConfigForScenario(ctx: CometContext) { config.interestSeconds = 110; } + if (ctx.world.base.network === 'base' && ctx.world.base.deployment === 'usdc') { + if(i == 4) { + config.supplyCollateral = 2; + config.transferCollateral = 2; + config.withdrawCollateral = 2; + } + } + + if (ctx.world.base.network === 'base' && ctx.world.base.deployment === 'usds') { config.liquidationBase2 = 100; config.liquidationAsset1 = 99; @@ -83,16 +92,37 @@ export function getConfigForScenario(ctx: CometContext) { config.liquidationBase = 1000; } + if (ctx.world.base.network === 'optimism' && ctx.world.base.deployment === 'usdc') { + config.bulkerAsset = 10000; + config.bulkerAsset1 = 10000; + config.transferAsset1 = 10000; + config.withdrawAsset = 7000; + } + + if (ctx.world.base.network === 'optimism' && ctx.world.base.deployment === 'usdt') { + config.bulkerAsset = 10000; + config.bulkerAsset1 = 10000; + config.transferAsset1 = 10000; + config.withdrawAsset = 7000; + } + if (ctx.world.base.network === 'optimism' && ctx.world.base.deployment === 'weth') { config.liquidationBase = 1000; } if (ctx.world.base.network === 'arbitrum' && ctx.world.base.deployment === 'usdc') { - config.withdrawAsset = 3500; + config.bulkerAsset = 10000; + config.bulkerAsset1 = 10000; + config.withdrawAsset = 7000; + config.transferAsset = 500000; + config.transferBase = 100; } if (ctx.world.base.network === 'arbitrum' && ctx.world.base.deployment === 'usdt') { - config.withdrawAsset = 3500; + config.withdrawAsset = 7000; + config.bulkerAsset = 10000; + config.bulkerAsset1 = 10000; + config.transferAsset1 = 10000; } if (ctx.world.base.network === 'arbitrum' && ctx.world.base.deployment === 'usdc.e') { diff --git a/src/deploy/index.ts b/src/deploy/index.ts index 789b25920..6d9de2386 100644 --- a/src/deploy/index.ts +++ b/src/deploy/index.ts @@ -144,6 +144,9 @@ export const WHALES = { '0x56CC5A9c0788e674f17F7555dC8D3e2F1C0313C0', // wUSDM whale '0x8437d7C167dFB82ED4Cb79CD44B7a32A1dd95c77', // weETH whale '0x6b030Ff3FB9956B1B69f475B77aE0d3Cf2CC5aFa', // rsETH whale + '0x186cF879186986A20aADFb7eAD50e3C20cb26CeC', // tBTC whale + '0x620Fe90b1EAcaEa936ea199e7B05F998CA65836a', // tBTC whale + '0x54b5569deC8A6A8AE61A36Fd34e5c8945810db8b', // tBTC whale ], base: [ '0x6D3c5a4a7aC4B1428368310E4EC3bB1350d01455', // USDbC whale diff --git a/tasks/deployment_manager/task.ts b/tasks/deployment_manager/task.ts index 0caa14516..d4378cb64 100644 --- a/tasks/deployment_manager/task.ts +++ b/tasks/deployment_manager/task.ts @@ -32,7 +32,8 @@ async function runMigration( overwrite: boolean, tenderly: boolean = false ) { - deploymentManager.cleanCache(); + await deploymentManager.cleanCache(); + console.log(`Reading artifact for migration: ${migration.name}`); let artifact: T = await deploymentManager.readArtifact(migration); if (prepare) { if (artifact && !overwrite) { @@ -53,11 +54,13 @@ async function runMigration( } if (enact) { + console.log('Running enactment step...'); const { governor, timelock } = await govDeploymentManager.getContracts(); - + + console.log('Running enact...'); await migration.actions.enact( deploymentManager, govDeploymentManager, diff --git a/test/configurator-test.ts b/test/configurator-test.ts index 07a6b724f..1aa46d439 100644 --- a/test/configurator-test.ts +++ b/test/configurator-test.ts @@ -140,7 +140,7 @@ describe('configurator', function () { describe('configuration setters', function () { it('sets factory and deploys Comet using new factory', async () => { - const { configurator, configuratorProxy, proxyAdmin, cometFactory, cometProxy } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometFactoryWithExtendedAssetList: cometFactory, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); // Deploy modified CometFactory const CometModifiedFactoryFactory = (await ethers.getContractFactory('CometModifiedFactory')) as CometModifiedFactory__factory; diff --git a/test/helpers.ts b/test/helpers.ts index 710b5adb9..de826ea29 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -8,6 +8,7 @@ import { BaseBulker__factory, CometExt, CometExt__factory, + CometExtAssetList, CometExtAssetList__factory, CometHarness__factory, CometHarnessInterface as Comet, @@ -27,6 +28,8 @@ import { CometProxyAdmin__factory, CometFactory, CometFactory__factory, + CometFactoryWithExtendedAssetList, + CometFactoryWithExtendedAssetList__factory, Configurator, Configurator__factory, CometHarnessInterface, @@ -99,6 +102,7 @@ export type Protocol = { governor: SignerWithAddress; pauseGuardian: SignerWithAddress; extensionDelegate: CometExt; + extensionDelegateAssetList: CometExtAssetList; users: SignerWithAddress[]; base: string; reward: string; @@ -119,7 +123,9 @@ export type ConfiguratorAndProtocol = { configuratorProxy: ConfiguratorProxy; proxyAdmin: CometProxyAdmin; cometFactory: CometFactory; + cometFactoryWithExtendedAssetList: CometFactoryWithExtendedAssetList; cometProxy: TransparentUpgradeableProxy; + cometProxyWithExtendedAssetList: TransparentUpgradeableProxy; } & Protocol; export type RewardsOpts = { @@ -370,6 +376,7 @@ export async function makeProtocol(opts: ProtocolOpts = {}): Promise { governor, pauseGuardian, extensionDelegate, + extensionDelegateAssetList: extensionDelegateAssetList as CometExtAssetList, users, base, reward, @@ -390,6 +397,7 @@ export async function makeConfigurator(opts: ProtocolOpts = {}): Promise Date: Wed, 12 Nov 2025 14:16:50 +0200 Subject: [PATCH 14/65] fix: change base rpc --- .github/workflows/deploy-market.yaml | 2 +- .github/workflows/enact-migration.yaml | 2 +- .github/workflows/prepare-migration.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy-market.yaml b/.github/workflows/deploy-market.yaml index bb1c424dc..dc0cba639 100644 --- a/.github/workflows/deploy-market.yaml +++ b/.github/workflows/deploy-market.yaml @@ -49,7 +49,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"linea\":\"https://omniscient-hardworking-gas.linea-mainnet.quiknode.pro/${LINEA_QUICKNODE_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://rpc.ankr.com/mantle/${ANKR_KEY}\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://rpc.ankr.com/arbitrum/$ANKR_KEY\",\"base\":\"https://rpc.ankr.com/base/$ANKR_KEY\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"https://omniscient-hardworking-gas.linea-mainnet.quiknode.pro/${LINEA_QUICKNODE_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://rpc.ankr.com/mantle/${ANKR_KEY}\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://rpc.ankr.com/arbitrum/$ANKR_KEY\",\"base\":\"https://mainnet.base.org\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' diff --git a/.github/workflows/enact-migration.yaml b/.github/workflows/enact-migration.yaml index 67468c57c..fc2cc94f5 100644 --- a/.github/workflows/enact-migration.yaml +++ b/.github/workflows/enact-migration.yaml @@ -93,7 +93,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"linea\":\"https://omniscient-hardworking-gas.linea-mainnet.quiknode.pro/${LINEA_QUICKNODE_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://rpc.ankr.com/mantle/${ANKR_KEY}\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://rpc.ankr.com/arbitrum/$ANKR_KEY\",\"base\":\"https://rpc.ankr.com/base/$ANKR_KEY\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"https://omniscient-hardworking-gas.linea-mainnet.quiknode.pro/${LINEA_QUICKNODE_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://rpc.ankr.com/mantle/${ANKR_KEY}\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://rpc.ankr.com/arbitrum/$ANKR_KEY\",\"base\":\"https://mainnet.base.org\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' diff --git a/.github/workflows/prepare-migration.yaml b/.github/workflows/prepare-migration.yaml index 152c7d125..c26b7c06e 100644 --- a/.github/workflows/prepare-migration.yaml +++ b/.github/workflows/prepare-migration.yaml @@ -63,7 +63,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"linea\":\"https://omniscient-hardworking-gas.linea-mainnet.quiknode.pro/${LINEA_QUICKNODE_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://rpc.ankr.com/mantle/${ANKR_KEY}\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://rpc.ankr.com/arbitrum/$ANKR_KEY\",\"base\":\"https://rpc.ankr.com/base/$ANKR_KEY\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"https://omniscient-hardworking-gas.linea-mainnet.quiknode.pro/${LINEA_QUICKNODE_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://rpc.ankr.com/mantle/${ANKR_KEY}\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://rpc.ankr.com/arbitrum/$ANKR_KEY\",\"base\":\"https://mainnet.base.org\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' From 68f6aabc77b429dde7d35c61fbab00f2b8db4b10 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Fri, 14 Nov 2025 17:05:17 +0200 Subject: [PATCH 15/65] fix: change rpc --- .github/workflows/deploy-market.yaml | 6 +++--- .github/workflows/enact-migration.yaml | 6 +++--- .github/workflows/prepare-migration.yaml | 6 +++--- .github/workflows/run-contract-linter.yaml | 4 ++-- .github/workflows/run-coverage.yaml | 4 ++-- .github/workflows/run-eslint.yaml | 4 ++-- .github/workflows/run-forge-tests.yaml | 4 ++-- .github/workflows/run-gas-profiler.yaml | 4 ++-- .github/workflows/run-scenarios.yaml | 4 ++-- .github/workflows/run-semgrep.yaml | 4 ++-- .github/workflows/run-unit-tests.yaml | 4 ++-- hardhat.config.ts | 15 ++++++++------- plugins/import/blockscout.ts | 2 +- scenario/utils/scenarioHelper.ts | 7 +++++-- 14 files changed, 39 insertions(+), 35 deletions(-) diff --git a/.github/workflows/deploy-market.yaml b/.github/workflows/deploy-market.yaml index dc0cba639..21854a310 100644 --- a/.github/workflows/deploy-market.yaml +++ b/.github/workflows/deploy-market.yaml @@ -41,15 +41,15 @@ jobs: MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} - UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} - LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} + UNICHAIN_QUICKNODE_LINK: ${{ secrets.UNICHAIN_QUICKNODE_LINK }} + LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} steps: - name: Seacrest uses: hayesgm/seacrest@af229b0a00b73cb6fa9940a836a62fa3b918fd77 with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"linea\":\"https://omniscient-hardworking-gas.linea-mainnet.quiknode.pro/${LINEA_QUICKNODE_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://rpc.ankr.com/mantle/${ANKR_KEY}\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://rpc.ankr.com/arbitrum/$ANKR_KEY\",\"base\":\"https://mainnet.base.org\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"https://rpc.ankr.com/mantle/${ANKR_KEY}\",\"optimism\":\"https://mainnet.optimism.io\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://rpc.ankr.com/arbitrum/$ANKR_KEY\",\"base\":\"https://mainnet.base.org\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' diff --git a/.github/workflows/enact-migration.yaml b/.github/workflows/enact-migration.yaml index fc2cc94f5..d5e72f430 100644 --- a/.github/workflows/enact-migration.yaml +++ b/.github/workflows/enact-migration.yaml @@ -64,8 +64,8 @@ jobs: SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} _TENDERLY_KEY_POLYGON: ${{ secrets._TENDERLY_KEY_POLYGON }} - UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} - LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} + UNICHAIN_QUICKNODE_LINK: ${{ secrets.UNICHAIN_QUICKNODE_LINK }} + LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} GOV_NETWORK: ${{ vars.GOV_NETWORK }} steps: - name: Get governance network @@ -93,7 +93,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"linea\":\"https://omniscient-hardworking-gas.linea-mainnet.quiknode.pro/${LINEA_QUICKNODE_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://rpc.ankr.com/mantle/${ANKR_KEY}\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://rpc.ankr.com/arbitrum/$ANKR_KEY\",\"base\":\"https://mainnet.base.org\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"https://rpc.ankr.com/mantle/${ANKR_KEY}\",\"optimism\":\"https://mainnet.optimism.io\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://rpc.ankr.com/arbitrum/$ANKR_KEY\",\"base\":\"https://mainnet.base.org\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' diff --git a/.github/workflows/prepare-migration.yaml b/.github/workflows/prepare-migration.yaml index c26b7c06e..de5e17383 100644 --- a/.github/workflows/prepare-migration.yaml +++ b/.github/workflows/prepare-migration.yaml @@ -44,8 +44,8 @@ jobs: OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} - UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} - LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} + UNICHAIN_QUICKNODE_LINK: ${{ secrets.UNICHAIN_QUICKNODE_LINK }} + LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} GOV_NETWORK: ${{ vars.GOV_NETWORK }} steps: - name: Get governance network @@ -63,7 +63,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"linea\":\"https://omniscient-hardworking-gas.linea-mainnet.quiknode.pro/${LINEA_QUICKNODE_KEY}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}\",\"mantle\":\"https://rpc.ankr.com/mantle/${ANKR_KEY}\",\"optimism\":\"https://rpc.ankr.com/optimism/$ANKR_KEY\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://rpc.ankr.com/arbitrum/$ANKR_KEY\",\"base\":\"https://mainnet.base.org\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"https://rpc.ankr.com/mantle/${ANKR_KEY}\",\"optimism\":\"https://mainnet.optimism.io\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://rpc.ankr.com/arbitrum/$ANKR_KEY\",\"base\":\"https://mainnet.base.org\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' diff --git a/.github/workflows/run-contract-linter.yaml b/.github/workflows/run-contract-linter.yaml index ed0e23eee..f106d9d0d 100644 --- a/.github/workflows/run-contract-linter.yaml +++ b/.github/workflows/run-contract-linter.yaml @@ -16,8 +16,8 @@ jobs: OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} - UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} - LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} + UNICHAIN_QUICKNODE_LINK: ${{ secrets.UNICHAIN_QUICKNODE_LINK }} + LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/run-coverage.yaml b/.github/workflows/run-coverage.yaml index 484362254..157aea0a7 100644 --- a/.github/workflows/run-coverage.yaml +++ b/.github/workflows/run-coverage.yaml @@ -18,8 +18,8 @@ jobs: OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} - UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} - LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} + UNICHAIN_QUICKNODE_LINK: ${{ secrets.UNICHAIN_QUICKNODE_LINK }} + LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/run-eslint.yaml b/.github/workflows/run-eslint.yaml index a9f542aa0..ea286eb26 100644 --- a/.github/workflows/run-eslint.yaml +++ b/.github/workflows/run-eslint.yaml @@ -16,8 +16,8 @@ jobs: OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} - UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} - LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} + UNICHAIN_QUICKNODE_LINK: ${{ secrets.UNICHAIN_QUICKNODE_LINK }} + LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/run-forge-tests.yaml b/.github/workflows/run-forge-tests.yaml index f30fa465c..1498bef16 100644 --- a/.github/workflows/run-forge-tests.yaml +++ b/.github/workflows/run-forge-tests.yaml @@ -33,8 +33,8 @@ jobs: OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} - UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} - LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} + UNICHAIN_QUICKNODE_LINK: ${{ secrets.UNICHAIN_QUICKNODE_LINK }} + LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} - name: Build Comet with older solc versions run: | diff --git a/.github/workflows/run-gas-profiler.yaml b/.github/workflows/run-gas-profiler.yaml index 821a8dafd..b28e6a7e3 100644 --- a/.github/workflows/run-gas-profiler.yaml +++ b/.github/workflows/run-gas-profiler.yaml @@ -17,8 +17,8 @@ jobs: OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} - UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} - LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} + UNICHAIN_QUICKNODE_LINK: ${{ secrets.UNICHAIN_QUICKNODE_LINK }} + LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/run-scenarios.yaml b/.github/workflows/run-scenarios.yaml index 2132d38e9..2988d9ada 100644 --- a/.github/workflows/run-scenarios.yaml +++ b/.github/workflows/run-scenarios.yaml @@ -23,8 +23,8 @@ jobs: OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} - UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} - LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} + UNICHAIN_QUICKNODE_LINK: ${{ secrets.UNICHAIN_QUICKNODE_LINK }} + LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} runs-on: ubuntu-latest steps: - name: Checkout repository diff --git a/.github/workflows/run-semgrep.yaml b/.github/workflows/run-semgrep.yaml index 9259901a6..b5efe0c3e 100644 --- a/.github/workflows/run-semgrep.yaml +++ b/.github/workflows/run-semgrep.yaml @@ -23,8 +23,8 @@ jobs: OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} - UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} - LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} + UNICHAIN_QUICKNODE_LINK: ${{ secrets.UNICHAIN_QUICKNODE_LINK }} + LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} container: # A Docker image with Semgrep installed. Do not change this. image: returntocorp/semgrep diff --git a/.github/workflows/run-unit-tests.yaml b/.github/workflows/run-unit-tests.yaml index 4f4da3c4c..acedebeea 100644 --- a/.github/workflows/run-unit-tests.yaml +++ b/.github/workflows/run-unit-tests.yaml @@ -20,8 +20,8 @@ jobs: OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} - UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} - LINEA_QUICKNODE_KEY: ${{ secrets.LINEA_QUICKNODE_KEY }} + UNICHAIN_QUICKNODE_LINK: ${{ secrets.UNICHAIN_QUICKNODE_LINK }} + LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/hardhat.config.ts b/hardhat.config.ts index 53398d315..91be9c8ec 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -61,6 +61,7 @@ const { ETHERSCAN_KEY, SNOWTRACE_KEY, ANKR_KEY, + INFURA_KEY, _TENDERLY_KEY_RONIN, _TENDERLY_KEY_POLYGON, MNEMONIC = 'myth like woof scare over problem client lizard pioneer submit female collect', @@ -68,8 +69,8 @@ const { NETWORK_PROVIDER = '', GOV_NETWORK_PROVIDER = '', GOV_NETWORK = '', - UNICHAIN_QUICKNODE_KEY = '', - LINEA_QUICKNODE_KEY = '', + UNICHAIN_QUICKNODE_LINK = '', + LINEA_QUICKNODE_LINK = '', REMOTE_ACCOUNTS = '' } = process.env; @@ -94,8 +95,8 @@ export function requireEnv(varName, msg?: string): string { 'SNOWTRACE_KEY', 'INFURA_KEY', 'ANKR_KEY', - 'UNICHAIN_QUICKNODE_KEY', - 'LINEA_QUICKNODE_KEY' + 'UNICHAIN_QUICKNODE_LINK', + 'LINEA_QUICKNODE_LINK' ].map((v) => requireEnv(v)); // Networks @@ -124,7 +125,7 @@ export const networkConfigs: NetworkConfig[] = [ { network: 'mainnet', chainId: 1, - url: `https://rpc.ankr.com/eth/${ANKR_KEY}` + url: `https://mainnet.infura.io/v3/${INFURA_KEY}` }, { network: 'sepolia', @@ -157,12 +158,12 @@ export const networkConfigs: NetworkConfig[] = [ { network: 'unichain', chainId: 130, - url: `https://multi-boldest-patina.unichain-mainnet.quiknode.pro/${UNICHAIN_QUICKNODE_KEY}`, + url: `${UNICHAIN_QUICKNODE_LINK}`, }, { network: 'linea', chainId: 59144, - url: `https://omniscient-hardworking-gas.linea-mainnet.quiknode.pro/${LINEA_QUICKNODE_KEY}/`, + url: `${LINEA_QUICKNODE_LINK}`, }, { network: 'base', diff --git a/plugins/import/blockscout.ts b/plugins/import/blockscout.ts index 092ed5418..b693c551d 100644 --- a/plugins/import/blockscout.ts +++ b/plugins/import/blockscout.ts @@ -33,7 +33,7 @@ export function getBlockscoutUrl(network: string): string { export async function getBlockscoutRPCUrl(network: string): Promise { let host = { - 'unichain': `multi-boldest-patina.unichain-mainnet.quiknode.pro/${process.env.UNICHAIN_QUICKNODE_KEY}/` + 'unichain': `${process.env.UNICHAIN_QUICKNODE_LINK}`.replace('https://', '') }[network]; if (!host) { diff --git a/scenario/utils/scenarioHelper.ts b/scenario/utils/scenarioHelper.ts index ff61bf055..d27e42ba7 100644 --- a/scenario/utils/scenarioHelper.ts +++ b/scenario/utils/scenarioHelper.ts @@ -200,15 +200,18 @@ export function getConfigForScenario(ctx: CometContext, i?: number) { } if (ctx.world.base.network === 'unichain' && ctx.world.base.deployment === 'weth') { - config.liquidationBase = 1000; + config.liquidationBase = 250; config.liquidationBase1 = 350; config.liquidationAsset = 100; config.bulkerAsset = 500; config.bulkerComet = 500; config.bulkerBorrowBase = 100; config.bulkerBorrowAsset = 50; + config.supplyCollateral = 10; + config.transferCollateral = 10; + config.withdrawCollateral = 10; config.rewardsBase = 100; - config.rewardsAsset = 1000; + config.rewardsAsset = 250; config.transferBase = 100; config.transferAsset = 500; config.transferAsset1 = 500; From d2801ea71e7811121160acd2c786b50ee184b1ec Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Mon, 17 Nov 2025 13:47:37 +0200 Subject: [PATCH 16/65] fix: replace ankr with quicknode --- .github/workflows/deploy-market.yaml | 13 +++++-- .github/workflows/enact-migration.yaml | 13 +++++-- .github/workflows/prepare-migration.yaml | 13 +++++-- .github/workflows/run-contract-linter.yaml | 9 ++++- .github/workflows/run-coverage.yaml | 9 ++++- .github/workflows/run-eslint.yaml | 9 ++++- .github/workflows/run-gas-profiler.yaml | 9 ++++- .github/workflows/run-scenarios.yaml | 9 ++++- .github/workflows/run-semgrep.yaml | 9 ++++- .github/workflows/run-unit-tests.yaml | 9 ++++- hardhat.config.ts | 40 +++++++++++----------- 11 files changed, 106 insertions(+), 36 deletions(-) diff --git a/.github/workflows/deploy-market.yaml b/.github/workflows/deploy-market.yaml index 21854a310..77485c3cf 100644 --- a/.github/workflows/deploy-market.yaml +++ b/.github/workflows/deploy-market.yaml @@ -34,7 +34,14 @@ jobs: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} - ANKR_KEY: ${{ secrets.ANKR_KEY }} + MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} + SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} + RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} + POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} + OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} + MANTLE_QUICKNODE_LINK: ${{ secrets.MANTLE_QUICKNODE_LINK }} + BASE_QUICKNODE_LINK: ${{ secrets.BASE_QUICKNODE_LINK }} + ARBITRUM_QUICKNODE_LINK: ${{ secrets.ARBITRUM_QUICKNODE_LINK }} POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} BASESCAN_KEY: ${{ secrets.BASESCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} @@ -49,7 +56,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"https://rpc.ankr.com/mantle/${ANKR_KEY}\",\"optimism\":\"https://mainnet.optimism.io\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://rpc.ankr.com/arbitrum/$ANKR_KEY\",\"base\":\"https://mainnet.base.org\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"${RONIN_QUICKNODE_LINK}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"${MANTLE_QUICKNODE_LINK}\",\"optimism\":\"${OPTIMISM_QUICKNODE_LINK}\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"sepolia\":\"${SEPOLIA_QUICKNODE_LINK}\",\"polygon\":\"${POLYGON_QUICKNODE_LINK}\",\"arbitrum\":\"${ARBITRUM_QUICKNODE_LINK}\",\"base\":\"${BASE_QUICKNODE_LINK}\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' @@ -58,7 +65,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ vars.GOV_NETWORK }}" - ethereum_url: "${{ fromJSON('{\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\"}')[vars.GOV_NETWORK] }}" + ethereum_url: "${{ fromJSON('{\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"sepolia\":\"${SEPOLIA_QUICKNODE_LINK}\"}')[vars.GOV_NETWORK] }}" port: 8685 if: github.event.inputs.eth_pk == '' && vars.GOV_NETWORK != '' && github.event.inputs.network != vars.GOV_NETWORK diff --git a/.github/workflows/enact-migration.yaml b/.github/workflows/enact-migration.yaml index d5e72f430..4e74f6803 100644 --- a/.github/workflows/enact-migration.yaml +++ b/.github/workflows/enact-migration.yaml @@ -56,7 +56,14 @@ jobs: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} - ANKR_KEY: ${{ secrets.ANKR_KEY }} + MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} + SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} + RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} + POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} + OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} + MANTLE_QUICKNODE_LINK: ${{ secrets.MANTLE_QUICKNODE_LINK }} + BASE_QUICKNODE_LINK: ${{ secrets.BASE_QUICKNODE_LINK }} + ARBITRUM_QUICKNODE_LINK: ${{ secrets.ARBITRUM_QUICKNODE_LINK }} POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} BASESCAN_KEY: ${{ secrets.BASESCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} @@ -93,7 +100,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"https://rpc.ankr.com/mantle/${ANKR_KEY}\",\"optimism\":\"https://mainnet.optimism.io\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://rpc.ankr.com/arbitrum/$ANKR_KEY\",\"base\":\"https://mainnet.base.org\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"${RONIN_QUICKNODE_LINK}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"${MANTLE_QUICKNODE_LINK}\",\"optimism\":\"${OPTIMISM_QUICKNODE_LINK}\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"sepolia\":\"${SEPOLIA_QUICKNODE_LINK}\",\"polygon\":\"${POLYGON_QUICKNODE_LINK}\",\"arbitrum\":\"${ARBITRUM_QUICKNODE_LINK}\",\"base\":\"${BASE_QUICKNODE_LINK}\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' @@ -102,7 +109,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ vars.GOV_NETWORK }}" - ethereum_url: "${{ fromJSON('{\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\"}')[vars.GOV_NETWORK] }}" + ethereum_url: "${{ fromJSON('{\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"sepolia\":\"${SEPOLIA_QUICKNODE_LINK}\"}')[vars.GOV_NETWORK] }}" port: 8685 if: github.event.inputs.eth_pk == '' && vars.GOV_NETWORK != '' && github.event.inputs.network != vars.GOV_NETWORK diff --git a/.github/workflows/prepare-migration.yaml b/.github/workflows/prepare-migration.yaml index de5e17383..4dbf72b19 100644 --- a/.github/workflows/prepare-migration.yaml +++ b/.github/workflows/prepare-migration.yaml @@ -37,7 +37,14 @@ jobs: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} - ANKR_KEY: ${{ secrets.ANKR_KEY }} + MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} + SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} + RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} + POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} + OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} + MANTLE_QUICKNODE_LINK: ${{ secrets.MANTLE_QUICKNODE_LINK }} + BASE_QUICKNODE_LINK: ${{ secrets.BASE_QUICKNODE_LINK }} + ARBITRUM_QUICKNODE_LINK: ${{ secrets.ARBITRUM_QUICKNODE_LINK }} _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} BASESCAN_KEY: ${{ secrets.BASESCAN_KEY }} @@ -63,7 +70,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"https://rpc.ankr.com/mantle/${ANKR_KEY}\",\"optimism\":\"https://mainnet.optimism.io\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\",\"polygon\":\"https://polygon-mainnet.infura.io/v3/$INFURA_KEY\",\"arbitrum\":\"https://rpc.ankr.com/arbitrum/$ANKR_KEY\",\"base\":\"https://mainnet.base.org\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"${RONIN_QUICKNODE_LINK}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"${MANTLE_QUICKNODE_LINK}\",\"optimism\":\"${OPTIMISM_QUICKNODE_LINK}\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"sepolia\":\"${SEPOLIA_QUICKNODE_LINK}\",\"polygon\":\"${POLYGON_QUICKNODE_LINK}\",\"arbitrum\":\"${ARBITRUM_QUICKNODE_LINK}\",\"base\":\"${BASE_QUICKNODE_LINK}\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' @@ -72,7 +79,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ vars.GOV_NETWORK }}" - ethereum_url: "${{ fromJSON('{\"mainnet\":\"https://mainnet.infura.io/v3/${INFURA_KEY}\",\"sepolia\":\"https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}\"}')[vars.GOV_NETWORK] }}" + ethereum_url: "${{ fromJSON('{\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"sepolia\":\"${SEPOLIA_QUICKNODE_LINK}\"}')[vars.GOV_NETWORK] }}" port: 8685 if: github.event.inputs.eth_pk == '' && vars.GOV_NETWORK != '' && github.event.inputs.network != vars.GOV_NETWORK diff --git a/.github/workflows/run-contract-linter.yaml b/.github/workflows/run-contract-linter.yaml index f106d9d0d..e8391205c 100644 --- a/.github/workflows/run-contract-linter.yaml +++ b/.github/workflows/run-contract-linter.yaml @@ -10,7 +10,14 @@ jobs: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} - ANKR_KEY: ${{ secrets.ANKR_KEY }} + MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} + SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} + RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} + POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} + OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} + MANTLE_QUICKNODE_LINK: ${{ secrets.MANTLE_QUICKNODE_LINK }} + BASE_QUICKNODE_LINK: ${{ secrets.BASE_QUICKNODE_LINK }} + ARBITRUM_QUICKNODE_LINK: ${{ secrets.ARBITRUM_QUICKNODE_LINK }} _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} diff --git a/.github/workflows/run-coverage.yaml b/.github/workflows/run-coverage.yaml index 157aea0a7..b1a52fec8 100644 --- a/.github/workflows/run-coverage.yaml +++ b/.github/workflows/run-coverage.yaml @@ -12,7 +12,14 @@ jobs: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} - ANKR_KEY: ${{ secrets.ANKR_KEY }} + MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} + SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} + RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} + POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} + OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} + MANTLE_QUICKNODE_LINK: ${{ secrets.MANTLE_QUICKNODE_LINK }} + BASE_QUICKNODE_LINK: ${{ secrets.BASE_QUICKNODE_LINK }} + ARBITRUM_QUICKNODE_LINK: ${{ secrets.ARBITRUM_QUICKNODE_LINK }} _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} diff --git a/.github/workflows/run-eslint.yaml b/.github/workflows/run-eslint.yaml index ea286eb26..87c7627b7 100644 --- a/.github/workflows/run-eslint.yaml +++ b/.github/workflows/run-eslint.yaml @@ -10,7 +10,14 @@ jobs: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} - ANKR_KEY: ${{ secrets.ANKR_KEY }} + MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} + SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} + RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} + POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} + OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} + MANTLE_QUICKNODE_LINK: ${{ secrets.MANTLE_QUICKNODE_LINK }} + BASE_QUICKNODE_LINK: ${{ secrets.BASE_QUICKNODE_LINK }} + ARBITRUM_QUICKNODE_LINK: ${{ secrets.ARBITRUM_QUICKNODE_LINK }} _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} diff --git a/.github/workflows/run-gas-profiler.yaml b/.github/workflows/run-gas-profiler.yaml index b28e6a7e3..a812c41dd 100644 --- a/.github/workflows/run-gas-profiler.yaml +++ b/.github/workflows/run-gas-profiler.yaml @@ -11,7 +11,14 @@ jobs: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} - ANKR_KEY: ${{ secrets.ANKR_KEY }} + MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} + SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} + RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} + POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} + OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} + MANTLE_QUICKNODE_LINK: ${{ secrets.MANTLE_QUICKNODE_LINK }} + BASE_QUICKNODE_LINK: ${{ secrets.BASE_QUICKNODE_LINK }} + ARBITRUM_QUICKNODE_LINK: ${{ secrets.ARBITRUM_QUICKNODE_LINK }} _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} diff --git a/.github/workflows/run-scenarios.yaml b/.github/workflows/run-scenarios.yaml index 2988d9ada..8646c39e8 100644 --- a/.github/workflows/run-scenarios.yaml +++ b/.github/workflows/run-scenarios.yaml @@ -15,7 +15,14 @@ jobs: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} - ANKR_KEY: ${{ secrets.ANKR_KEY }} + MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} + SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} + RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} + POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} + OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} + MANTLE_QUICKNODE_LINK: ${{ secrets.MANTLE_QUICKNODE_LINK }} + BASE_QUICKNODE_LINK: ${{ secrets.BASE_QUICKNODE_LINK }} + ARBITRUM_QUICKNODE_LINK: ${{ secrets.ARBITRUM_QUICKNODE_LINK }} _TENDERLY_KEY_POLYGON: ${{ secrets._TENDERLY_KEY_POLYGON }} _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} diff --git a/.github/workflows/run-semgrep.yaml b/.github/workflows/run-semgrep.yaml index b5efe0c3e..c32c5c1b0 100644 --- a/.github/workflows/run-semgrep.yaml +++ b/.github/workflows/run-semgrep.yaml @@ -17,7 +17,14 @@ jobs: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} - ANKR_KEY: ${{ secrets.ANKR_KEY }} + MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} + SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} + RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} + POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} + OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} + MANTLE_QUICKNODE_LINK: ${{ secrets.MANTLE_QUICKNODE_LINK }} + BASE_QUICKNODE_LINK: ${{ secrets.BASE_QUICKNODE_LINK }} + ARBITRUM_QUICKNODE_LINK: ${{ secrets.ARBITRUM_QUICKNODE_LINK }} _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} diff --git a/.github/workflows/run-unit-tests.yaml b/.github/workflows/run-unit-tests.yaml index acedebeea..7b4f9e3e3 100644 --- a/.github/workflows/run-unit-tests.yaml +++ b/.github/workflows/run-unit-tests.yaml @@ -14,7 +14,14 @@ jobs: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} - ANKR_KEY: ${{ secrets.ANKR_KEY }} + MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} + SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} + RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} + POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} + OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} + MANTLE_QUICKNODE_LINK: ${{ secrets.MANTLE_QUICKNODE_LINK }} + BASE_QUICKNODE_LINK: ${{ secrets.BASE_QUICKNODE_LINK }} + ARBITRUM_QUICKNODE_LINK: ${{ secrets.ARBITRUM_QUICKNODE_LINK }} _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} diff --git a/hardhat.config.ts b/hardhat.config.ts index 91be9c8ec..98d3b1646 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -60,8 +60,16 @@ const { ETH_PK, ETHERSCAN_KEY, SNOWTRACE_KEY, - ANKR_KEY, - INFURA_KEY, + MAINNET_QUICKNODE_LINK, + SEPOLIA_QUICKNODE_LINK, + RONIN_QUICKNODE_LINK, + POLYGON_QUICKNODE_LINK, + OPTIMISM_QUICKNODE_LINK, + MANTLE_QUICKNODE_LINK, + BASE_QUICKNODE_LINK, + ARBITRUM_QUICKNODE_LINK, + UNICHAIN_QUICKNODE_LINK = '', + LINEA_QUICKNODE_LINK = '', _TENDERLY_KEY_RONIN, _TENDERLY_KEY_POLYGON, MNEMONIC = 'myth like woof scare over problem client lizard pioneer submit female collect', @@ -69,8 +77,6 @@ const { NETWORK_PROVIDER = '', GOV_NETWORK_PROVIDER = '', GOV_NETWORK = '', - UNICHAIN_QUICKNODE_LINK = '', - LINEA_QUICKNODE_LINK = '', REMOTE_ACCOUNTS = '' } = process.env; @@ -93,8 +99,7 @@ export function requireEnv(varName, msg?: string): string { [ 'ETHERSCAN_KEY', 'SNOWTRACE_KEY', - 'INFURA_KEY', - 'ANKR_KEY', + 'MAINNET_QUICKNODE_LINK', 'UNICHAIN_QUICKNODE_LINK', 'LINEA_QUICKNODE_LINK' ].map((v) => requireEnv(v)); @@ -125,33 +130,33 @@ export const networkConfigs: NetworkConfig[] = [ { network: 'mainnet', chainId: 1, - url: `https://mainnet.infura.io/v3/${INFURA_KEY}` + url: `${MAINNET_QUICKNODE_LINK}`, }, { network: 'sepolia', chainId: 11155111, - url: `https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}`, + url: `${SEPOLIA_QUICKNODE_LINK}`, }, { network: 'ronin', chainId: 2020, - url: `https://ronin.gateway.tenderly.co/${_TENDERLY_KEY_RONIN}`, + url: `${RONIN_QUICKNODE_LINK}`, }, { network: 'polygon', chainId: 137, - url: `https://polygon.gateway.tenderly.co/${_TENDERLY_KEY_POLYGON}`, + url: `${POLYGON_QUICKNODE_LINK}`, }, { network: 'optimism', chainId: 10, - url: `https://rpc.ankr.com/optimism/${ANKR_KEY}`, + url: `${OPTIMISM_QUICKNODE_LINK}`, }, { network: 'mantle', chainId: 5000, // link for scenarios - url: `https://rpc.ankr.com/mantle/${ANKR_KEY}`, + url: `${MANTLE_QUICKNODE_LINK}`, // link for deployment // url: `https://rpc.mantle.xyz`, }, @@ -168,12 +173,12 @@ export const networkConfigs: NetworkConfig[] = [ { network: 'base', chainId: 8453, - url: `https://rpc.ankr.com/base/${ANKR_KEY}`, + url: `${BASE_QUICKNODE_LINK}`, }, { network: 'arbitrum', chainId: 42161, - url: `https://rpc.ankr.com/arbitrum/${ANKR_KEY}`, + url: `${ARBITRUM_QUICKNODE_LINK}`, }, { network: 'avalanche', @@ -192,10 +197,6 @@ export const networkConfigs: NetworkConfig[] = [ }, ]; -function getDefaultProviderURL(network: string) { - return `https://rpc.ankr.com/${network}/${ANKR_KEY}`; -} - function setupDefaultNetworkProviders(hardhatConfig: HardhatUserConfig) { for (const netConfig of networkConfigs) { hardhatConfig.networks[netConfig.network] = { @@ -203,8 +204,7 @@ function setupDefaultNetworkProviders(hardhatConfig: HardhatUserConfig) { url: (netConfig.network === GOV_NETWORK ? GOV_NETWORK_PROVIDER || undefined : undefined) || NETWORK_PROVIDER || - netConfig.url || - getDefaultProviderURL(netConfig.network), + netConfig.url, gas: netConfig.gas || 'auto', gasPrice: netConfig.gasPrice || 'auto', accounts: REMOTE_ACCOUNTS ? 'remote' : (ETH_PK ? [...deriveAccounts(ETH_PK)] : { mnemonic: MNEMONIC }), From 38a9d9e43d0b048019153d0d7d8a48f2fcbcead9 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Mon, 24 Nov 2025 16:26:15 +0200 Subject: [PATCH 17/65] fix: working tests --- forge/lib/forge-std | 2 +- test/marketupdates/market-updates-helper.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/forge/lib/forge-std b/forge/lib/forge-std index 8f24d6b04..77041d2ce 160000 --- a/forge/lib/forge-std +++ b/forge/lib/forge-std @@ -1 +1 @@ -Subproject commit 8f24d6b04c92975e0795b5868aa0d783251cdeaa +Subproject commit 77041d2ce690e692d6e03cc812b57d1ddaa4d505 diff --git a/test/marketupdates/market-updates-helper.ts b/test/marketupdates/market-updates-helper.ts index b2b4a9512..9d095718d 100644 --- a/test/marketupdates/market-updates-helper.ts +++ b/test/marketupdates/market-updates-helper.ts @@ -13,8 +13,8 @@ export async function makeMarketAdmin() { const signers = await ethers.getSigners(); - const marketUpdateMultiSig = signers[8]; - const marketUpdateProposalGuardianSigner = signers[11]; + const marketUpdateMultiSig = signers[7]; + const marketUpdateProposalGuardianSigner = signers[8]; const marketAdminPauseGuardianSigner = signers[9]; const marketAdminTimelockFactory = (await ethers.getContractFactory( From 525e5a8f66f75d74ac6f1daccabc5faf47ca5add Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Mon, 24 Nov 2025 17:03:34 +0200 Subject: [PATCH 18/65] fix: working forge test --- .github/workflows/run-forge-tests.yaml | 12 ++++++------ foundry.toml | 12 ++++++------ scripts/exportNetworkConfigs.js | 12 ++++++------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/run-forge-tests.yaml b/.github/workflows/run-forge-tests.yaml index db40c45e5..b2ef65f50 100644 --- a/.github/workflows/run-forge-tests.yaml +++ b/.github/workflows/run-forge-tests.yaml @@ -37,13 +37,13 @@ jobs: MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} UNICHAIN_QUICKNODE_KEY: ${{ secrets.UNICHAIN_QUICKNODE_KEY }} - MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} - OPTIMISM_RPC_URL: ${{ secrets.OPTIMISM_RPC_URL }} - BASE_RPC_URL: ${{ secrets.BASE_RPC_URL }} + MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} + OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} + BASE_QUICKNODE_LINK: ${{ secrets.BASE_QUICKNODE_LINK }} SCROLL_RPC_URL: ${{ secrets.SCROLL_RPC_URL }} - ARBITRUM_RPC_URL: ${{ secrets.ARBITRUM_RPC_URL }} - POLYGON_RPC_URL: ${{ secrets.POLYGON_RPC_URL }} - MANTLE_RPC_URL: ${{ secrets.MANTLE_RPC_URL }} + ARBITRUM_QUICKNODE_LINK: ${{ secrets.ARBITRUM_QUICKNODE_LINK }} + POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} + MANTLE_QUICKNODE_LINK: ${{ secrets.MANTLE_QUICKNODE_LINK }} SALT: ${{ secrets.SALT }} - name: Build Comet with older solc versions diff --git a/foundry.toml b/foundry.toml index 91c860753..3ea87d9cc 100644 --- a/foundry.toml +++ b/foundry.toml @@ -21,11 +21,11 @@ remappings = [ ] [rpc_endpoints] -mainnet = "${MAINNET_RPC_URL}" -polygon = "${POLYGON_RPC_URL}" -arbitrum = "${ARBITRUM_RPC_URL}" -optimism = "${OPTIMISM_RPC_URL}" +mainnet = "${MAINNET_QUICKNODE_LINK}" +polygon = "${POLYGON_QUICKNODE_LINK}" +arbitrum = "${ARBITRUM_QUICKNODE_LINK}" +optimism = "${OPTIMISM_QUICKNODE_LINK}" scroll = "${SCROLL_RPC_URL}" -base = "${BASE_RPC_URL}" +base = "${BASE_QUICKNODE_LINK}" sepolia = "${SEPOLIA_RPC_URL}" -mantle = "${MANTLE_RPC_URL}" +mantle = "${MANTLE_QUICKNODE_LINK}" diff --git a/scripts/exportNetworkConfigs.js b/scripts/exportNetworkConfigs.js index e6032b651..e16da6da0 100644 --- a/scripts/exportNetworkConfigs.js +++ b/scripts/exportNetworkConfigs.js @@ -35,14 +35,14 @@ function getUrl(network) { const envVar = { SALT: process.env.SALT || 'comet', - MAINNET_RPC_URL: getUrl('mainnet'), - POLYGON_RPC_URL: getUrl('polygon'), - ARBITRUM_RPC_URL: getUrl('arbitrum'), - OPTIMISM_RPC_URL: getUrl('optimism'), + MAINNET_QUICKNODE_LINK: getUrl('mainnet'), + POLYGON_QUICKNODE_LINK: getUrl('polygon'), + ARBITRUM_QUICKNODE_LINK: getUrl('arbitrum'), + OPTIMISM_QUICKNODE_LINK: getUrl('optimism'), SCROLL_RPC_URL: getUrl('scroll'), - BASE_RPC_URL: getUrl('base'), + BASE_QUICKNODE_LINK: getUrl('base'), SEPOLIA_RPC_URL: getUrl('sepolia'), - MANTLE_RPC_URL: getUrl('mantle'), + MANTLE_QUICKNODE_LINK: getUrl('mantle'), }; const envString = Object.entries(envVar) From d73df396e2ddad2e9067c5a3ce9c1c1a01b7d6a2 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Mon, 24 Nov 2025 17:30:05 +0200 Subject: [PATCH 19/65] Update run-forge-tests.yaml --- .github/workflows/run-forge-tests.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/run-forge-tests.yaml b/.github/workflows/run-forge-tests.yaml index b2ef65f50..f8d886070 100644 --- a/.github/workflows/run-forge-tests.yaml +++ b/.github/workflows/run-forge-tests.yaml @@ -41,6 +41,8 @@ jobs: OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} BASE_QUICKNODE_LINK: ${{ secrets.BASE_QUICKNODE_LINK }} SCROLL_RPC_URL: ${{ secrets.SCROLL_RPC_URL }} + SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} + RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} ARBITRUM_QUICKNODE_LINK: ${{ secrets.ARBITRUM_QUICKNODE_LINK }} POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} MANTLE_QUICKNODE_LINK: ${{ secrets.MANTLE_QUICKNODE_LINK }} From 640d956313d216976386bdfaeff685e2cafe38bb Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Mon, 24 Nov 2025 17:46:37 +0200 Subject: [PATCH 20/65] Update run-forge-tests.yaml --- .github/workflows/run-forge-tests.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/run-forge-tests.yaml b/.github/workflows/run-forge-tests.yaml index f8d886070..1d1c10283 100644 --- a/.github/workflows/run-forge-tests.yaml +++ b/.github/workflows/run-forge-tests.yaml @@ -41,6 +41,8 @@ jobs: OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} BASE_QUICKNODE_LINK: ${{ secrets.BASE_QUICKNODE_LINK }} SCROLL_RPC_URL: ${{ secrets.SCROLL_RPC_URL }} + UNICHAIN_QUICKNODE_LINK: ${{ secrets.UNICHAIN_QUICKNODE_LINK }} + LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} ARBITRUM_QUICKNODE_LINK: ${{ secrets.ARBITRUM_QUICKNODE_LINK }} From 49ac1368a10d3188219c7fad50f2efd7359fb461 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Thu, 27 Nov 2025 14:32:54 +0200 Subject: [PATCH 21/65] Update run-scenarios.yaml --- .github/workflows/run-scenarios.yaml | 55 +++++++++++++++++++--------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/.github/workflows/run-scenarios.yaml b/.github/workflows/run-scenarios.yaml index 8646c39e8..d22e19767 100644 --- a/.github/workflows/run-scenarios.yaml +++ b/.github/workflows/run-scenarios.yaml @@ -5,6 +5,44 @@ on: permissions: checks: write jobs: + prepare: + name: Prepare Repository + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: recursive + + - uses: actions/setup-node@v4 + with: + cache: 'yarn' + node-version: '18' + + - name: Cache Deployments + uses: actions/cache@v4 + with: + path: | + deployments/*/.contracts + deployments/**/aliases.json + !deployments/hardhat + !deployments/relations.ts + !deployments/**/roots.json + !deployments/**/relations.ts + !deployments/**/configuration.json + !deployments/**/migrations/* + key: deployments-v4 + + - name: Install packages + run: yarn install --non-interactive --frozen-lockfile && yarn build + + - name: Compile + run: npx hardhat compile + + - name: Spider Contracts + run: yarn hardhat spider --network mainnet --deployment usdc + run-scenarios: strategy: fail-fast: false @@ -34,17 +72,6 @@ jobs: LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} runs-on: ubuntu-latest steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - submodules: recursive - - - uses: actions/setup-node@v4 - with: - cache: 'yarn' - node-version: '18' - - name: Cache Deployments uses: actions/cache@v4 with: @@ -59,12 +86,6 @@ jobs: !deployments/**/migrations/* key: deployments-v4 - - name: Install packages - run: yarn install --non-interactive --frozen-lockfile && yarn build - - - name: Compile - run: npx hardhat compile - - name: Run scenarios run: yarn scenario --bases ${{ matrix.bases }} From a16813aa6e6e54a741e9c75b09ff89f216b1f9d3 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Thu, 27 Nov 2025 14:38:22 +0200 Subject: [PATCH 22/65] fix: env in scenario --- .github/workflows/run-scenarios.yaml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/run-scenarios.yaml b/.github/workflows/run-scenarios.yaml index d22e19767..49240e369 100644 --- a/.github/workflows/run-scenarios.yaml +++ b/.github/workflows/run-scenarios.yaml @@ -7,6 +7,27 @@ permissions: jobs: prepare: name: Prepare Repository + env: + ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} + SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} + INFURA_KEY: ${{ secrets.INFURA_KEY }} + MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} + SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} + RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} + POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} + OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} + MANTLE_QUICKNODE_LINK: ${{ secrets.MANTLE_QUICKNODE_LINK }} + BASE_QUICKNODE_LINK: ${{ secrets.BASE_QUICKNODE_LINK }} + ARBITRUM_QUICKNODE_LINK: ${{ secrets.ARBITRUM_QUICKNODE_LINK }} + _TENDERLY_KEY_POLYGON: ${{ secrets._TENDERLY_KEY_POLYGON }} + _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} + POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} + BASESCAN_KEY: ${{ secrets.BASESCAN_KEY }} + OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} + MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} + SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} + UNICHAIN_QUICKNODE_LINK: ${{ secrets.UNICHAIN_QUICKNODE_LINK }} + LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} runs-on: ubuntu-latest steps: - name: Checkout repository From 0407aa65bb2b0aad5ef72bae48e82f8c086ae46c Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Thu, 27 Nov 2025 15:07:47 +0200 Subject: [PATCH 23/65] fix: use different keys for etherscan --- .github/workflows/deploy-market.yaml | 5 +++++ .github/workflows/enact-migration.yaml | 5 +++++ .github/workflows/prepare-migration.yaml | 5 +++++ .github/workflows/run-contract-linter.yaml | 5 +++++ .github/workflows/run-coverage.yaml | 5 +++++ .github/workflows/run-eslint.yaml | 5 +++++ .github/workflows/run-gas-profiler.yaml | 5 +++++ .github/workflows/run-scenarios.yaml | 10 ++++++++++ .github/workflows/run-semgrep.yaml | 5 +++++ .github/workflows/run-unit-tests.yaml | 5 +++++ hardhat.config.ts | 19 ++++++++++++------- plugins/import/etherscan.ts | 10 +++++----- 12 files changed, 72 insertions(+), 12 deletions(-) diff --git a/.github/workflows/deploy-market.yaml b/.github/workflows/deploy-market.yaml index 77485c3cf..a41584ded 100644 --- a/.github/workflows/deploy-market.yaml +++ b/.github/workflows/deploy-market.yaml @@ -32,6 +32,11 @@ jobs: runs-on: ubuntu-latest env: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} + ETHERSCAN_KEY_FOR_OPTIMISM: ${{ secrets.ETHERSCAN_KEY_FOR_OPTIMISM }} + ETHERSCAN_KEY_FOR_BASE: ${{ secrets.ETHERSCAN_KEY_FOR_BASE }} + ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} + ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} + ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} diff --git a/.github/workflows/enact-migration.yaml b/.github/workflows/enact-migration.yaml index 4e74f6803..faa035cbf 100644 --- a/.github/workflows/enact-migration.yaml +++ b/.github/workflows/enact-migration.yaml @@ -54,6 +54,11 @@ jobs: runs-on: ubuntu-latest env: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} + ETHERSCAN_KEY_FOR_OPTIMISM: ${{ secrets.ETHERSCAN_KEY_FOR_OPTIMISM }} + ETHERSCAN_KEY_FOR_BASE: ${{ secrets.ETHERSCAN_KEY_FOR_BASE }} + ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} + ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} + ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} diff --git a/.github/workflows/prepare-migration.yaml b/.github/workflows/prepare-migration.yaml index 4dbf72b19..042e66729 100644 --- a/.github/workflows/prepare-migration.yaml +++ b/.github/workflows/prepare-migration.yaml @@ -35,6 +35,11 @@ jobs: runs-on: ubuntu-latest env: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} + ETHERSCAN_KEY_FOR_OPTIMISM: ${{ secrets.ETHERSCAN_KEY_FOR_OPTIMISM }} + ETHERSCAN_KEY_FOR_BASE: ${{ secrets.ETHERSCAN_KEY_FOR_BASE }} + ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} + ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} + ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} diff --git a/.github/workflows/run-contract-linter.yaml b/.github/workflows/run-contract-linter.yaml index e8391205c..432977561 100644 --- a/.github/workflows/run-contract-linter.yaml +++ b/.github/workflows/run-contract-linter.yaml @@ -8,6 +8,11 @@ jobs: runs-on: ubuntu-latest env: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} + ETHERSCAN_KEY_FOR_OPTIMISM: ${{ secrets.ETHERSCAN_KEY_FOR_OPTIMISM }} + ETHERSCAN_KEY_FOR_BASE: ${{ secrets.ETHERSCAN_KEY_FOR_BASE }} + ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} + ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} + ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} diff --git a/.github/workflows/run-coverage.yaml b/.github/workflows/run-coverage.yaml index b1a52fec8..06d00fead 100644 --- a/.github/workflows/run-coverage.yaml +++ b/.github/workflows/run-coverage.yaml @@ -10,6 +10,11 @@ jobs: env: NODE_OPTIONS: '--max-old-space-size=4096' ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} + ETHERSCAN_KEY_FOR_OPTIMISM: ${{ secrets.ETHERSCAN_KEY_FOR_OPTIMISM }} + ETHERSCAN_KEY_FOR_BASE: ${{ secrets.ETHERSCAN_KEY_FOR_BASE }} + ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} + ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} + ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} diff --git a/.github/workflows/run-eslint.yaml b/.github/workflows/run-eslint.yaml index 87c7627b7..6a0a92224 100644 --- a/.github/workflows/run-eslint.yaml +++ b/.github/workflows/run-eslint.yaml @@ -8,6 +8,11 @@ jobs: runs-on: ubuntu-latest env: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} + ETHERSCAN_KEY_FOR_OPTIMISM: ${{ secrets.ETHERSCAN_KEY_FOR_OPTIMISM }} + ETHERSCAN_KEY_FOR_BASE: ${{ secrets.ETHERSCAN_KEY_FOR_BASE }} + ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} + ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} + ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} diff --git a/.github/workflows/run-gas-profiler.yaml b/.github/workflows/run-gas-profiler.yaml index a812c41dd..8096fa29c 100644 --- a/.github/workflows/run-gas-profiler.yaml +++ b/.github/workflows/run-gas-profiler.yaml @@ -9,6 +9,11 @@ jobs: env: COINMARKETCAP_API_KEY: b52b18a2-d44f-4646-9949-0eb0e9c68574 ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} + ETHERSCAN_KEY_FOR_OPTIMISM: ${{ secrets.ETHERSCAN_KEY_FOR_OPTIMISM }} + ETHERSCAN_KEY_FOR_BASE: ${{ secrets.ETHERSCAN_KEY_FOR_BASE }} + ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} + ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} + ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} diff --git a/.github/workflows/run-scenarios.yaml b/.github/workflows/run-scenarios.yaml index 49240e369..42e84bf02 100644 --- a/.github/workflows/run-scenarios.yaml +++ b/.github/workflows/run-scenarios.yaml @@ -9,6 +9,11 @@ jobs: name: Prepare Repository env: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} + ETHERSCAN_KEY_FOR_OPTIMISM: ${{ secrets.ETHERSCAN_KEY_FOR_OPTIMISM }} + ETHERSCAN_KEY_FOR_BASE: ${{ secrets.ETHERSCAN_KEY_FOR_BASE }} + ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} + ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} + ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} @@ -72,6 +77,11 @@ jobs: name: Run scenarios env: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} + ETHERSCAN_KEY_FOR_OPTIMISM: ${{ secrets.ETHERSCAN_KEY_FOR_OPTIMISM }} + ETHERSCAN_KEY_FOR_BASE: ${{ secrets.ETHERSCAN_KEY_FOR_BASE }} + ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} + ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} + ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} diff --git a/.github/workflows/run-semgrep.yaml b/.github/workflows/run-semgrep.yaml index c32c5c1b0..62301b2e4 100644 --- a/.github/workflows/run-semgrep.yaml +++ b/.github/workflows/run-semgrep.yaml @@ -15,6 +15,11 @@ jobs: runs-on: ubuntu-latest env: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} + ETHERSCAN_KEY_FOR_OPTIMISM: ${{ secrets.ETHERSCAN_KEY_FOR_OPTIMISM }} + ETHERSCAN_KEY_FOR_BASE: ${{ secrets.ETHERSCAN_KEY_FOR_BASE }} + ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} + ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} + ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} diff --git a/.github/workflows/run-unit-tests.yaml b/.github/workflows/run-unit-tests.yaml index 7b4f9e3e3..012be4cc9 100644 --- a/.github/workflows/run-unit-tests.yaml +++ b/.github/workflows/run-unit-tests.yaml @@ -12,6 +12,11 @@ jobs: runs-on: ubuntu-latest env: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} + ETHERSCAN_KEY_FOR_OPTIMISM: ${{ secrets.ETHERSCAN_KEY_FOR_OPTIMISM }} + ETHERSCAN_KEY_FOR_BASE: ${{ secrets.ETHERSCAN_KEY_FOR_BASE }} + ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} + ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} + ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} diff --git a/hardhat.config.ts b/hardhat.config.ts index 98d3b1646..79910f9b3 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -59,6 +59,11 @@ const { COINMARKETCAP_API_KEY, ETH_PK, ETHERSCAN_KEY, + ETHERSCAN_KEY_FOR_OPTIMISM, + ETHERSCAN_KEY_FOR_BASE, + ETHERSCAN_KEY_FOR_ARBITRUM, + ETHERSCAN_KEY_FOR_POLYGON, + ETHERSCAN_KEY_FOR_LINEA, SNOWTRACE_KEY, MAINNET_QUICKNODE_LINK, SEPOLIA_QUICKNODE_LINK, @@ -374,21 +379,21 @@ const config: HardhatUserConfig = { avalanche: SNOWTRACE_KEY, avalancheFujiTestnet: SNOWTRACE_KEY, // Polygon - polygon: ETHERSCAN_KEY, + polygon: ETHERSCAN_KEY_FOR_POLYGON, // Arbitrum - arbitrumOne: ETHERSCAN_KEY, - arbitrumTestnet: ETHERSCAN_KEY, - arbitrum: ETHERSCAN_KEY, + arbitrumOne: ETHERSCAN_KEY_FOR_ARBITRUM, + arbitrumTestnet: ETHERSCAN_KEY_FOR_ARBITRUM, + arbitrum: ETHERSCAN_KEY_FOR_ARBITRUM, // Base - base: ETHERSCAN_KEY, + base: ETHERSCAN_KEY_FOR_BASE, // optimism: OPTIMISMSCAN_KEY, - optimisticEthereum: ETHERSCAN_KEY, + optimisticEthereum: ETHERSCAN_KEY_FOR_OPTIMISM, // Mantle mantle: ETHERSCAN_KEY, unichain: ETHERSCAN_KEY, // Scroll 'scroll': ETHERSCAN_KEY, - linea: ETHERSCAN_KEY, + linea: ETHERSCAN_KEY_FOR_LINEA, }, customChains: [ { diff --git a/plugins/import/etherscan.ts b/plugins/import/etherscan.ts index 34f32e36a..d39e0f9ab 100644 --- a/plugins/import/etherscan.ts +++ b/plugins/import/etherscan.ts @@ -57,13 +57,13 @@ export function getEtherscanApiKey(network: string): string { mainnet: process.env.ETHERSCAN_KEY, fuji: process.env.SNOWTRACE_KEY, avalanche: process.env.SNOWTRACE_KEY, - polygon: process.env.ETHERSCAN_KEY, - arbitrum: process.env.ETHERSCAN_KEY, - base: process.env.ETHERSCAN_KEY, - optimism: process.env.ETHERSCAN_KEY, + polygon: process.env.ETHERSCAN_KEY_FOR_POLYGON, + arbitrum: process.env.ETHERSCAN_KEY_FOR_ARBITRUM, + base: process.env.ETHERSCAN_KEY_FOR_BASE, + optimism: process.env.ETHERSCAN_KEY_FOR_OPTIMISM, mantle: process.env.ETHERSCAN_KEY, scroll: process.env.ETHERSCAN_KEY, - linea: process.env.ETHERSCAN_KEY, + linea: process.env.ETHERSCAN_KEY_FOR_LINEA, }[network]; if (!apiKey) { From 1a368d432ddd71633d7709b73fff28425ccfe959 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Thu, 27 Nov 2025 15:17:28 +0200 Subject: [PATCH 24/65] fix: strict order --- .github/workflows/run-scenarios.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/run-scenarios.yaml b/.github/workflows/run-scenarios.yaml index 42e84bf02..135180b4d 100644 --- a/.github/workflows/run-scenarios.yaml +++ b/.github/workflows/run-scenarios.yaml @@ -70,6 +70,7 @@ jobs: run: yarn hardhat spider --network mainnet --deployment usdc run-scenarios: + needs: prepare strategy: fail-fast: false matrix: @@ -118,6 +119,8 @@ jobs: key: deployments-v4 - name: Run scenarios + env: + DEBUG: true run: yarn scenario --bases ${{ matrix.bases }} - uses: actions/upload-artifact@v4 # upload scenario results From a34434f76d539622e73f5b4540c07ad3c602b37b Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Thu, 27 Nov 2025 15:47:17 +0200 Subject: [PATCH 25/65] fix: pass the prepared state --- .github/workflows/run-scenarios.yaml | 38 +++++++++++++++++----------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/.github/workflows/run-scenarios.yaml b/.github/workflows/run-scenarios.yaml index 135180b4d..9ae4f5452 100644 --- a/.github/workflows/run-scenarios.yaml +++ b/.github/workflows/run-scenarios.yaml @@ -34,6 +34,10 @@ jobs: UNICHAIN_QUICKNODE_LINK: ${{ secrets.UNICHAIN_QUICKNODE_LINK }} LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + network: [mainnet, base, arbitrum, polygon, optimism, linea] steps: - name: Checkout repository uses: actions/checkout@v4 @@ -46,20 +50,6 @@ jobs: cache: 'yarn' node-version: '18' - - name: Cache Deployments - uses: actions/cache@v4 - with: - path: | - deployments/*/.contracts - deployments/**/aliases.json - !deployments/hardhat - !deployments/relations.ts - !deployments/**/roots.json - !deployments/**/relations.ts - !deployments/**/configuration.json - !deployments/**/migrations/* - key: deployments-v4 - - name: Install packages run: yarn install --non-interactive --frozen-lockfile && yarn build @@ -67,7 +57,19 @@ jobs: run: npx hardhat compile - name: Spider Contracts - run: yarn hardhat spider --network mainnet --deployment usdc + run: yarn hardhat spider --network ${{ matrix.network }} --deployment usdc + + - name: Upload prepared state + uses: actions/upload-artifact@v4 + with: + name: prepared-data + path: | + deployments/**/aliases.json + deployments/*/.contracts + node_modules/ + artifacts/ + build/ + cache/ run-scenarios: needs: prepare @@ -104,6 +106,12 @@ jobs: LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} runs-on: ubuntu-latest steps: + - name: Download prepared state + uses: actions/download-artifact@v4 + with: + name: prepared-data + path: . + - name: Cache Deployments uses: actions/cache@v4 with: From 9d6c077ddeca74debea71fa9959e6bee7b215a7d Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Thu, 27 Nov 2025 15:53:43 +0200 Subject: [PATCH 26/65] fix: remove matrix --- .github/workflows/run-scenarios.yaml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/run-scenarios.yaml b/.github/workflows/run-scenarios.yaml index 9ae4f5452..f80dc6b6b 100644 --- a/.github/workflows/run-scenarios.yaml +++ b/.github/workflows/run-scenarios.yaml @@ -34,10 +34,6 @@ jobs: UNICHAIN_QUICKNODE_LINK: ${{ secrets.UNICHAIN_QUICKNODE_LINK }} LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - network: [mainnet, base, arbitrum, polygon, optimism, linea] steps: - name: Checkout repository uses: actions/checkout@v4 @@ -56,8 +52,17 @@ jobs: - name: Compile run: npx hardhat compile - - name: Spider Contracts - run: yarn hardhat spider --network ${{ matrix.network }} --deployment usdc + - name: Spider Contracts on Mainnet + run: yarn hardhat spider --network mainnet --deployment usdc + + - name: Spider Contracts on Base + run: yarn hardhat spider --network base --deployment usdc + + - name: Spider Contracts on Arbitrum + run: yarn hardhat spider --network arbitrum --deployment usdc + + - name: Spider Contracts on Linea + run: yarn hardhat spider --network linea --deployment usdc - name: Upload prepared state uses: actions/upload-artifact@v4 From 58ed4783231aa7930f48c141855e91ea02d4caec Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Thu, 27 Nov 2025 16:08:52 +0200 Subject: [PATCH 27/65] fix: pass node modules --- .github/workflows/run-scenarios.yaml | 140 +++++++++++++-------------- 1 file changed, 67 insertions(+), 73 deletions(-) diff --git a/.github/workflows/run-scenarios.yaml b/.github/workflows/run-scenarios.yaml index f80dc6b6b..b71c66a87 100644 --- a/.github/workflows/run-scenarios.yaml +++ b/.github/workflows/run-scenarios.yaml @@ -4,35 +4,37 @@ on: pull_request: permissions: checks: write + +env: + ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} + ETHERSCAN_KEY_FOR_OPTIMISM: ${{ secrets.ETHERSCAN_KEY_FOR_OPTIMISM }} + ETHERSCAN_KEY_FOR_BASE: ${{ secrets.ETHERSCAN_KEY_FOR_BASE }} + ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} + ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} + ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} + SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} + INFURA_KEY: ${{ secrets.INFURA_KEY }} + MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} + SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} + RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} + POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} + OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} + MANTLE_QUICKNODE_LINK: ${{ secrets.MANTLE_QUICKNODE_LINK }} + BASE_QUICKNODE_LINK: ${{ secrets.BASE_QUICKNODE_LINK }} + ARBITRUM_QUICKNODE_LINK: ${{ secrets.ARBITRUM_QUICKNODE_LINK }} + _TENDERLY_KEY_POLYGON: ${{ secrets._TENDERLY_KEY_POLYGON }} + _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} + POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} + BASESCAN_KEY: ${{ secrets.BASESCAN_KEY }} + OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} + MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} + SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} + UNICHAIN_QUICKNODE_LINK: ${{ secrets.UNICHAIN_QUICKNODE_LINK }} + LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} + jobs: prepare: name: Prepare Repository - env: - ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} - ETHERSCAN_KEY_FOR_OPTIMISM: ${{ secrets.ETHERSCAN_KEY_FOR_OPTIMISM }} - ETHERSCAN_KEY_FOR_BASE: ${{ secrets.ETHERSCAN_KEY_FOR_BASE }} - ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} - ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} - ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} - SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} - INFURA_KEY: ${{ secrets.INFURA_KEY }} - MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} - SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} - RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} - POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} - OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} - MANTLE_QUICKNODE_LINK: ${{ secrets.MANTLE_QUICKNODE_LINK }} - BASE_QUICKNODE_LINK: ${{ secrets.BASE_QUICKNODE_LINK }} - ARBITRUM_QUICKNODE_LINK: ${{ secrets.ARBITRUM_QUICKNODE_LINK }} - _TENDERLY_KEY_POLYGON: ${{ secrets._TENDERLY_KEY_POLYGON }} - _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} - POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} - BASESCAN_KEY: ${{ secrets.BASESCAN_KEY }} - OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} - MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} - SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} - UNICHAIN_QUICKNODE_LINK: ${{ secrets.UNICHAIN_QUICKNODE_LINK }} - LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} runs-on: ubuntu-latest steps: - name: Checkout repository @@ -43,9 +45,19 @@ jobs: - uses: actions/setup-node@v4 with: - cache: 'yarn' node-version: '18' + # Create a deterministic cache key based on yarn.lock + - name: Cache node_modules (create/save) + uses: actions/cache@v4 + id: yarn-cache + with: + path: | + node_modules + .yarn/cache + .yarn/__virtual__ + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + - name: Install packages run: yarn install --non-interactive --frozen-lockfile && yarn build @@ -55,15 +67,7 @@ jobs: - name: Spider Contracts on Mainnet run: yarn hardhat spider --network mainnet --deployment usdc - - name: Spider Contracts on Base - run: yarn hardhat spider --network base --deployment usdc - - - name: Spider Contracts on Arbitrum - run: yarn hardhat spider --network arbitrum --deployment usdc - - - name: Spider Contracts on Linea - run: yarn hardhat spider --network linea --deployment usdc - + # Upload only the prepared artifacts you need (no node_modules) - name: Upload prepared state uses: actions/upload-artifact@v4 with: @@ -71,7 +75,6 @@ jobs: path: | deployments/**/aliases.json deployments/*/.contracts - node_modules/ artifacts/ build/ cache/ @@ -83,53 +86,44 @@ jobs: matrix: bases: [ development, mainnet, mainnet-weth, mainnet-wbtc, mainnet-usdt, mainnet-wsteth, mainnet-usds, sepolia-usdc, sepolia-weth, fuji, polygon, polygon-usdt, arbitrum-usdc.e, arbitrum-usdc, arbitrum-weth, arbitrum-usdt, base-usdbc, base-weth, base-usdc, base-aero, base-usds, optimism-usdc, optimism-usdt, optimism-weth, mantle-usde, linea-usdc, linea-weth, scroll-usdc, ronin-weth, ronin-wron, unichain-usdc, unichain-weth] name: Run scenarios - env: - ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} - ETHERSCAN_KEY_FOR_OPTIMISM: ${{ secrets.ETHERSCAN_KEY_FOR_OPTIMISM }} - ETHERSCAN_KEY_FOR_BASE: ${{ secrets.ETHERSCAN_KEY_FOR_BASE }} - ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} - ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} - ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} - SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} - INFURA_KEY: ${{ secrets.INFURA_KEY }} - MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} - SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} - RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} - POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} - OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} - MANTLE_QUICKNODE_LINK: ${{ secrets.MANTLE_QUICKNODE_LINK }} - BASE_QUICKNODE_LINK: ${{ secrets.BASE_QUICKNODE_LINK }} - ARBITRUM_QUICKNODE_LINK: ${{ secrets.ARBITRUM_QUICKNODE_LINK }} - _TENDERLY_KEY_POLYGON: ${{ secrets._TENDERLY_KEY_POLYGON }} - _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} - POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} - BASESCAN_KEY: ${{ secrets.BASESCAN_KEY }} - OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} - MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} - SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} - UNICHAIN_QUICKNODE_LINK: ${{ secrets.UNICHAIN_QUICKNODE_LINK }} - LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} runs-on: ubuntu-latest steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: recursive + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: '18' + - name: Download prepared state uses: actions/download-artifact@v4 with: name: prepared-data path: . - - name: Cache Deployments + # Restore the same cache created in prepare + - name: Restore node_modules cache uses: actions/cache@v4 with: path: | - deployments/*/.contracts - deployments/**/aliases.json - !deployments/hardhat - !deployments/relations.ts - !deployments/**/roots.json - !deployments/**/relations.ts - !deployments/**/configuration.json - !deployments/**/migrations/* - key: deployments-v4 + node_modules + .yarn/cache + .yarn/__virtual__ + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + + # Install only if cache miss (keeps matrix jobs fast) + - name: Install deps if needed + run: | + if [ ! -d node_modules ] || [ ! -f node_modules/.bin ]; then + echo "node_modules missing — running yarn install" + yarn install --non-interactive --frozen-lockfile + else + echo "node_modules present from cache — skipping install" + fi - name: Run scenarios env: From 0e67e928bbb158c7ccce3f00964a10a31bb3ce14 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Fri, 28 Nov 2025 16:06:57 +0200 Subject: [PATCH 28/65] fix: add contracts to cache before scenario run --- .../deployment_manager/DeploymentManager.ts | 45 ++++++++++++++++++- plugins/scenario/Runner.ts | 1 + scenario/constraints/ProposalConstraint.ts | 6 +-- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/plugins/deployment_manager/DeploymentManager.ts b/plugins/deployment_manager/DeploymentManager.ts index e32a0f80c..2bcfc2357 100644 --- a/plugins/deployment_manager/DeploymentManager.ts +++ b/plugins/deployment_manager/DeploymentManager.ts @@ -5,7 +5,7 @@ import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; import { Alias, Address, BuildFile, TraceFn } from './Types'; import { getAliases, storeAliases, putAlias } from './Aliases'; import { Cache } from './Cache'; -import { ContractMap } from './ContractMap'; +import { ContractMap, getBuildFile } from './ContractMap'; import { DeployOpts, deploy, deployBuild } from './Deploy'; import { fetchAndCacheContract, readContract } from './Import'; import { getRelationConfig } from './RelationConfig'; @@ -388,6 +388,49 @@ export class DeploymentManager { return await verifyContract(args, this.hre, (await this.deployOpts()).raiseOnVerificationFailure); } + /* Loads contracts from existing cache (aliases.json and .contracts/*.json files) */ + async loadContractsFromExistingCache() { + const trace = this.tracer(); + + // Load aliases from deployments/{network}/{deployment}/aliases.json + const aliases = await getAliases(this.cache); + + if (aliases.size === 0) { + trace('No aliases found in cache'); + return; + } + + trace(`Loading ${aliases.size} contracts from existing cache`); + + // Initialize contractsCache if it's empty + if (this.contractsCache === null) { + this.contractsCache = new Map(); + } + + // Load build files for each alias + for (const [alias, address] of aliases.entries()) { + try { + // Read build file from cache by address + // Build files are stored in deployments/{network}/.contracts/{address}.json + const buildFile = await getBuildFile(this.cache, this.network, address); + + if (buildFile) { + // Create ethers Contract from build file + const contract = getEthersContract(address, buildFile, this.hre); + + // Store in contractsCache + this.contractsCache.set(alias, contract); + + trace(`Loaded ${alias} @ ${address} from cache`); + } + } catch (e) { + console.warn(`Failed to load contract ${alias} @ ${address} from cache:`, e.message); + } + } + + trace(`Successfully loaded ${this.contractsCache.size} contracts from cache`); + } + /* Loads contract configuration by tracing from roots outwards, based on relationConfig */ async spider(deployed: Deployed = {}): Promise { const relationConfigMap = getRelationConfig( diff --git a/plugins/scenario/Runner.ts b/plugins/scenario/Runner.ts index e7df109cf..1bda4ace5 100644 --- a/plugins/scenario/Runner.ts +++ b/plugins/scenario/Runner.ts @@ -197,6 +197,7 @@ export async function runScenarios(bases: ForkSpec[]) { const world = new World(base); await world.initialize(base); const dm = world.deploymentManager; + await dm.loadContractsFromExistingCache(); const delta = await dm.runDeployScript({ allMissing: true }); console.log(`[${base.name}] Deployed ${dm.counter} contracts, spent ${dm.spent} to initialize world 🗺`); console.log(`[${base.name}]\n${dm.diffDelta(delta)}`); diff --git a/scenario/constraints/ProposalConstraint.ts b/scenario/constraints/ProposalConstraint.ts index bc2d0f1d4..b1e45cd7d 100644 --- a/scenario/constraints/ProposalConstraint.ts +++ b/scenario/constraints/ProposalConstraint.ts @@ -78,9 +78,9 @@ export class ProposalConstraint implements StaticConstra ); } - // temporary hack to skip proposal 427 - if (proposal.id.eq(427)) { - console.log('Skipping proposal 427'); + // temporary hack to skip proposal 504 + if (proposal.id.eq(504)) { + console.log('Skipping proposal 504'); continue; } From bc0871e3bb5e7d728ee2fc5bf43e538d62dad5e4 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Fri, 28 Nov 2025 16:22:28 +0200 Subject: [PATCH 29/65] fix: cache path fix --- .github/workflows/run-scenarios.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-scenarios.yaml b/.github/workflows/run-scenarios.yaml index b71c66a87..992ede4d0 100644 --- a/.github/workflows/run-scenarios.yaml +++ b/.github/workflows/run-scenarios.yaml @@ -74,7 +74,7 @@ jobs: name: prepared-data path: | deployments/**/aliases.json - deployments/*/.contracts + deployments/**/.contracts/*.json artifacts/ build/ cache/ From 5f4fc6feb21a3696faa44c9b12d0ca7992bf84f3 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Fri, 28 Nov 2025 16:29:32 +0200 Subject: [PATCH 30/65] fix: use hidden files --- .github/workflows/run-scenarios.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run-scenarios.yaml b/.github/workflows/run-scenarios.yaml index 992ede4d0..64311a570 100644 --- a/.github/workflows/run-scenarios.yaml +++ b/.github/workflows/run-scenarios.yaml @@ -59,10 +59,10 @@ jobs: key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - name: Install packages - run: yarn install --non-interactive --frozen-lockfile && yarn build + run: yarn install --non-interactive --frozen-lockfile - name: Compile - run: npx hardhat compile + run: yarn build - name: Spider Contracts on Mainnet run: yarn hardhat spider --network mainnet --deployment usdc @@ -78,6 +78,7 @@ jobs: artifacts/ build/ cache/ + include-hidden-files: true run-scenarios: needs: prepare From 5a77147cb1d2212ac53532840b8beca3f12461af Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Fri, 28 Nov 2025 17:12:16 +0200 Subject: [PATCH 31/65] fix: fuji --- plugins/import/import.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/import/import.ts b/plugins/import/import.ts index 925c0a9f7..5863644f1 100644 --- a/plugins/import/import.ts +++ b/plugins/import/import.ts @@ -491,7 +491,7 @@ export async function loadEtherscanContract(network: string, address: string) { const contractFQN = `${contractPath}:${contract}`; let contractCreationCode = await getContractCreationCode(networkName, address); - if (constructorArgs.length > 0 && contractCreationCode.endsWith(constructorArgs)) { + if (contractCreationCode.endsWith(constructorArgs) && constructorArgs.length > 0) { contractCreationCode = contractCreationCode.slice(0, -constructorArgs.length); } From b287ff21ad5a8d15a73be85bb80f7a4cb464b0af Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Tue, 2 Dec 2025 16:19:47 +0200 Subject: [PATCH 32/65] feat: rotate apikeys and some arbitrum fixes --- deployments/arbitrum/weth/relations.ts | 8 + plugins/import/etherscan.ts | 41 +++- plugins/import/import.ts | 214 ++++++++++++--------- scenario/constraints/ProposalConstraint.ts | 6 +- src/deploy/index.ts | 2 + 5 files changed, 168 insertions(+), 103 deletions(-) diff --git a/deployments/arbitrum/weth/relations.ts b/deployments/arbitrum/weth/relations.ts index b42cc0bf2..b61a62f10 100644 --- a/deployments/arbitrum/weth/relations.ts +++ b/deployments/arbitrum/weth/relations.ts @@ -14,6 +14,14 @@ export default { ClonableBeaconProxy: { artifact: 'contracts/ERC20.sol:ERC20' }, + ERC1967Proxy: { + artifact: 'contracts/ERC20.sol:ERC20', + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, // WETH '0x82af49447d8a07e3bd95bd0d56f35241523fbab1': { artifact: 'contracts/ERC20.sol:ERC20', diff --git a/plugins/import/etherscan.ts b/plugins/import/etherscan.ts index d39e0f9ab..a4506a419 100644 --- a/plugins/import/etherscan.ts +++ b/plugins/import/etherscan.ts @@ -49,10 +49,9 @@ export function getEtherscanUrl(network: string): string { return `https://${host}`; } -export function getEtherscanApiKey(network: string): string { - let apiKey = { - rinkeby: process.env.ETHERSCAN_KEY, - ropsten: process.env.ETHERSCAN_KEY, +export function getEtherscanApiKey(network: string, i?: number): string { + // Primary key for each network + const primaryKeys = { sepolia: process.env.ETHERSCAN_KEY, mainnet: process.env.ETHERSCAN_KEY, fuji: process.env.SNOWTRACE_KEY, @@ -64,13 +63,39 @@ export function getEtherscanApiKey(network: string): string { mantle: process.env.ETHERSCAN_KEY, scroll: process.env.ETHERSCAN_KEY, linea: process.env.ETHERSCAN_KEY_FOR_LINEA, - }[network]; + }; + + // All available keys for rotation (after primary) + const allKeys = [ + process.env.ETHERSCAN_KEY, + process.env.ETHERSCAN_KEY_FOR_POLYGON, + process.env.ETHERSCAN_KEY_FOR_ARBITRUM, + process.env.ETHERSCAN_KEY_FOR_BASE, + process.env.ETHERSCAN_KEY_FOR_OPTIMISM, + process.env.ETHERSCAN_KEY_FOR_LINEA + ].filter(key => key !== undefined && key !== ''); + + const primaryKey = primaryKeys[network]; + + if (!primaryKey && allKeys.length === 0) { + throw new Error(`No etherscan API keys configured for network ${network}`); + } + + // If 'i' is not provided or is 0, return primary key + if (i === undefined || i === 0) { + if (!primaryKey) { + throw new Error(`No primary etherscan API key configured for network ${network}`); + } + return primaryKey; + } - if (!apiKey) { - throw new Error(`Unknown etherscan API key for network ${network}`); + // For i > 0, rotate through all available keys + if (allKeys.length === 0) { + throw new Error(`No additional etherscan API keys available for rotation`); } - return apiKey; + const keyIndex = (i - 1) % allKeys.length; + return allKeys[keyIndex]; } export async function get(url, data) { diff --git a/plugins/import/import.ts b/plugins/import/import.ts index 5863644f1..63fdd8198 100644 --- a/plugins/import/import.ts +++ b/plugins/import/import.ts @@ -276,12 +276,12 @@ async function getEtherscanApiData(network: string, address: string, apiKey: str }; } -async function scrapeContractCreationCodeFromEtherscanApi(network: string, address: string) { +async function scrapeContractCreationCodeFromEtherscanApi(network: string, address: string, i?: number) { const params = { module: 'proxy', action: 'eth_getCode', address, - apikey: getEtherscanApiKey(network) + apikey: getEtherscanApiKey(network, i) }; const url = `${getEtherscanApiUrl(network)}&${paramString(params)}`; const debugUrl = `${getEtherscanApiUrl(network)}&${paramString({ ...params, ...{ apikey: '[API_KEY]' } })}`; @@ -321,7 +321,7 @@ function paramString(params: { [k: string]: string | number }) { return Object.entries(params).map(([k, v]) => `${k}=${v}`).join('&'); } -async function pullFirstTransactionForContractFromEtherscan(network: string, address: string) { +async function pullFirstTransactionForContractFromEtherscan(network: string, address: string, i?: number) { const params = { module: 'account', action: 'txlist', @@ -331,7 +331,7 @@ async function pullFirstTransactionForContractFromEtherscan(network: string, add page: 1, offset: 10, sort: 'asc', - apikey: getEtherscanApiKey(network) + apikey: getEtherscanApiKey(network, i) }; const url = `${getEtherscanApiUrl(network)}&${paramString(params)}`; const debugUrl = `${getEtherscanApiUrl(network)}&${paramString({ ...params, ...{ apikey: '[API_KEY]' } })}`; @@ -357,11 +357,11 @@ async function getRoninContractDeploymentData(tx: string) { return res.result.input; } -async function getContractCreationCode(network: string, address: string) { +async function getContractCreationCode(network: string, address: string, i: number = 0) { const strategies = [ - scrapeContractCreationCodeFromEtherscan, - scrapeContractCreationCodeFromEtherscanApi, - pullFirstTransactionForContractFromEtherscan, + (net: string, addr: string) => scrapeContractCreationCodeFromEtherscan(net, addr), + (net: string, addr: string) => scrapeContractCreationCodeFromEtherscanApi(net, addr, i), + (net: string, addr: string) => pullFirstTransactionForContractFromEtherscan(net, addr, i), ]; let errors = []; if (network === 'ronin') { @@ -426,103 +426,133 @@ function parseSources({ source, contract, optimized, optimizationRuns }: Ethersc export async function loadRoninContract(network: string, address: string) { const networkName = network; - const apiKey = getEtherscanApiKey('mainnet'); - const roninData = await getRoninApiData(networkName, address, apiKey); - const { language, settings, sources } = parseSources(roninData); - let contractCreationCode = await getContractCreationCode(networkName, address); - let { - abi, - contract, - compiler, - constructorArgs - } = roninData; - let bytecodeWithTxArgs = await getRoninContractDeploymentData(constructorArgs); + const maxRetries = 12; // Maximum number of API key rotations + let lastError: Error | null = null; - constructorArgs = bytecodeWithTxArgs.slice(contractCreationCode.length); - const encodedABI = JSON.stringify(abi); - const contractPath = Object.keys(sources)[0]; - const contractFQN = `${contractPath}:${contract}`; - - const contractBuild = { - contract, - contracts: { - [contractFQN]: { - network, - address, - name: contract, - abi: encodedABI, - bin: contractCreationCode.slice(0, 1), - constructorArgs, - metadata: JSON.stringify({ - compiler: { - version: compiler, - }, - language, - output: { + for (let i = 0; i < maxRetries; i++) { + try { + const apiKey = getEtherscanApiKey('mainnet', i); + const roninData = await getRoninApiData(networkName, address, apiKey); + const { language, settings, sources } = parseSources(roninData); + let contractCreationCode = await getContractCreationCode(networkName, address, i); + let { + abi, + contract, + compiler, + constructorArgs + } = roninData; + let bytecodeWithTxArgs = await getRoninContractDeploymentData(constructorArgs); + + constructorArgs = bytecodeWithTxArgs.slice(contractCreationCode.length); + const encodedABI = JSON.stringify(abi); + const contractPath = Object.keys(sources)[0]; + const contractFQN = `${contractPath}:${contract}`; + + const contractBuild = { + contract, + contracts: { + [contractFQN]: { + network, + address, + name: contract, abi: encodedABI, + bin: contractCreationCode.slice(0, 1), + constructorArgs, + metadata: JSON.stringify({ + compiler: { + version: compiler, + }, + language, + output: { + abi: encodedABI, + }, + devdoc: {}, + sources, + settings, + version: 1, + }), }, - devdoc: {}, - sources, - settings, - version: 1, - }), - }, - }, - version: compiler, - }; + }, + version: compiler, + }; - return contractBuild; + return contractBuild; + } catch (error) { + lastError = error; + debug(`Attempt ${i + 1} failed for loadRoninContract: ${error.message}`); + if (i < maxRetries - 1) { + debug(`Retrying with next API key...`); + } + } + } + + throw new Error(`Failed to load Ronin contract after ${maxRetries} attempts: ${lastError?.message}`); } export async function loadEtherscanContract(network: string, address: string) { - const apiKey = getEtherscanApiKey(network); const networkName = network; - const etherscanData = await getEtherscanApiData(networkName, address, apiKey); - const { - abi, - contract, - compiler, - constructorArgs - } = etherscanData; - const { language, settings, sources } = parseSources(etherscanData); - const contractPath = Object.keys(sources)[0]; - const contractFQN = `${contractPath}:${contract}`; + const maxRetries = 12; // Maximum number of API key rotations + let lastError: Error | null = null; - let contractCreationCode = await getContractCreationCode(networkName, address); - if (contractCreationCode.endsWith(constructorArgs) && constructorArgs.length > 0) { - contractCreationCode = contractCreationCode.slice(0, -constructorArgs.length); - } + for (let i = 0; i < maxRetries; i++) { + try { + const apiKey = getEtherscanApiKey(network, i); + const etherscanData = await getEtherscanApiData(networkName, address, apiKey); + const { + abi, + contract, + compiler, + constructorArgs + } = etherscanData; + const { language, settings, sources } = parseSources(etherscanData); + const contractPath = Object.keys(sources)[0]; + const contractFQN = `${contractPath}:${contract}`; + + let contractCreationCode = await getContractCreationCode(networkName, address, i); + if (contractCreationCode.endsWith(constructorArgs) && constructorArgs.length > 0) { + contractCreationCode = contractCreationCode.slice(0, -constructorArgs.length); + } - const encodedABI = JSON.stringify(abi); - const contractBuild = { - contract, - contracts: { - [contractFQN]: { - network, - address, - name: contract, - abi: encodedABI, - bin: contractCreationCode, - constructorArgs, - metadata: JSON.stringify({ - compiler: { - version: compiler, - }, - language, - output: { + const encodedABI = JSON.stringify(abi); + const contractBuild = { + contract, + contracts: { + [contractFQN]: { + network, + address, + name: contract, abi: encodedABI, + bin: contractCreationCode, + constructorArgs, + metadata: JSON.stringify({ + compiler: { + version: compiler, + }, + language, + output: { + abi: encodedABI, + }, + devdoc: {}, + sources, + settings, + version: 1, + }), }, - devdoc: {}, - sources, - settings, - version: 1, - }), - }, - }, - version: compiler, - }; + }, + version: compiler, + }; - return contractBuild; + return contractBuild; + } catch (error) { + lastError = error; + debug(`Attempt ${i + 1} failed for loadEtherscanContract: ${error.message}`); + if (i < maxRetries - 1) { + debug(`Retrying with next API key...`); + } + } + } + + throw new Error(`Failed to load Etherscan contract after ${maxRetries} attempts: ${lastError?.message}`); } diff --git a/scenario/constraints/ProposalConstraint.ts b/scenario/constraints/ProposalConstraint.ts index b1e45cd7d..df76002d9 100644 --- a/scenario/constraints/ProposalConstraint.ts +++ b/scenario/constraints/ProposalConstraint.ts @@ -78,9 +78,9 @@ export class ProposalConstraint implements StaticConstra ); } - // temporary hack to skip proposal 504 - if (proposal.id.eq(504)) { - console.log('Skipping proposal 504'); + // temporary hack to skip proposal 510 + if (proposal.id.eq(510)) { + console.log('Skipping proposal 510'); continue; } diff --git a/src/deploy/index.ts b/src/deploy/index.ts index 6d9de2386..3757ac900 100644 --- a/src/deploy/index.ts +++ b/src/deploy/index.ts @@ -147,6 +147,8 @@ export const WHALES = { '0x186cF879186986A20aADFb7eAD50e3C20cb26CeC', // tBTC whale '0x620Fe90b1EAcaEa936ea199e7B05F998CA65836a', // tBTC whale '0x54b5569deC8A6A8AE61A36Fd34e5c8945810db8b', // tBTC whale + '0xDBD974Eb5360d053ea0c56B4DaCF4A9D3E894Ee2', // tETH whale + '0xbA1333333333a1BA1108E8412f11850A5C319bA9', // tETH whale ], base: [ '0x6D3c5a4a7aC4B1428368310E4EC3bB1350d01455', // USDbC whale From 98e67837a0e437eb46bdcdae933ab7806caf7564 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Wed, 3 Dec 2025 15:10:04 +0200 Subject: [PATCH 33/65] fix: working arbitrum scenarios --- deployments/arbitrum/usdt/relations.ts | 8 ++++++++ scenario/utils/scenarioHelper.ts | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/deployments/arbitrum/usdt/relations.ts b/deployments/arbitrum/usdt/relations.ts index d53c3a05d..0068ed963 100644 --- a/deployments/arbitrum/usdt/relations.ts +++ b/deployments/arbitrum/usdt/relations.ts @@ -5,6 +5,14 @@ export default { governor: { artifact: 'contracts/bridges/arbitrum/ArbitrumBridgeReceiver.sol:ArbitrumBridgeReceiver' }, + ERC1967Proxy: { + artifact: 'contracts/ERC20.sol:ERC20', + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, // WBTC ClonableBeaconProxy: { artifact: 'contracts/ERC20.sol:ERC20', diff --git a/scenario/utils/scenarioHelper.ts b/scenario/utils/scenarioHelper.ts index d27e42ba7..a104a629c 100644 --- a/scenario/utils/scenarioHelper.ts +++ b/scenario/utils/scenarioHelper.ts @@ -116,13 +116,24 @@ export function getConfigForScenario(ctx: CometContext, i?: number) { config.withdrawAsset = 7000; config.transferAsset = 500000; config.transferBase = 100; + if(i == 8) { // tBTC + config.supplyCollateral = 2; + config.transferCollateral = 2; + config.withdrawCollateral = 2; + } } if (ctx.world.base.network === 'arbitrum' && ctx.world.base.deployment === 'usdt') { config.withdrawAsset = 7000; config.bulkerAsset = 10000; config.bulkerAsset1 = 10000; + config.transferAsset = 10000; config.transferAsset1 = 10000; + if(i == 5) { // tBTC + config.supplyCollateral = 2; + config.transferCollateral = 2; + config.withdrawCollateral = 2; + } } if (ctx.world.base.network === 'arbitrum' && ctx.world.base.deployment === 'usdc.e') { From b2b05a2701ae7a374792d529ab45c83a3507acb5 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Wed, 3 Dec 2025 19:20:53 +0200 Subject: [PATCH 34/65] fix: teth symbol fix --- deployments/relations.ts | 31 ++++++++++++++++++-- hardhat.config.ts | 10 ------- plugins/deployment_manager/RelationConfig.ts | 19 +++++++++++- 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/deployments/relations.ts b/deployments/relations.ts index 4353bc16b..c7b823b32 100644 --- a/deployments/relations.ts +++ b/deployments/relations.ts @@ -45,11 +45,22 @@ const relationConfigMap: RelationConfigMap = { ); }, alias: async (token) => { + const address = token.address.toLowerCase(); + try { - return token.symbol(); + const symbol = await token.symbol(); + return symbol; } catch (e) { - throw new Error(`Failed to get symbol for token ${token.address}`); + // If symbol() fails (e.g., proxy contract in fork), try to get it from storage + // This is a workaround for contracts that don't work in Hardhat fork + + // invalid opcode when calling symbol() + if (address === '0xd09acb80c1e8f2291862c4978a008791c9167003') { + return 'tETH'; + } + + throw new Error(`Failed to get symbol for token ${token.address}: ${e.message}`); } }, }, @@ -63,7 +74,21 @@ const relationConfigMap: RelationConfigMap = { }) ); }, - alias: async (_, { assets }, i) => `${await assets[i].symbol()}:priceFeed`, + alias: async (_, { assets }, i) => { + try { + return `${await assets[i].symbol()}:priceFeed`; + } catch (e) { + // invalid opcode when calling symbol() + const address = assets[i].address.toLowerCase(); + + // Known contract mappings for Arbitrum + if (address === '0xd09acb80c1e8f2291862c4978a008791c9167003') { + return 'tETH:priceFeed'; + } + + throw new Error(`Failed to get symbol for token ${assets[i].address}: ${e.message}`); + } + }, }, cometAdmin: { field: { diff --git a/hardhat.config.ts b/hardhat.config.ts index 79910f9b3..63d2caae8 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -346,16 +346,6 @@ const config: HardhatUserConfig = { }; return acc; } - if (chainId === 42161) { - acc[chainId] = { - hardforkHistory: { - berlin: 1, - london: 2, - shanghai: 3, - } - }; - return acc; - } acc[chainId] = { hardforkHistory: { berlin: 1, diff --git a/plugins/deployment_manager/RelationConfig.ts b/plugins/deployment_manager/RelationConfig.ts index fccbbd90b..1be3d8cd4 100644 --- a/plugins/deployment_manager/RelationConfig.ts +++ b/plugins/deployment_manager/RelationConfig.ts @@ -80,7 +80,24 @@ async function readKey(contract: Contract, fnName: string): Promise { if (!fn) { throw new Error(`Cannot find contract function ${await contract.address}.${fnName}()`); } - return await fn(); + + try { + const result = await fn(); + return result; + } catch (e) { + // Handle contracts that fail in Hardhat fork but work on real network + // This is a workaround for proxy contracts with incompatible bytecode + const address = contract.address.toLowerCase(); + + if (e.code === 'CALL_EXCEPTION' && fnName === 'symbol') { + // invalid opcode when calling symbol() + if (address === '0xd09acb80c1e8f2291862c4978a008791c9167003') { + return 'tETH'; + } + } + + throw e; + } } export async function readField(contract: Contract, fieldKey: FieldKey, context: Ctx): Promise { From a0fdad70e8e7829b7ed2afc6c9da6d8405bad6da Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Wed, 3 Dec 2025 21:16:18 +0200 Subject: [PATCH 35/65] fix: add debug for spider --- .github/workflows/run-scenarios.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/run-scenarios.yaml b/.github/workflows/run-scenarios.yaml index 64311a570..bbb576eff 100644 --- a/.github/workflows/run-scenarios.yaml +++ b/.github/workflows/run-scenarios.yaml @@ -66,6 +66,8 @@ jobs: - name: Spider Contracts on Mainnet run: yarn hardhat spider --network mainnet --deployment usdc + env: + DEBUG: true # Upload only the prepared artifacts you need (no node_modules) - name: Upload prepared state From e7f8ce6833887fb5a019e4c544f0884bd3fc5d52 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Mon, 22 Dec 2025 12:11:34 +0200 Subject: [PATCH 36/65] fix: ronin and forge test fixes --- .../1761125221_upgrade_to_capo_price_feeds.ts | 165 +++++++++ .../1761228877_upgrade_to_capo_price_feeds.ts | 324 ++++++++++++++++++ .../1735299664_upgrade_to_capo_price_feeds.ts | 4 +- .../helpers/GovernanceHelper.sol | 7 +- hardhat.config.ts | 1 + .../deployment_manager/DeploymentManager.ts | 4 +- scenario/SupplyScenario.ts | 20 +- scenario/TransferScenario.ts | 61 ++-- scenario/utils/index.ts | 2 +- scenario/utils/relayMessage.ts | 2 +- scenario/utils/scenarioHelper.ts | 13 +- src/deploy/index.ts | 9 +- 12 files changed, 560 insertions(+), 52 deletions(-) create mode 100644 deployments/base/aero/migrations/1761125221_upgrade_to_capo_price_feeds.ts create mode 100644 deployments/base/weth/migrations/1761228877_upgrade_to_capo_price_feeds.ts diff --git a/deployments/base/aero/migrations/1761125221_upgrade_to_capo_price_feeds.ts b/deployments/base/aero/migrations/1761125221_upgrade_to_capo_price_feeds.ts new file mode 100644 index 000000000..2a6172bc0 --- /dev/null +++ b/deployments/base/aero/migrations/1761125221_upgrade_to_capo_price_feeds.ts @@ -0,0 +1,165 @@ +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { calldata, proposal } from '../../../../src/deploy'; +import { utils } from 'ethers'; +import { Numeric } from '../../../../test/helpers'; +import { AggregatorV3Interface } from '../../../../build/types'; + +export function exp(i: number, d: Numeric = 0, r: Numeric = 6): bigint { + return (BigInt(Math.floor(i * 10 ** Number(r))) * 10n ** BigInt(d)) / 10n ** BigInt(r); +} + +const ETH_USD_PRICE_FEED = '0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70'; + +const WSTETH_ADDRESS = '0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452'; +const WSTETH_STETH_PRICE_FEED_ADDRESS = '0xB88BAc61a4Ca37C43a3725912B1f472c9A5bc061'; + +const FEED_DECIMALS = 8; +const blockToFetch = 36000000; + +let newWstETHPriceFeed: string; +let oldWstETHPriceFeed: string; + +export default migration('1761125221_upgrade_to_capo_price_feeds', { + async prepare(deploymentManager: DeploymentManager) { + const { timelock } = await deploymentManager.getContracts(); + const blockToFetchTimestamp = (await deploymentManager.hre.ethers.provider.getBlock(blockToFetch))!.timestamp; + + //1. wstEth + const rateProviderWstEth = await deploymentManager.existing('wstEth:priceFeed', WSTETH_STETH_PRICE_FEED_ADDRESS, 'base', 'contracts/capo/contracts/interfaces/AggregatorV3Interface.sol:AggregatorV3Interface') as AggregatorV3Interface; + const [, currentRatioWstEth] = await rateProviderWstEth.latestRoundData({ blockTag: blockToFetch }); + + const wstEthCapoPriceFeed = await deploymentManager.deploy( + 'wstETH:priceFeed', + 'capo/contracts/ChainlinkCorrelatedAssetsPriceOracle.sol', + [ + timelock.address, + ETH_USD_PRICE_FEED, + WSTETH_STETH_PRICE_FEED_ADDRESS, + 'wstETH / USD CAPO Price Feed', + FEED_DECIMALS, + 3600, + { + snapshotRatio: currentRatioWstEth, + snapshotTimestamp: blockToFetchTimestamp, + maxYearlyRatioGrowthPercent: exp(0.0404, 4) + } + ], + true + ); + + return { + wstEthCapoPriceFeedAddress: wstEthCapoPriceFeed.address + }; + }, + + async enact(deploymentManager: DeploymentManager, govDeploymentManager: DeploymentManager, { + wstEthCapoPriceFeedAddress + }) { + newWstETHPriceFeed = wstEthCapoPriceFeedAddress; + + const trace = deploymentManager.tracer(); + + const { + configurator, + comet, + bridgeReceiver, + cometAdmin + } = await deploymentManager.getContracts(); + + const { + governor, + baseL1CrossDomainMessenger + } = await govDeploymentManager.getContracts(); + + const updateWstEthPriceFeedCalldata = await calldata( + configurator.populateTransaction.updateAssetPriceFeed( + comet.address, + WSTETH_ADDRESS, + wstEthCapoPriceFeedAddress + ) + ); + + const deployAndUpgradeToCalldata = await calldata( + cometAdmin.populateTransaction.deployAndUpgradeTo( + configurator.address, + comet.address + ) + ); + + const l2ProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [configurator.address, cometAdmin.address], + [0, 0], + ['updateAssetPriceFeed(address,address,address)', 'deployAndUpgradeTo(address,address)'], + [updateWstEthPriceFeedCalldata, deployAndUpgradeToCalldata], + ] + ); + + [,, oldWstETHPriceFeed] = await comet.getAssetInfoByAddress(WSTETH_ADDRESS); + + const mainnetActions = [ + { + contract: baseL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [ + bridgeReceiver.address, + l2ProposalData, + 3_000_000 + ] + }, + ]; + + const description = `# Update wstETH price feed in cAEROv3 on Base with CAPO implementation. + +## Proposal summary + +This proposal updates existing price feeds for wstETH on the AERO market on Base. + +### CAPO summary + +CAPO is a price oracle adapter designed to support assets that grow gradually relative to a base asset - such as liquid staking tokens that accumulate yield over time. It provides a mechanism to track this expected growth while protecting downstream protocol from sudden or manipulated price spikes. wstETH price feed is updated to their CAPO implementations. + +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1038) and [forum discussion for CAPO](https://www.comp.xyz/t/woof-correlated-assets-price-oracle-capo/6245). + +### CAPO audit + +CAPO has been audited by [OpenZeppelin](https://www.comp.xyz/t/capo-price-feed-audit/6631, as well as the LST / LRT implementation [here](https://www.comp.xyz/t/capo-lst-lrt-audit/7118). + +## Proposal actions + +The first action updates wstETH price feed to the CAPO implementation. This sends the encoded 'updateAssetPriceFeed' and 'deployAndUpgradeTo' calls across the bridge to the governance receiver on Base. +`; + + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ) + ); + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(deploymentManager: DeploymentManager): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + const { comet, configurator } = await deploymentManager.getContracts(); + + const wstETHIndexInComet = await configurator.getAssetIndex(comet.address, WSTETH_ADDRESS); + + // Check if the price feeds are set correctly. + const wstETHInCometInfo = await comet.getAssetInfoByAddress(WSTETH_ADDRESS); + const wstETHInConfiguratorInfoWETHComet = (await configurator.getConfiguration(comet.address)).assetConfigs[wstETHIndexInComet]; + + expect(wstETHInCometInfo.priceFeed).to.eq(newWstETHPriceFeed); + expect(wstETHInConfiguratorInfoWETHComet.priceFeed).to.eq(newWstETHPriceFeed); + expect(await comet.getPrice(newWstETHPriceFeed)).to.equal(await comet.getPrice(oldWstETHPriceFeed)); + }, +}); diff --git a/deployments/base/weth/migrations/1761228877_upgrade_to_capo_price_feeds.ts b/deployments/base/weth/migrations/1761228877_upgrade_to_capo_price_feeds.ts new file mode 100644 index 000000000..8ac4fb51c --- /dev/null +++ b/deployments/base/weth/migrations/1761228877_upgrade_to_capo_price_feeds.ts @@ -0,0 +1,324 @@ +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { calldata, proposal } from '../../../../src/deploy'; +import { utils } from 'ethers'; +import { Numeric } from '../../../../test/helpers'; +import { AggregatorV3Interface } from '../../../../build/types'; + +export function exp(i: number, d: Numeric = 0, r: Numeric = 6): bigint { + return (BigInt(Math.floor(i * 10 ** Number(r))) * 10n ** BigInt(d)) / 10n ** BigInt(r); +} + +const WSTETH_ADDRESS = '0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452'; +const WSTETH_STETH_PRICE_FEED_ADDRESS = '0xB88BAc61a4Ca37C43a3725912B1f472c9A5bc061'; + +const EZETH_ADDRESS = '0x2416092f143378750bb29b79ed961ab195cceea5'; +const EZETH_TO_ETH_PRICE_FEED_ADDRESS = '0xC4300B7CF0646F0Fe4C5B2ACFCCC4dCA1346f5d8'; + +const WRSETH_ADDRESS = '0xEDfa23602D0EC14714057867A78d01e94176BEA0'; +const WRSETH_ORACLE = '0xe8dD07CCf5BC4922424140E44Eb970F5950725ef'; + +const WEETH_ADDRESS = '0x04C0599Ae5A44757c0af6F9eC3b93da8976c150A'; +const WEETH_STETH_PRICE_FEED_ADDRESS = '0x35e9D7001819Ea3B39Da906aE6b06A62cfe2c181'; + +const blockToFetch = 36000000; + +let newWstETHToETHPriceFeed: string; +let newEzETHToETHPriceFeed: string; +let newWrsEthToETHPriceFeed: string; +let newWeEthToETHPriceFeed: string; + +let oldWstETHToETHPriceFeed: string; +let oldEzETHToETHPriceFeed: string; +let oldWrsEthToETHPriceFeed: string; +let oldWeEthToETHPriceFeed: string; + +const FEED_DECIMALS = 8; +export default migration('1761228877_upgrade_to_capo_price_feeds', { + async prepare(deploymentManager: DeploymentManager) { + const { timelock } = await deploymentManager.getContracts(); + const blockToFetchTimestamp = (await deploymentManager.hre.ethers.provider.getBlock(blockToFetch))!.timestamp; + const constantPriceFeed = await deploymentManager.fromDep('WETH:priceFeed', 'base', 'weth'); + + //1. wstEth + const rateProviderWstEth = await deploymentManager.existing('wstETH:_rateProvider', WSTETH_STETH_PRICE_FEED_ADDRESS, 'base', 'contracts/capo/contracts/interfaces/AggregatorV3Interface.sol:AggregatorV3Interface') as AggregatorV3Interface; + const [, currentRatioWstEth] = await rateProviderWstEth.latestRoundData({blockTag: blockToFetch}); + + const wstEthCapoPriceFeed = await deploymentManager.deploy( + 'wstETH:priceFeed', + 'capo/contracts/ChainlinkCorrelatedAssetsPriceOracle.sol', + [ + timelock.address, + constantPriceFeed.address, + WSTETH_STETH_PRICE_FEED_ADDRESS, + 'wstETH / ETH CAPO Price Feed', + FEED_DECIMALS, + 3600, + { + snapshotRatio: currentRatioWstEth, + snapshotTimestamp: blockToFetchTimestamp, + maxYearlyRatioGrowthPercent: exp(0.0404, 4) + } + ], + true + ); + + //2. ezEth + const rateProviderEzEth = await deploymentManager.existing('ezETH:_rateProvider', EZETH_TO_ETH_PRICE_FEED_ADDRESS, 'base', 'contracts/capo/contracts/interfaces/AggregatorV3Interface.sol:AggregatorV3Interface') as AggregatorV3Interface; + const [, currentRatioEzEth] = await rateProviderEzEth.latestRoundData({blockTag: blockToFetch}); + const ezEthCapoPriceFeed = await deploymentManager.deploy( + 'ezETH:priceFeed', + 'capo/contracts/ChainlinkCorrelatedAssetsPriceOracle.sol', + [ + timelock.address, + constantPriceFeed.address, + EZETH_TO_ETH_PRICE_FEED_ADDRESS, + 'ezETH / ETH CAPO Price Feed', + FEED_DECIMALS, + 3600, + { + snapshotRatio: currentRatioEzEth, + snapshotTimestamp: blockToFetchTimestamp, + maxYearlyRatioGrowthPercent: exp(0.0707, 4) + } + ], + true + ); + + const rateProviderRsEth = await deploymentManager.existing('rsETH:_rateProvider', WRSETH_ORACLE, 'base', 'contracts/capo/contracts/interfaces/AggregatorV3Interface.sol:AggregatorV3Interface') as AggregatorV3Interface; + const [, currentRatioWrsEth] = await rateProviderRsEth.latestRoundData({blockTag: blockToFetch}); + const rsEthCapoPriceFeed = await deploymentManager.deploy( + 'rsETH:priceFeed', + 'capo/contracts/ChainlinkCorrelatedAssetsPriceOracle.sol', + [ + timelock.address, + constantPriceFeed.address, + WRSETH_ORACLE, + 'rsETH / ETH CAPO Price Feed', + FEED_DECIMALS, + 3600, + { + snapshotRatio: currentRatioWrsEth, + snapshotTimestamp: blockToFetchTimestamp, + maxYearlyRatioGrowthPercent: exp(0.0554, 4) + } + ], + true + ); + + + const rateProviderWeEth = await deploymentManager.existing('weETH:_rateProvider', WEETH_STETH_PRICE_FEED_ADDRESS, 'base', 'contracts/capo/contracts/interfaces/AggregatorV3Interface.sol:AggregatorV3Interface') as AggregatorV3Interface; + const [, currentRatioWeEth] = await rateProviderWeEth.latestRoundData({blockTag: blockToFetch}); + const weEthCapoPriceFeed = await deploymentManager.deploy( + 'weETH:priceFeed', + 'capo/contracts/ChainlinkCorrelatedAssetsPriceOracle.sol', + [ + timelock.address, + constantPriceFeed.address, + WEETH_STETH_PRICE_FEED_ADDRESS, + 'weETH / ETH CAPO Price Feed', + FEED_DECIMALS, + 3600, + { + snapshotRatio: currentRatioWeEth, + snapshotTimestamp: blockToFetchTimestamp, + maxYearlyRatioGrowthPercent: exp(0.0323, 4) + } + ], + true + ); + + return { + wstEthCapoPriceFeedAddress: wstEthCapoPriceFeed.address, + ezEthCapoPriceFeedAddress: ezEthCapoPriceFeed.address, + rsEthCapoPriceFeedAddress: rsEthCapoPriceFeed.address, + weEthCapoPriceFeedAddress: weEthCapoPriceFeed.address + }; + }, + + async enact(deploymentManager: DeploymentManager, govDeploymentManager, { + wstEthCapoPriceFeedAddress, + ezEthCapoPriceFeedAddress, + rsEthCapoPriceFeedAddress, + weEthCapoPriceFeedAddress + }) { + + newWstETHToETHPriceFeed = wstEthCapoPriceFeedAddress; + newEzETHToETHPriceFeed = ezEthCapoPriceFeedAddress; + newWrsEthToETHPriceFeed = rsEthCapoPriceFeedAddress; + newWeEthToETHPriceFeed = weEthCapoPriceFeedAddress; + + const trace = deploymentManager.tracer(); + + const { + configurator, + comet, + bridgeReceiver, + cometAdmin + } = await deploymentManager.getContracts(); + + const { + governor, + baseL1CrossDomainMessenger + } = await govDeploymentManager.getContracts(); + + const updateEzEthPriceFeedCalldata = await calldata( + configurator.populateTransaction.updateAssetPriceFeed( + comet.address, + EZETH_ADDRESS, + ezEthCapoPriceFeedAddress + ) + ); + + const updateWstEthPriceFeedCalldata = await calldata( + configurator.populateTransaction.updateAssetPriceFeed( + comet.address, + WSTETH_ADDRESS, + wstEthCapoPriceFeedAddress + ) + ); + + const updateRsEthPriceFeedCalldata = await calldata( + configurator.populateTransaction.updateAssetPriceFeed( + comet.address, + WRSETH_ADDRESS, + rsEthCapoPriceFeedAddress + ) + ); + + const updateWeEthPriceFeedCalldata = await calldata( + configurator.populateTransaction.updateAssetPriceFeed( + comet.address, + WEETH_ADDRESS, + weEthCapoPriceFeedAddress + ) + ); + + const deployAndUpgradeToCalldata = utils.defaultAbiCoder.encode( + ['address', 'address'], + [configurator.address, comet.address] + ); + + const l2ProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + configurator.address, + configurator.address, + configurator.address, + configurator.address, + cometAdmin.address + ], + [0, 0, 0, 0, 0], + [ + 'updateAssetPriceFeed(address,address,address)', + 'updateAssetPriceFeed(address,address,address)', + 'updateAssetPriceFeed(address,address,address)', + 'updateAssetPriceFeed(address,address,address)', + 'deployAndUpgradeTo(address,address)' + ], + [ + updateWstEthPriceFeedCalldata, + updateEzEthPriceFeedCalldata, + updateRsEthPriceFeedCalldata, + updateWeEthPriceFeedCalldata, + deployAndUpgradeToCalldata + ], + ] + ); + + [,, oldWstETHToETHPriceFeed] = await comet.getAssetInfoByAddress(WSTETH_ADDRESS); + [,, oldEzETHToETHPriceFeed] = await comet.getAssetInfoByAddress(EZETH_ADDRESS); + [,, oldWrsEthToETHPriceFeed] = await comet.getAssetInfoByAddress(WRSETH_ADDRESS); + [,, oldWeEthToETHPriceFeed] = await comet.getAssetInfoByAddress(WEETH_ADDRESS); + + const mainnetActions = [ + { + contract: baseL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [ + bridgeReceiver.address, + l2ProposalData, + 3_000_000 + ] + }, + ]; + + const description = `# Update price feeds in cWETHv3 on Base with CAPO implementation. + +## Proposal summary + +This proposal updates existing price feeds for wstETH, ezETH, rsETH, and weETH on the WETH market on Base. + +### CAPO summary + +CAPO is a price oracle adapter designed to support assets that grow gradually relative to a base asset - such as liquid staking tokens that accumulate yield over time. It provides a mechanism to track this expected growth while protecting downstream protocol from sudden or manipulated price spikes. wstETH, ezETH, rsETH, and weETH price feeds are updated to their CAPO implementations. + +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1040) and [forum discussion for CAPO](https://www.comp.xyz/t/woof-correlated-assets-price-oracle-capo/6245). + +### CAPO audit + +CAPO has been audited by [OpenZeppelin](https://www.comp.xyz/t/capo-price-feed-audit/6631, as well as the LST / LRT implementation [here](https://www.comp.xyz/t/capo-lst-lrt-audit/7118). + +## Proposal actions + +The first action updates wstETH, ezETH, rsETH, and weETH price feeds to the CAPO implementation. This sends the encoded 'updateAssetPriceFeed' and 'deployAndUpgradeTo' calls across the bridge to the governance receiver on Base. +`; + const txn = await govDeploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ) + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(deploymentManager: DeploymentManager): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + const { comet, configurator } = await deploymentManager.getContracts(); + + // 1. wstETH + const wstETHIndexInComet = await configurator.getAssetIndex(comet.address, WSTETH_ADDRESS); + const wstETHInCometInfo = await comet.getAssetInfoByAddress(WSTETH_ADDRESS); + const wstETHInConfiguratorInfoWETHComet = (await configurator.getConfiguration(comet.address)).assetConfigs[wstETHIndexInComet]; + + expect(wstETHInCometInfo.priceFeed).to.eq(newWstETHToETHPriceFeed); + expect(wstETHInConfiguratorInfoWETHComet.priceFeed).to.eq(newWstETHToETHPriceFeed); + expect(await comet.getPrice(newWstETHToETHPriceFeed)).to.be.closeTo(await comet.getPrice(oldWstETHToETHPriceFeed), 1e6); + + // 2. ezETH + const ezETHIndexInComet = await configurator.getAssetIndex(comet.address, EZETH_ADDRESS); + const ezETHInCometInfo = await comet.getAssetInfoByAddress(EZETH_ADDRESS); + const ezETHInConfiguratorInfoWETHComet = (await configurator.getConfiguration(comet.address)).assetConfigs[ezETHIndexInComet]; + + expect(ezETHInCometInfo.priceFeed).to.eq(newEzETHToETHPriceFeed); + expect(ezETHInConfiguratorInfoWETHComet.priceFeed).to.eq(newEzETHToETHPriceFeed); + expect(await comet.getPrice(newEzETHToETHPriceFeed)).to.equal(await comet.getPrice(oldEzETHToETHPriceFeed)); + + // 3. wrsETH + const wrsETHIndexInComet = await configurator.getAssetIndex(comet.address, WRSETH_ADDRESS); + const wrsETHInCometInfo = await comet.getAssetInfoByAddress(WRSETH_ADDRESS); + const wrsETHInConfiguratorInfoWETHComet = (await configurator.getConfiguration(comet.address)).assetConfigs[wrsETHIndexInComet]; + + expect(wrsETHInCometInfo.priceFeed).to.eq(newWrsEthToETHPriceFeed); + expect(wrsETHInConfiguratorInfoWETHComet.priceFeed).to.eq(newWrsEthToETHPriceFeed); + expect(await comet.getPrice(newWrsEthToETHPriceFeed)).to.equal(await comet.getPrice(oldWrsEthToETHPriceFeed)); + + // 4. weETH + const weETHIndexInComet = await configurator.getAssetIndex(comet.address, WEETH_ADDRESS); + const weETHInCometInfo = await comet.getAssetInfoByAddress(WEETH_ADDRESS); + const weETHInConfiguratorInfoWETHComet = (await configurator.getConfiguration(comet.address)).assetConfigs[weETHIndexInComet]; + + expect(weETHInCometInfo.priceFeed).to.eq(newWeEthToETHPriceFeed); + expect(weETHInConfiguratorInfoWETHComet.priceFeed).to.eq(newWeEthToETHPriceFeed); + expect(await comet.getPrice(newWeEthToETHPriceFeed)).to.equal(await comet.getPrice(oldWeEthToETHPriceFeed)); + }, +}); diff --git a/deployments/mainnet/usdt/migrations/1735299664_upgrade_to_capo_price_feeds.ts b/deployments/mainnet/usdt/migrations/1735299664_upgrade_to_capo_price_feeds.ts index 399fe8401..efe7f8750 100644 --- a/deployments/mainnet/usdt/migrations/1735299664_upgrade_to_capo_price_feeds.ts +++ b/deployments/mainnet/usdt/migrations/1735299664_upgrade_to_capo_price_feeds.ts @@ -262,11 +262,11 @@ export default migration('1735299664_upgrade_to_capo_price_feeds', { This proposal updates existing price feeds for wstETH, sFRAX, weETH, WBTC, WETH, mETH, COMP, and LINK on the USDT market on Mainnet. -SVR summery +## SVR summary [RFP process](https://www.comp.xyz/t/oev-rfp-process-update-july-2025/6945) and community [vote](https://snapshot.box/#/s:comp-vote.eth/proposal/0x98a3873319cdb5a4c66b6f862752bdcfb40d443a5b9c2f9472188d7ed5f9f2e0) passed and decided to implement Chainlink's SVR solution for Mainnet markets, this proposal updates wstETH, WBTC, WETH, LINK, weETH, mETH, COMP price feeds to support SVR implementations. -CAPO summery +## CAPO summary CAPO is a price oracle adapter designed to support assets that grow gradually relative to a base asset - such as liquid staking tokens that accumulate yield over time. It provides a mechanism to track this expected growth while protecting downstream protocol from sudden or manipulated price spikes. wstETH, sFRAX, weETH, mETH price feeds are updated to their CAPO implementations. diff --git a/forge/script/marketupdates/helpers/GovernanceHelper.sol b/forge/script/marketupdates/helpers/GovernanceHelper.sol index eaaf77422..f56257cfb 100644 --- a/forge/script/marketupdates/helpers/GovernanceHelper.sol +++ b/forge/script/marketupdates/helpers/GovernanceHelper.sol @@ -210,7 +210,7 @@ library GovernanceHelper { } function voteOnProposal(Vm vm, uint256 proposalId, address proposalCreator) public { - address[12] memory voters = getTopDelegates(); + address[11] memory voters = getTopDelegates(); console.log("Voting on proposal with ID: ", proposalId); console.log("Proposal Creator: ", proposalCreator); @@ -225,12 +225,11 @@ library GovernanceHelper { } } - function getTopDelegates() public pure returns (address[12] memory) { + function getTopDelegates() public pure returns (address[11] memory) { return [ 0x070341aA5Ed571f0FB2c4a5641409B1A46b4961b, 0x0579A616689f7ed748dC07692A3F150D44b0CA09, - 0x9AA835Bc7b8cE13B9B0C9764A52FbF71AC62cCF1, - 0x7E959eAB54932f5cFd10239160a7fd6474171318, + 0x66cD62c6F8A4BB0Cd8720488BCBd1A6221B765F9, 0x2210dc066aacB03C9676C4F1b36084Af14cCd02E, 0x88F659b4B6D5614B991c6404b34f821e10390eC0, 0xb06DF4dD01a5c5782f360aDA9345C87E86ADAe3D, diff --git a/hardhat.config.ts b/hardhat.config.ts index 63d2caae8..480c078b3 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -342,6 +342,7 @@ const config: HardhatUserConfig = { hardforkHistory: { berlin: 1, london: 2, + shanghai: 3, } }; return acc; diff --git a/plugins/deployment_manager/DeploymentManager.ts b/plugins/deployment_manager/DeploymentManager.ts index 2bcfc2357..5ddf68d71 100644 --- a/plugins/deployment_manager/DeploymentManager.ts +++ b/plugins/deployment_manager/DeploymentManager.ts @@ -282,7 +282,7 @@ export class DeploymentManager { } } - stashRelayMessage(messanger: string, callData: string, signer: string) { + stashRelayMessage(messenger: string, callData: string, signer: string) { try { const cacheDir = path.resolve(__dirname, '../..', 'cache'); mkdirSync(cacheDir, { recursive: true }); @@ -301,7 +301,7 @@ export class DeploymentManager { } } - const newEntry = { messanger, callData, signer }; + const newEntry = { messenger, callData, signer }; if (!data.some(entry => JSON.stringify(entry) === JSON.stringify(newEntry))) { data.push(newEntry); writeFileSync(file, JSON.stringify(data, null, 2), 'utf8'); diff --git a/scenario/SupplyScenario.ts b/scenario/SupplyScenario.ts index be3be8537..10a02a33f 100644 --- a/scenario/SupplyScenario.ts +++ b/scenario/SupplyScenario.ts @@ -406,12 +406,20 @@ scenario( scenario( 'Comet#supplyFrom > repay borrow', { - tokenBalances: { - albert: { $base: 1010 } - }, - cometBalances: { - betty: { $base: '<= -1000' } // in units of asset, not wei - }, + tokenBalances: async (ctx) => ( + { + albert: { + $base: getConfigForScenario(ctx).supplyBase + (0.01 * getConfigForScenario(ctx).supplyBase) + } + } + ), + cometBalances: async (ctx) => ( + { + betty: { + $base: `<= -${getConfigForScenario(ctx).supplyBase}` + } + } + ), }, async ({ comet, actors }, context) => { const { albert, betty } = actors; diff --git a/scenario/TransferScenario.ts b/scenario/TransferScenario.ts index e5c94310b..0039b9601 100644 --- a/scenario/TransferScenario.ts +++ b/scenario/TransferScenario.ts @@ -180,32 +180,35 @@ scenario( scenario( 'Comet#transferFrom > withdraw to repay', { - cometBalances: { - albert: { $base: 1000, $asset0: 50 }, // in units of asset, not wei - betty: { $base: -1000 }, - charles: { $base: 1000 }, // to give the protocol enough base for others to borrow from - }, + cometBalances: async (ctx) => ( + { + albert: { $base: getConfigForScenario(ctx).transferBase, $asset0: getConfigForScenario(ctx).transferAsset2 }, // in units of asset, not wei + betty: { $base: -getConfigForScenario(ctx).transferBase }, + charles: { $base: getConfigForScenario(ctx).transferBase }, // to give the protocol enough base for others to borrow from + } + ), }, async ({ comet, actors }, context) => { const { albert, betty } = actors; const baseAssetAddress = await comet.baseToken(); const baseAsset = context.getAssetByAddress(baseAssetAddress); const scale = (await comet.baseScale()).toBigInt(); + const amountTransferred = BigInt(getConfigForScenario(context).transferBase) * scale; const utilization = await comet.getUtilization(); const borrowRate = (await comet.getBorrowRate(utilization)).toBigInt(); // XXX 70 seconds?! - expectApproximately(await albert.getCometBaseBalance(), 1000n * scale, getInterest(1000n * scale, borrowRate, BigInt(getConfigForScenario(context).interestSeconds)) + 2n); - expectApproximately(await betty.getCometBaseBalance(), -1000n * scale, getInterest(1000n * scale, borrowRate, BigInt(getConfigForScenario(context).interestSeconds)) + 2n); + expectApproximately(await albert.getCometBaseBalance(), amountTransferred, getInterest(amountTransferred, borrowRate, BigInt(getConfigForScenario(context).interestSeconds)) + 2n); + expectApproximately(await betty.getCometBaseBalance(), -amountTransferred, getInterest(amountTransferred, borrowRate, BigInt(getConfigForScenario(context).interestSeconds)) + 2n); await albert.allow(betty, true); // Betty withdraws from Albert to repay her own borrows - const toTransfer = 999n * scale; // XXX cannot withdraw 1000 (to ~0) + const toTransfer = amountTransferred - scale; // XXX cannot withdraw 1000 (to ~0) const txn = await betty.transferAssetFrom({ src: albert.address, dst: betty.address, asset: baseAsset.address, amount: toTransfer }); - expectApproximately(await albert.getCometBaseBalance(), scale, getInterest(1000n * scale, borrowRate, BigInt(getConfigForScenario(context).interestSeconds)) + 2n); - expectApproximately(await betty.getCometBaseBalance(), -scale, getInterest(1000n * scale, borrowRate, BigInt(getConfigForScenario(context).interestSeconds)) + 2n); + expectApproximately(await albert.getCometBaseBalance(), scale, getInterest(amountTransferred, borrowRate, BigInt(getConfigForScenario(context).interestSeconds)) + 2n); + expectApproximately(await betty.getCometBaseBalance(), -scale, getInterest(amountTransferred, borrowRate, BigInt(getConfigForScenario(context).interestSeconds)) + 2n); return txn; // return txn to measure gas } @@ -214,26 +217,29 @@ scenario( scenario( 'Comet#transfer base reverts if undercollateralized', { - cometBalances: { - albert: { $base: 1000, $asset0: 0.000001 }, // in units of asset, not wei - betty: { $base: -1000 }, - charles: { $base: 1000 }, // to give the protocol enough base for others to borrow from - }, + cometBalances: async (ctx) => ( + { + albert: { $base: getConfigForScenario(ctx).transferBase, $asset0: 0.000001 }, // in units of asset, not wei + betty: { $base: -getConfigForScenario(ctx).transferBase }, + charles: { $base: getConfigForScenario(ctx).transferBase }, // to give the protocol enough base for others to borrow from + } + ), }, async ({ comet, actors }, context) => { const { albert, betty } = actors; const baseAssetAddress = await comet.baseToken(); const baseAsset = context.getAssetByAddress(baseAssetAddress); const scale = (await comet.baseScale()).toBigInt(); + const amountTransferred = BigInt(getConfigForScenario(context).transferBase) * scale; const utilization = await comet.getUtilization(); const borrowRate = (await comet.getBorrowRate(utilization)).toBigInt(); // XXX 100 seconds?! - expectApproximately(await albert.getCometBaseBalance(), 1000n * scale, getInterest(1000n * scale, borrowRate, 100n) + 2n); - expectApproximately(await betty.getCometBaseBalance(), -1000n * scale, getInterest(1000n * scale, borrowRate, 100n) + 2n); + expectApproximately(await albert.getCometBaseBalance(), amountTransferred, getInterest(amountTransferred, borrowRate, BigInt(getConfigForScenario(context).interestSeconds)) + 2n); + expectApproximately(await betty.getCometBaseBalance(), -amountTransferred, getInterest(amountTransferred, borrowRate, 100n) + 2n); // Albert with positive balance transfers to Betty with negative balance - const toTransfer = 2001n * scale; // XXX min borrow... + const toTransfer = 2n*amountTransferred + scale; // XXX min borrow... await expectRevertCustom( albert.transferAsset({ dst: betty.address, @@ -248,28 +254,31 @@ scenario( scenario( 'Comet#transferFrom base reverts if undercollateralized', { - cometBalances: { - albert: { $base: 1000, $asset0: 0.000001 }, // in units of asset, not wei - betty: { $base: -1000 }, - charles: { $base: 1000 }, // to give the protocol enough base for others to borrow from - }, + cometBalances: async (ctx) => ( + { + albert: { $base: getConfigForScenario(ctx).transferBase, $asset0: 0.000001 }, // in units of asset, not wei + betty: { $base: -getConfigForScenario(ctx).transferBase }, + charles: { $base: getConfigForScenario(ctx).transferBase }, // to give the protocol enough base for others to borrow from + } + ), }, async ({ comet, actors }, context) => { const { albert, betty } = actors; const baseAssetAddress = await comet.baseToken(); const baseAsset = context.getAssetByAddress(baseAssetAddress); const scale = (await comet.baseScale()).toBigInt(); + const amountTransferred = BigInt(getConfigForScenario(context).transferBase) * scale; const utilization = await comet.getUtilization(); const borrowRate = (await comet.getBorrowRate(utilization)).toBigInt(); // XXX 70 seconds?! - expectApproximately(await albert.getCometBaseBalance(), 1000n * scale, getInterest(1000n * scale, borrowRate, BigInt(getConfigForScenario(context).interestSeconds)) + 2n); - expectApproximately(await betty.getCometBaseBalance(), -1000n * scale, getInterest(1000n * scale, borrowRate, BigInt(getConfigForScenario(context).interestSeconds)) + 2n); + expectApproximately(await albert.getCometBaseBalance(), amountTransferred, getInterest(amountTransferred, borrowRate, BigInt(getConfigForScenario(context).interestSeconds)) + 2n); + expectApproximately(await betty.getCometBaseBalance(), -amountTransferred, getInterest(amountTransferred, borrowRate, BigInt(getConfigForScenario(context).interestSeconds)) + 2n); await albert.allow(betty, true); // Albert with positive balance transfers to Betty with negative balance - const toTransfer = 2001n * scale; // XXX min borrow... + const toTransfer = 2n*amountTransferred + scale; // XXX min borrow... await expectRevertCustom( betty.transferAssetFrom({ src: albert.address, diff --git a/scenario/utils/index.ts b/scenario/utils/index.ts index 410d7c318..23f94ddfa 100644 --- a/scenario/utils/index.ts +++ b/scenario/utils/index.ts @@ -910,7 +910,7 @@ export async function tenderlyExecute( return { network_id: chainId2.toString(), from: msg.signer, - to: msg.messanger, + to: msg.messenger, block_number: Number(block), block_header: { timestamp: gdm.hre.ethers.utils.hexlify(Number(timestamp)) diff --git a/scenario/utils/relayMessage.ts b/scenario/utils/relayMessage.ts index 0bccd6467..fa0523665 100644 --- a/scenario/utils/relayMessage.ts +++ b/scenario/utils/relayMessage.ts @@ -16,7 +16,7 @@ export default async function relayMessage( tenderlyLogs?: any[] ) { const bridgeNetwork = bridgeDeploymentManager.network; - console.log(`Relaying messages from ${bridgeNetwork} -> ${governanceDeploymentManager.network}`); + console.log(`Relaying messages from ${governanceDeploymentManager.network} -> ${bridgeNetwork}`); let proposal; switch (bridgeNetwork) { case 'base': diff --git a/scenario/utils/scenarioHelper.ts b/scenario/utils/scenarioHelper.ts index a104a629c..e0d85f787 100644 --- a/scenario/utils/scenarioHelper.ts +++ b/scenario/utils/scenarioHelper.ts @@ -22,6 +22,7 @@ const config = { transferBase: 1000, transferAsset: 5000, transferAsset1: 5000, + transferAsset2: 50, interestSeconds: 110, withdrawBase: 1000, withdrawAsset: 3000, @@ -29,7 +30,8 @@ const config = { withdrawAsset1: 3000, withdrawCollateral: 100, transferCollateral: 100, - supplyCollateral: 100 + supplyCollateral: 100, + supplyBase: 1000, }; export function getConfigForScenario(ctx: CometContext, i?: number) { @@ -153,15 +155,16 @@ export function getConfigForScenario(ctx: CometContext, i?: number) { } if (ctx.world.base.network === 'ronin' && ctx.world.base.deployment === 'weth') { + config.supplyBase = 100; config.transferBase = 10; - config.transferAsset = 200000; - config.transferAsset1 = 200000; + config.transferAsset = 400000; + config.transferAsset1 = 400000; config.rewardsAsset = 1000000; config.rewardsBase = 200; config.withdrawBase = 10; config.withdrawBase1 = 10; - config.withdrawAsset = 100000; - config.withdrawAsset1 = 10000; + config.withdrawAsset = 400000; + config.withdrawAsset1 = 30000; config.liquidationBase = 150; config.liquidationBase1 = 50; config.liquidationAsset = 5; diff --git a/src/deploy/index.ts b/src/deploy/index.ts index 3757ac900..6dadb2831 100644 --- a/src/deploy/index.ts +++ b/src/deploy/index.ts @@ -79,12 +79,11 @@ export type TestnetProposal = [ // Ideally these wouldn't be hardcoded, but other solutions are much more complex, and slower export const COMP_WHALES = { mainnet: [ - '0x9aa835bc7b8ce13b9b0c9764a52fbf71ac62ccf1', - '0x683a4f9915d6216f73d6df50151725036bd26c02', + '0x66cD62c6F8A4BB0Cd8720488BCBd1A6221B765F9', + '0xb06df4dd01a5c5782f360ada9345c87e86adae3d', + '0x3FB19771947072629C8EEE7995a2eF23B72d4C8A', '0x8169522c2C57883E8EF80C498aAB7820dA539806', - '0x8d07D225a769b7Af3A923481E1FdF49180e6A265', - '0x7d1a02C0ebcF06E1A36231A54951E061673ab27f', - '0x54A37d93E57c5DA659F508069Cf65A381b61E189', + '0x36cc7B13029B5DEe4034745FB4F24034f3F2ffc6', ], testnet: ['0xbbfe34e868343e6f4f5e8b5308de980d7bd88c46'] From b3456dafb3088413e0945ae383e17aee42b19b21 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Wed, 24 Dec 2025 20:16:42 +0200 Subject: [PATCH 37/65] fix: working arbitrum scenarios --- scenario/constraints/ProposalConstraint.ts | 6 +++--- scenario/utils/scenarioHelper.ts | 25 +++++++++++----------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/scenario/constraints/ProposalConstraint.ts b/scenario/constraints/ProposalConstraint.ts index df76002d9..36956771c 100644 --- a/scenario/constraints/ProposalConstraint.ts +++ b/scenario/constraints/ProposalConstraint.ts @@ -78,9 +78,9 @@ export class ProposalConstraint implements StaticConstra ); } - // temporary hack to skip proposal 510 - if (proposal.id.eq(510)) { - console.log('Skipping proposal 510'); + // temporary hack to skip proposal 519 + if (proposal.id.eq(519)) { + console.log('Skipping proposal 519'); continue; } diff --git a/scenario/utils/scenarioHelper.ts b/scenario/utils/scenarioHelper.ts index e0d85f787..0e342c876 100644 --- a/scenario/utils/scenarioHelper.ts +++ b/scenario/utils/scenarioHelper.ts @@ -113,10 +113,11 @@ export function getConfigForScenario(ctx: CometContext, i?: number) { } if (ctx.world.base.network === 'arbitrum' && ctx.world.base.deployment === 'usdc') { - config.bulkerAsset = 10000; - config.bulkerAsset1 = 10000; - config.withdrawAsset = 7000; + config.bulkerAsset = 100000; + config.bulkerAsset1 = 100000; + config.withdrawAsset = 10000; config.transferAsset = 500000; + config.transferAsset1 = 500000; config.transferBase = 100; if(i == 8) { // tBTC config.supplyCollateral = 2; @@ -126,11 +127,11 @@ export function getConfigForScenario(ctx: CometContext, i?: number) { } if (ctx.world.base.network === 'arbitrum' && ctx.world.base.deployment === 'usdt') { - config.withdrawAsset = 7000; - config.bulkerAsset = 10000; + config.withdrawAsset = 10000; + config.bulkerAsset = 100000; config.bulkerAsset1 = 10000; - config.transferAsset = 10000; - config.transferAsset1 = 10000; + config.transferAsset = 100000; + config.transferAsset1 = 100000; if(i == 5) { // tBTC config.supplyCollateral = 2; config.transferCollateral = 2; @@ -139,11 +140,11 @@ export function getConfigForScenario(ctx: CometContext, i?: number) { } if (ctx.world.base.network === 'arbitrum' && ctx.world.base.deployment === 'usdc.e') { - config.withdrawAsset = 7000; - config.bulkerAsset = 10000; - config.bulkerAsset1 = 10000; - config.transferAsset = 10000; - config.transferAsset1 = 10000; + config.withdrawAsset = 10000; + config.bulkerAsset = 100000; + config.bulkerAsset1 = 100000; + config.transferAsset = 500000; + config.transferAsset1 = 500000; config.liquidationDenominator = 84; config.liquidationBase = 100000; config.liquidationBase1 = 50000; From 8b2ea24d6e67b805c2d012e28631455c05617759 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Mon, 23 Feb 2026 17:49:39 +0200 Subject: [PATCH 38/65] new fixes --- .../1761125221_upgrade_to_capo_price_feeds.ts | 7 +- .../1761228877_upgrade_to_capo_price_feeds.ts | 7 +- .../1735299664_upgrade_to_capo_price_feeds.ts | 9 +- deployments/ronin/weth/deploy.ts | 6 + deployments/ronin/weth/roots.json | 1 + deployments/ronin/wron/deploy.ts | 7 + deployments/ronin/wron/roots.json | 1 + scenario/LiquidationScenario.ts | 5 +- scenario/utils/index.ts | 435 ++++++++++-------- scenario/utils/relayRoninMessage.ts | 131 +++++- scenario/utils/scenarioHelper.ts | 25 +- src/deploy/index.ts | 2 + test/allow-by-sig-test.ts | 2 +- 13 files changed, 405 insertions(+), 233 deletions(-) diff --git a/deployments/base/aero/migrations/1761125221_upgrade_to_capo_price_feeds.ts b/deployments/base/aero/migrations/1761125221_upgrade_to_capo_price_feeds.ts index 2a6172bc0..d58fd5fb7 100644 --- a/deployments/base/aero/migrations/1761125221_upgrade_to_capo_price_feeds.ts +++ b/deployments/base/aero/migrations/1761125221_upgrade_to_capo_price_feeds.ts @@ -1,15 +1,10 @@ import { expect } from 'chai'; import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; import { migration } from '../../../../plugins/deployment_manager/Migration'; -import { calldata, proposal } from '../../../../src/deploy'; +import { calldata, proposal, exp } from '../../../../src/deploy'; import { utils } from 'ethers'; -import { Numeric } from '../../../../test/helpers'; import { AggregatorV3Interface } from '../../../../build/types'; -export function exp(i: number, d: Numeric = 0, r: Numeric = 6): bigint { - return (BigInt(Math.floor(i * 10 ** Number(r))) * 10n ** BigInt(d)) / 10n ** BigInt(r); -} - const ETH_USD_PRICE_FEED = '0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70'; const WSTETH_ADDRESS = '0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452'; diff --git a/deployments/base/weth/migrations/1761228877_upgrade_to_capo_price_feeds.ts b/deployments/base/weth/migrations/1761228877_upgrade_to_capo_price_feeds.ts index 8ac4fb51c..56cffa4f0 100644 --- a/deployments/base/weth/migrations/1761228877_upgrade_to_capo_price_feeds.ts +++ b/deployments/base/weth/migrations/1761228877_upgrade_to_capo_price_feeds.ts @@ -1,15 +1,10 @@ import { expect } from 'chai'; import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; import { migration } from '../../../../plugins/deployment_manager/Migration'; -import { calldata, proposal } from '../../../../src/deploy'; +import { calldata, proposal, exp } from '../../../../src/deploy'; import { utils } from 'ethers'; -import { Numeric } from '../../../../test/helpers'; import { AggregatorV3Interface } from '../../../../build/types'; -export function exp(i: number, d: Numeric = 0, r: Numeric = 6): bigint { - return (BigInt(Math.floor(i * 10 ** Number(r))) * 10n ** BigInt(d)) / 10n ** BigInt(r); -} - const WSTETH_ADDRESS = '0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452'; const WSTETH_STETH_PRICE_FEED_ADDRESS = '0xB88BAc61a4Ca37C43a3725912B1f472c9A5bc061'; diff --git a/deployments/mainnet/usdt/migrations/1735299664_upgrade_to_capo_price_feeds.ts b/deployments/mainnet/usdt/migrations/1735299664_upgrade_to_capo_price_feeds.ts index efe7f8750..e724eec36 100644 --- a/deployments/mainnet/usdt/migrations/1735299664_upgrade_to_capo_price_feeds.ts +++ b/deployments/mainnet/usdt/migrations/1735299664_upgrade_to_capo_price_feeds.ts @@ -1,15 +1,10 @@ import { expect } from 'chai'; import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; import { migration } from '../../../../plugins/deployment_manager/Migration'; -import { proposal } from '../../../../src/deploy'; -import { Numeric } from '../../../../test/helpers'; +import { proposal, exp } from '../../../../src/deploy'; import { IWstETH, IRateProvider, AggregatorV3Interface } from '../../../../build/types'; import { constants } from 'ethers'; -export function exp(i: number, d: Numeric = 0, r: Numeric = 6): bigint { - return (BigInt(Math.floor(i * 10 ** Number(r))) * 10n ** BigInt(d)) / 10n ** BigInt(r); -} - const WETH_ADDRESS = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'; const ETH_USD_SVR_PRICE_FEED = '0xc0053f3FBcCD593758258334Dfce24C2A9A673aD'; @@ -307,7 +302,7 @@ The ninth action deploys and upgrades Comet to a new version. }, async enacted(): Promise { - return false; + return true; }, async verify(deploymentManager: DeploymentManager) { diff --git a/deployments/ronin/weth/deploy.ts b/deployments/ronin/weth/deploy.ts index 06bebf97e..383b9b10a 100644 --- a/deployments/ronin/weth/deploy.ts +++ b/deployments/ronin/weth/deploy.ts @@ -73,6 +73,11 @@ async function deployContracts( 'ronin' ); + const l2CCIPOnRamp = await deploymentManager.existing( + 'l2CCIPOnRamp', + '0x02b60267bceeaFDC45005e0Fa0dd783eFeBc9F1b', + 'ronin' + ); // Deploy Local Timelock const localTimelock = await deploymentManager.deploy( @@ -195,6 +200,7 @@ async function deployContracts( bridgeReceiver, l2CCIPRouter, l2CCIPOffRamp, + l2CCIPOnRamp, roninl2NativeBridge, bulker, // COMP diff --git a/deployments/ronin/weth/roots.json b/deployments/ronin/weth/roots.json index 7756d849c..86fa59c10 100644 --- a/deployments/ronin/weth/roots.json +++ b/deployments/ronin/weth/roots.json @@ -6,6 +6,7 @@ "bridgeReceiver": "0x2c7EfA766338D33B9192dB1fB5D170Bdc03ef3F9", "l2CCIPRouter": "0x46527571D5D1B68eE7Eb60B18A32e6C60DcEAf99", "l2CCIPOffRamp": "0x320A10449556388503Fd71D74A16AB52e0BD1dEb", + "l2CCIPOnRamp": "0x02b60267bceeaFDC45005e0Fa0dd783eFeBc9F1b", "roninl2NativeBridge": "0x0cf8ff40a508bdbc39fbe1bb679dcba64e65c7df", "bulker": "0x840281FaD56DD88afba052B7F18Be2A65796Ecc6", "l2TokenAdminRegistry": "0x90e83d532A4aD13940139c8ACE0B93b0DdbD323a" diff --git a/deployments/ronin/wron/deploy.ts b/deployments/ronin/wron/deploy.ts index eec9022bb..1aae0a786 100644 --- a/deployments/ronin/wron/deploy.ts +++ b/deployments/ronin/wron/deploy.ts @@ -79,6 +79,12 @@ async function deployContracts( 'ronin' ); + const l2CCIPOnRamp = await deploymentManager.existing( + 'l2CCIPOnRamp', + '0x02b60267bceeaFDC45005e0Fa0dd783eFeBc9F1b', + 'ronin' + ); + // Deploy all Comet-related contracts const deployed = await deployComet(deploymentManager, deploySpec, {}, true); @@ -86,6 +92,7 @@ async function deployContracts( ...deployed, bridgeReceiver, l2CCIPRouter, + l2CCIPOnRamp, l2CCIPOffRamp, l2TokenAdminRegistry, bulker diff --git a/deployments/ronin/wron/roots.json b/deployments/ronin/wron/roots.json index 13f7b0b98..a616419a3 100644 --- a/deployments/ronin/wron/roots.json +++ b/deployments/ronin/wron/roots.json @@ -5,6 +5,7 @@ "cometFactory": "0x4DF9E0f8e94a7A8A9aEa6010CD9d341F8Ecfe4c6", "bridgeReceiver": "0x2c7EfA766338D33B9192dB1fB5D170Bdc03ef3F9", "l2CCIPRouter": "0x46527571D5D1B68eE7Eb60B18A32e6C60DcEAf99", + "l2CCIPOnRamp": "0x02b60267bceeaFDC45005e0Fa0dd783eFeBc9F1b", "l2CCIPOffRamp": "0x320A10449556388503Fd71D74A16AB52e0BD1dEb", "roninl2NativeBridge": "0x0cf8ff40a508bdbc39fbe1bb679dcba64e65c7df", "l2TokenAdminRegistry": "0x90e83d532A4aD13940139c8ACE0B93b0DdbD323a", diff --git a/scenario/LiquidationScenario.ts b/scenario/LiquidationScenario.ts index e13612569..c22c0e133 100644 --- a/scenario/LiquidationScenario.ts +++ b/scenario/LiquidationScenario.ts @@ -210,7 +210,10 @@ scenario( scenario( 'Comet#liquidation > user can end up with a minted supply', { - filter: async (ctx) => !matchesDeployment(ctx, [{ network: 'base', deployment: 'usds' }]), + filter: async (ctx) => !matchesDeployment(ctx, [ + { network: 'base', deployment: 'usds' }, + { network: 'ronin' }, + ]), tokenBalances: async (ctx) => ( { $comet: { diff --git a/scenario/utils/index.ts b/scenario/utils/index.ts index 23f94ddfa..ed9cfd7c9 100644 --- a/scenario/utils/index.ts +++ b/scenario/utils/index.ts @@ -488,172 +488,213 @@ async function redeployRenzoOracle(dm: DeploymentManager) { } } -const tokens = new Map([ - ['WETH', '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'], - ['LINK', '0x514910771AF9Ca656af840dff83E8264EcF986CA'], +const tokens = [ + ['mainnet', 'WETH', '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'], + ['mainnet', 'LINK', '0x514910771AF9Ca656af840dff83E8264EcF986CA'], + ['mainnet', 'GHO', '0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f'], + ['ronin', 'WETH', '0xc99a6a985ed2cac1ef41640596c5a5f9f4e19ef5'], + ['ronin', 'WRON', '0xe514d9deb7966c8be0ca922de8a064264ea6bcd4'], + ['ronin', 'LINK', '0x3902228d6a3d2dc44731fd9d45fee6a61c722d0b'], +]; + +const dest = new Map([ + ['ronin', '6916147374840168594'], + ['mainnet', '5009297550715157269'], ]); -const dest = new Map([['ronin', '6916147374840168594']]); - -async function updateCCIPStats(dm: DeploymentManager) { - if (dm.network === 'mainnet') { - const commitStore = '0x2aa101bf99caef7fc1355d4c493a1fe187a007ce'; +export async function updateCCIPStats( + dm: DeploymentManager, + tenderlyLogs?: any[] +) { + const config = [ + { + network: 'mainnet', + commitStore: '0x2aa101bf99caef7fc1355d4c493a1fe187a007ce', + priceRegistry: '0x8c9b2Efb7c64C394119270bfecE7f54763b958Ad' + }, + { + network: 'ronin', + commitStore: '0x28c66d9693b2634b2f3b170f6d9584eec2f72ff0', + priceRegistry: '0xefCEa3CFA330adcDdeCe99219C57fd45cd166ac1' + } + ]; + const { commitStore, priceRegistry } = config.find(c => c.network === dm.network) || {}; + if (!commitStore || !priceRegistry) { + console.log(`No CCIP config for network ${dm.network}, skipping CCIP stats update.`); + return; + } + const abi = [ + { + inputs: [ + { + components: [ + { + components: [ + { + internalType: 'address', + name: 'sourceToken', + type: 'address', + }, + { + internalType: 'uint224', + name: 'usdPerToken', + type: 'uint224', + }, + ], + internalType: 'struct TokenPriceUpdate[]', + name: 'tokenPriceUpdates', + type: 'tuple[]', + }, + { + components: [ + { + internalType: 'uint64', + name: 'destChainSelector', + type: 'uint64', + }, + { + internalType: 'uint224', + name: 'usdPerUnitGas', + type: 'uint224', + }, + ], + internalType: 'struct GasPriceUpdate[]', + name: 'gasPriceUpdates', + type: 'tuple[]', + }, + ], + internalType: 'struct PriceUpdates', + name: 'priceUpdates', + type: 'tuple', + }, + ], + name: 'updatePrices', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint64', + name: 'destChainSelector', + type: 'uint64', + }, + ], + name: 'getDestinationChainGasPrice', + outputs: [ + { + components: [ + { + internalType: 'uint224', + name: 'value', + type: 'uint224', + }, + { + internalType: 'uint32', + name: 'timestamp', + type: 'uint32', + }, + ], + internalType: 'struct TimestampedPackedUint224', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'token', + type: 'address', + }, + ], + name: 'getTokenPrice', + outputs: [ + { + components: [ + { + internalType: 'uint224', + name: 'value', + type: 'uint224', + }, + { + internalType: 'uint32', + name: 'timestamp', + type: 'uint32', + }, + ], + internalType: 'struct TimestampedPackedUint224', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + ]; - const priceRegistry = '0x8c9b2Efb7c64C394119270bfecE7f54763b958Ad'; - const abi = [ - { - inputs: [ - { - components: [ - { - components: [ - { - internalType: 'address', - name: 'sourceToken', - type: 'address', - }, - { - internalType: 'uint224', - name: 'usdPerToken', - type: 'uint224', - }, - ], - internalType: 'struct TokenPriceUpdate[]', - name: 'tokenPriceUpdates', - type: 'tuple[]', - }, - { - components: [ - { - internalType: 'uint64', - name: 'destChainSelector', - type: 'uint64', - }, - { - internalType: 'uint224', - name: 'usdPerUnitGas', - type: 'uint224', - }, - ], - internalType: 'struct GasPriceUpdate[]', - name: 'gasPriceUpdates', - type: 'tuple[]', - }, - ], - internalType: 'struct PriceUpdates', - name: 'priceUpdates', - type: 'tuple', - }, - ], - name: 'updatePrices', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'uint64', - name: 'destChainSelector', - type: 'uint64', - }, - ], - name: 'getDestinationChainGasPrice', - outputs: [ - { - components: [ - { - internalType: 'uint224', - name: 'value', - type: 'uint224', - }, - { - internalType: 'uint32', - name: 'timestamp', - type: 'uint32', - }, - ], - internalType: 'struct TimestampedPackedUint224', - name: '', - type: 'tuple', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'token', - type: 'address', - }, - ], - name: 'getTokenPrice', - outputs: [ - { - components: [ - { - internalType: 'uint224', - name: 'value', - type: 'uint224', - }, - { - internalType: 'uint32', - name: 'timestamp', - type: 'uint32', - }, - ], - internalType: 'struct TimestampedPackedUint224', - name: '', - type: 'tuple', - }, - ], - stateMutability: 'view', - type: 'function', - }, - ]; + await dm.hre.network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [commitStore], + }); - await dm.hre.network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [commitStore], - }); + await dm.hre.network.provider.request({ + method: 'hardhat_setBalance', + params: [commitStore, '0x56bc75e2d63100000'], + }); + const commitStoreSigner = await dm.hre.ethers.getSigner(commitStore); - await dm.hre.network.provider.request({ - method: 'hardhat_setBalance', - params: [commitStore, '0x56bc75e2d63100000'], - }); - const commitStoreSigner = await dm.hre.ethers.getSigner(commitStore); + const registryContract = new Contract( + priceRegistry, + abi, + dm.hre.ethers.provider + ); - const registryContract = new Contract( - priceRegistry, - abi, - dm.hre.ethers.provider - ); + const tokenPrices = []; + const gasPrices = []; + for (const [network,, address] of tokens) { + if(network !== dm.network) continue; + const price = await registryContract.getTokenPrice(address); + tokenPrices.push([address, price.value]); + } - const tokenPrices = []; - const gasPrices = []; - for (const [, address] of tokens) { - const price = await registryContract.getTokenPrice(address); - tokenPrices.push([address, price.value]); - } - for (const [, address] of dest) { - const price = await registryContract.getDestinationChainGasPrice(address); - gasPrices.push([address, price.value]); + for (const [, chainSelector] of dest) { + try { + const price = await registryContract.getDestinationChainGasPrice(chainSelector); + gasPrices.push([chainSelector, price.value]); + } catch (e) { + continue; } + } - const tx0 = await commitStoreSigner.sendTransaction({ - to: priceRegistry, - data: registryContract.interface.encodeFunctionData('updatePrices', [ + if(tenderlyLogs) { + dm.stashRelayMessage( + priceRegistry, + registryContract.interface.encodeFunctionData('updatePrices', [ { tokenPriceUpdates: tokenPrices, gasPriceUpdates: gasPrices, }, ]), - }); - - await tx0.wait(); + commitStore + ); } + + const tx0 = await commitStoreSigner.sendTransaction({ + to: priceRegistry, + data: registryContract.interface.encodeFunctionData('updatePrices', [ + { + tokenPriceUpdates: tokenPrices, + gasPriceUpdates: gasPrices, + }, + ]), + }); + + await tx0.wait(); } const REDSTONE_FEEDS = { @@ -888,7 +929,7 @@ export async function tenderlyExecute( let proposals; if (chainId1 !== chainId2) { proposals = await relayMessage(gdm, bdm, parseFloat(B0.toString()), bundle[bundle.length - 1].transaction.transaction_info.logs); - + debug(`Proposals relayed: ${proposals.length}`); const timelockL2 = await bdm.getContractOrThrow('timelock'); const delay = await timelockL2.delay(); @@ -899,21 +940,21 @@ export async function tenderlyExecute( const B0L2 = Number(latestL2.number) + 1; const simsL2 = relayMessages.map((msg, i, arr) => { const isLast = i === arr.length - 1; - + const timestamp = isLast ? Number(T0L2) : latestL2.timestamp; - + const block = isLast ? B0L2 : latestL2.number; - + return { network_id: chainId2.toString(), from: msg.signer, to: msg.messenger, block_number: Number(block), block_header: { - timestamp: gdm.hre.ethers.utils.hexlify(Number(timestamp)) + timestamp: bdm.hre.ethers.utils.hexlify(Number(timestamp)) }, input: msg.callData, save: true, @@ -921,14 +962,6 @@ export async function tenderlyExecute( gas_price: 0, }; }); - - - while (!simsL1[0]) { - simsL1.shift(); - if (simsL1.length == 0) { - break; - } - } if (simsL2.length > 0) { const bundle2 = await simulateBundle(bdm, simsL2, Number(B0L2)); @@ -948,25 +981,65 @@ async function simulateBundle( simulations: any[], blockNumber: number = 0 ): Promise { - const { username, project, accessKey } = (dm.hre.config as any).tenderly; - const body = { - simulations, - block_number: blockNumber, - simulation_type: 'full', - save: true, - }; + const rollingStateChanges = {}; + const results = []; + + for (const sim of simulations) { + const { username, project, accessKey } = (dm.hre.config as any).tenderly; + + // Merge rolling state changes with simulation's own state_objects + const stateObjects = sim.state_objects + ? { ...rollingStateChanges, ...sim.state_objects } + : rollingStateChanges; + + const body = { + simulations: [{ + ...sim, + state_objects: stateObjects, + block_number: sim.block_number || blockNumber, + simulation_type: 'full', + save: true, + save_if_fails: true, + }] + }; - const result = await axios.post( - `https://api.tenderly.co/api/v1/account/${username}/project/${project}/simulate-bundle`, - body, - { - headers: { - 'X-Access-Key': accessKey, - 'Content-Type': 'application/json', - }, + const result = await axios.post( + `https://api.tenderly.co/api/v1/account/${username}/project/${project}/simulate-bundle`, + body, + { + headers: { + 'X-Access-Key': accessKey, + 'Content-Type': 'application/json', + }, + } + ); + + // Extract and accumulate state changes from state_diff + const simResult = result.data.simulation_results[0]; + if (simResult?.transaction?.transaction_info?.call_trace?.state_diff) { + const stateDiff = simResult.transaction.transaction_info.call_trace.state_diff; + + // state_diff is an array of objects with { address, raw: [...] } + for (const stateDiffEntry of stateDiff) { + const address = stateDiffEntry.address; + + if (!rollingStateChanges[address]) { + rollingStateChanges[address] = { storage: {} }; + } + + if (stateDiffEntry.raw && Array.isArray(stateDiffEntry.raw)) { + for (const change of stateDiffEntry.raw) { + // Each change has: { address, key, original, dirty } + rollingStateChanges[address].storage[change.key] = change.dirty; + } + } + } } - ); - return result.data.simulation_results; + + results.push(simResult); + } + + return results; } async function shareSimulation(dm: DeploymentManager, simulationId: string) { diff --git a/scenario/utils/relayRoninMessage.ts b/scenario/utils/relayRoninMessage.ts index 4a72cee87..e86c760b9 100644 --- a/scenario/utils/relayRoninMessage.ts +++ b/scenario/utils/relayRoninMessage.ts @@ -4,9 +4,13 @@ import { setNextBaseFeeToZero, setNextBlockTimestamp } from './hreUtils'; import { BigNumber, ethers } from 'ethers'; import { Log } from '@ethersproject/abstract-provider'; import { OpenBridgedProposal } from '../context/Gov'; -import { isTenderlyLog } from './index'; +import { isTenderlyLog, updateCCIPStats } from './index'; const roninChainSelector = '6916147374840168594'; +const mainnetChainSelector = '5009297550715157269'; + +const MAINNET_CCIP_ROUTER = '0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D'; +const MAINNET_RONIN_OFF_RAMP = '0x9a3Ed7007809CfD666999e439076B4Ce4120528D'; export default async function relayRoninMessage( governanceDeploymentManager: DeploymentManager, @@ -20,6 +24,7 @@ export default async function relayRoninMessage( const l2CCIPOffRamp = (await bridgeDeploymentManager.getContractOrThrow('l2CCIPOffRamp')); const bridgeReceiver = (await bridgeDeploymentManager.getContractOrThrow('bridgeReceiver')); const l1TokenAdminRegistry = await governanceDeploymentManager.getContractOrThrow('l1TokenAdminRegistry'); + const timelockMainnet = await governanceDeploymentManager.getContractOrThrow('timelock'); const l2TokenAdminRegistry = await bridgeDeploymentManager.existing( 'l2TokenAdminRegistry', @@ -27,7 +32,12 @@ export default async function relayRoninMessage( 'ronin' ); + const l2CCIPOnRamp = await bridgeDeploymentManager.getContractOrThrow('l2CCIPOnRamp'); + const l1CCIPRouter = await governanceDeploymentManager.existing('l1CCIPRouter', MAINNET_CCIP_ROUTER, 'mainnet'); + const l1CCIPOffRamp = await governanceDeploymentManager.existing('roninl1CCIPOffRamp', MAINNET_RONIN_OFF_RAMP, 'mainnet'); + const offRampSigner = await impersonateAddress(bridgeDeploymentManager, l2CCIPOffRamp.address); + const l1OffRampSigner = await impersonateAddress(governanceDeploymentManager, l1CCIPOffRamp.address); const openBridgedProposals: OpenBridgedProposal[] = []; @@ -80,7 +90,7 @@ export default async function relayRoninMessage( await bridgeDeploymentManager.hre.network.provider.request({ method: 'hardhat_setBalance', - params: [l2CCIPOffRamp.address, '0x1000000000000000000000'] + params: [offRampSigner.address, '0x1000000000000000000000'] }); await setNextBaseFeeToZero(bridgeDeploymentManager); @@ -99,7 +109,7 @@ export default async function relayRoninMessage( const callData = l2Router.interface.encodeFunctionData('routeMessage', [ any2EVMMessage, 25_000, - 2_000_000, + 10_000_000, internalMsg.receiver, ]); bridgeDeploymentManager.stashRelayMessage( @@ -136,7 +146,7 @@ export default async function relayRoninMessage( const routeTx = await l2Router.connect(offRampSigner).routeMessage( any2EVMMessage, 25_000, - 2_000_000, + 10_000_000, internalMsg.receiver, ); @@ -207,23 +217,6 @@ export default async function relayRoninMessage( } } - if (tenderlyLogs) { - const proposalFilter = bridgeReceiver.filters.ProposalCreated(); - const proposalEvents = await bridgeDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: 'latest', - toBlock: 'latest', - address: bridgeReceiver.address, - topics: proposalFilter.topics - }); - - for (let event of proposalEvents) { - const { - args: { id, eta }, - } = bridgeReceiver.interface.parseLog(event); - openBridgedProposals.push({ id, eta }); - } - } - for (const proposal of openBridgedProposals) { const { id, eta } = proposal; await setNextBlockTimestamp(bridgeDeploymentManager, eta.toNumber() + 1); @@ -231,6 +224,7 @@ export default async function relayRoninMessage( if (tenderlyLogs) { const callData = bridgeReceiver.interface.encodeFunctionData('executeProposal', [id]); + await updateCCIPStats(bridgeDeploymentManager, tenderlyLogs); const signer = await bridgeDeploymentManager.getSigner(); bridgeDeploymentManager.stashRelayMessage( bridgeReceiver.address, @@ -238,9 +232,100 @@ export default async function relayRoninMessage( await signer.getAddress() ); } else { - await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); + await updateCCIPStats(bridgeDeploymentManager); + const signer = await bridgeDeploymentManager.getSigner(); + await bridgeReceiver.connect(signer).executeProposal(id, { gasPrice: 0 }); + console.log(`[CCIP L2] Executed bridged proposal ${id.toString()}`); + } + } + if (tenderlyLogs) return openBridgedProposals; + + // Process L2→L1 (Ronin→Mainnet) messages + const filterCCIPL2ToL1 = l2CCIPOnRamp.filters.CCIPSendRequested(); + let logsCCIPL2ToL1: Log[] = []; + + const latestBlock = (await bridgeDeploymentManager.hre.ethers.provider.getBlock('latest')).number; + logsCCIPL2ToL1 = await bridgeDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: latestBlock - 500, + toBlock: 'latest', + address: l2CCIPOnRamp.address, + topics: filterCCIPL2ToL1.topics || [] + }); + + const targetReceivers = [ + timelockMainnet.address.toLowerCase() + ]; + + for (const log of logsCCIPL2ToL1) { + const parsedLog = l2CCIPOnRamp.interface.parseLog(log); + + const internalMsg = parsedLog.args.message; + if (!targetReceivers.includes(internalMsg.receiver.toLowerCase())) continue; + console.log(`[CCIP L2->L1] Found CCIPSendRequested with messageId=${internalMsg.messageId}, receiver=${internalMsg.receiver}`); + + await governanceDeploymentManager.hre.network.provider.request({ + method: 'hardhat_setBalance', + params: [l1CCIPOffRamp.address, '0x1000000000000000000000'] + }); + + await setNextBaseFeeToZero(governanceDeploymentManager); + + const any2EVMMessage = { + messageId: internalMsg.messageId, + sourceChainSelector: internalMsg.sourceChainSelector, + sender: ethers.utils.defaultAbiCoder.encode(['address'], [internalMsg.sender]), + data: internalMsg.data, + destTokenAmounts: internalMsg.tokenAmounts.map((t: any) => ({ + token: t.token as string, + amount: BigNumber.from(t.amount) + })), + }; + + const routeTx = await l1CCIPRouter.connect(l1OffRampSigner).routeMessage( + any2EVMMessage, + 25_000, + 2_000_000, + internalMsg.receiver, + ); + + await routeTx.wait(); + + if (internalMsg.tokenAmounts.length) { + for (const tokenTransferData of internalMsg.tokenAmounts) { + const l2TokenPoolAddress = await l2TokenAdminRegistry.getPool(tokenTransferData.token); + const l2TokenPool = new ethers.Contract( + l2TokenPoolAddress, + ['function getRemoteToken(uint64) external view returns (bytes)'], + bridgeDeploymentManager.hre.ethers.provider + ); + const l1Token64 = await l2TokenPool.getRemoteToken(mainnetChainSelector); + const l1TokenAddress = ethers.utils.defaultAbiCoder.decode(['address'], l1Token64)[0]; + const l1TokenPool = await l1TokenAdminRegistry.getPool(l1TokenAddress); + const l1Token = new ethers.Contract( + l1TokenAddress, + [ + 'function balanceOf(address) external view returns (uint256)', + 'function transfer(address, uint256) external returns (bool)' + ], + governanceDeploymentManager.hre.ethers.provider + ); + + const poolSigner = await impersonateAddress(governanceDeploymentManager, l1TokenPool); + await governanceDeploymentManager.hre.network.provider.request({ + method: 'hardhat_setBalance', + params: [l1TokenPool, '0x1000000000000000000000'] + }); + + const poolBalance = await l1Token.balanceOf(l1TokenPool); + console.log(`[CCIP L2->L1] Token pool ${l1TokenPool} balance: ${poolBalance.toString()}, transferring ${tokenTransferData.amount.toString()} to ${internalMsg.receiver}`); + + const transferTx = await l1Token.connect(poolSigner).transfer(internalMsg.receiver, tokenTransferData.amount); + await transferTx.wait(); + console.log(`[CCIP L2->L1] Transferred ${tokenTransferData.amount.toString()} of ${l1TokenAddress} to ${internalMsg.receiver}`); + } } - console.log(`[CCIP L2] Executed bridged proposal ${id.toString()}`); + + console.log(`[CCIP L2->L1] Routed message to ${internalMsg.receiver}`); } return openBridgedProposals; diff --git a/scenario/utils/scenarioHelper.ts b/scenario/utils/scenarioHelper.ts index 0e342c876..181a6e168 100644 --- a/scenario/utils/scenarioHelper.ts +++ b/scenario/utils/scenarioHelper.ts @@ -72,6 +72,14 @@ export function getConfigForScenario(ctx: CometContext, i?: number) { config.liquidationAsset = 100; } + if (ctx.world.base.network === 'mainnet' && ctx.world.base.deployment === 'usdt') { + if(i == 12) { + config.supplyCollateral = 0; + config.transferCollateral = 0; + config.withdrawCollateral = 0; + } + } + if (ctx.world.base.network === 'base' && ctx.world.base.deployment === 'aero') { config.interestSeconds = 110; } @@ -127,7 +135,8 @@ export function getConfigForScenario(ctx: CometContext, i?: number) { } if (ctx.world.base.network === 'arbitrum' && ctx.world.base.deployment === 'usdt') { - config.withdrawAsset = 10000; + config.rewardsAsset = 20000; + config.withdrawAsset = 20000; config.bulkerAsset = 100000; config.bulkerAsset1 = 10000; config.transferAsset = 100000; @@ -158,17 +167,17 @@ export function getConfigForScenario(ctx: CometContext, i?: number) { if (ctx.world.base.network === 'ronin' && ctx.world.base.deployment === 'weth') { config.supplyBase = 100; config.transferBase = 10; - config.transferAsset = 400000; - config.transferAsset1 = 400000; + config.transferAsset = 4000000; + config.transferAsset1 = 800000; config.rewardsAsset = 1000000; config.rewardsBase = 200; config.withdrawBase = 10; - config.withdrawBase1 = 10; - config.withdrawAsset = 400000; - config.withdrawAsset1 = 30000; - config.liquidationBase = 150; + config.withdrawBase1 = 50; + config.withdrawAsset = 4000000; + config.withdrawAsset1 = 4000000; + config.liquidationBase = 200; config.liquidationBase1 = 50; - config.liquidationAsset = 5; + config.liquidationAsset = 6; config.bulkerAsset = 100000; config.bulkerAsset1 = 100000; config.bulkerComet = 100; diff --git a/src/deploy/index.ts b/src/deploy/index.ts index 6dadb2831..4e96469ca 100644 --- a/src/deploy/index.ts +++ b/src/deploy/index.ts @@ -112,6 +112,7 @@ export const WHALES = { '0x34C0bD5877A5Ee7099D0f5688D65F4bB9158BDE2', // sFRAX whale '0x9152e9C04e8fE8373EDaa8f5841E25d4015658B7', // pumpBTC whale '0x65906988ADEe75306021C417a1A3458040239602', // LBTC whale + '0x7667095Caa12b79fCa489ff6E2198Ca01fDAe057', ], polygon: [ '0xF977814e90dA44bFA03b6295A0616a897441aceC', // USDT whale @@ -148,6 +149,7 @@ export const WHALES = { '0x54b5569deC8A6A8AE61A36Fd34e5c8945810db8b', // tBTC whale '0xDBD974Eb5360d053ea0c56B4DaCF4A9D3E894Ee2', // tETH whale '0xbA1333333333a1BA1108E8412f11850A5C319bA9', // tETH whale + '0xEA1132120ddcDDA2F119e99Fa7A27a0d036F7Ac9', // ezETH whale ], base: [ '0x6D3c5a4a7aC4B1428368310E4EC3bB1350d01455', // USDbC whale diff --git a/test/allow-by-sig-test.ts b/test/allow-by-sig-test.ts index 82195d7e6..2d422d449 100644 --- a/test/allow-by-sig-test.ts +++ b/test/allow-by-sig-test.ts @@ -29,7 +29,7 @@ const types = { describe('allowBySig', function () { beforeEach(async () => { - comet = (await makeProtocol()).comet; + comet = (await makeProtocol()).cometWithExtendedAssetList; [_admin, pauseGuardian, signer, manager] = await ethers.getSigners(); domain = { From 73cb01d249d4bc0d7cbd124bd9a116a7c55bfbde Mon Sep 17 00:00:00 2001 From: Mykhailo Shabodyash Date: Mon, 23 Feb 2026 18:53:21 +0200 Subject: [PATCH 39/65] fix --- plugins/deployment_manager/Import.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/deployment_manager/Import.ts b/plugins/deployment_manager/Import.ts index 2431acc89..1c3fe593e 100644 --- a/plugins/deployment_manager/Import.ts +++ b/plugins/deployment_manager/Import.ts @@ -44,7 +44,7 @@ export async function importContract( console.warn(`Import failed for ${network}@${address} (${e.message}), retrying in ${retryDelay / 1000}s; ${retries} retries left`); await new Promise(ok => setTimeout(ok, retryDelay)); - return importContract(network, address, retries - 1, retryDelay * 2); + return importContract(network, address, retries - 1, retryDelay * 2 > 10000 ? 10000 : retryDelay * 2); } } @@ -61,7 +61,7 @@ export async function importContract( console.warn(`Import failed for ${network}@${address} (${e.message}), retrying in ${retryDelay / 1000}s; ${retries} retries left`); await new Promise(ok => setTimeout(ok, retryDelay)); - return importContract(network, address, retries - 1, retryDelay * 2); + return importContract(network, address, retries - 1, retryDelay * 2 > 10000 ? 10000 : retryDelay * 2); } } From 7d4a913631c02e394a02d6931a60f80a741dbfaf Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Mon, 23 Feb 2026 19:43:23 +0200 Subject: [PATCH 40/65] fix: precision fix --- test/helpers.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/helpers.ts b/test/helpers.ts index c343729b7..53fcda4a4 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -156,7 +156,12 @@ export function dfn(x: T | undefined | null, dflt: T): T { } export function exp(i: number, d: Numeric = 0, r: Numeric = 6): bigint { - return (BigInt(Math.floor(i * 10 ** Number(r))) * 10n ** BigInt(d)) / 10n ** BigInt(r); + const sign = i < 0 ? -1n : 1n; + const parts = Math.abs(i).toString().split('.'); + const intPart = parts[0]; + const fracPart = (parts[1] || '').padEnd(Number(r), '0').slice(0, Number(r)); + const scaled = BigInt(intPart + fracPart); + return sign * (scaled * 10n ** BigInt(d)) / 10n ** BigInt(r); } export function factor(f: number): bigint { From f3ebdba92fa5fb3b3cb11ed3ebac266dae1a426b Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Thu, 9 Apr 2026 18:45:35 +0300 Subject: [PATCH 41/65] fix: change scroll rpc --- .github/workflows/deploy-market.yaml | 2 +- .github/workflows/enact-migration.yaml | 2 +- .github/workflows/prepare-migration.yaml | 2 +- hardhat.config.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy-market.yaml b/.github/workflows/deploy-market.yaml index a41584ded..c2066d7ec 100644 --- a/.github/workflows/deploy-market.yaml +++ b/.github/workflows/deploy-market.yaml @@ -61,7 +61,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"${RONIN_QUICKNODE_LINK}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"${MANTLE_QUICKNODE_LINK}\",\"optimism\":\"${OPTIMISM_QUICKNODE_LINK}\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"sepolia\":\"${SEPOLIA_QUICKNODE_LINK}\",\"polygon\":\"${POLYGON_QUICKNODE_LINK}\",\"arbitrum\":\"${ARBITRUM_QUICKNODE_LINK}\",\"base\":\"${BASE_QUICKNODE_LINK}\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"${RONIN_QUICKNODE_LINK}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"${MANTLE_QUICKNODE_LINK}\",\"optimism\":\"${OPTIMISM_QUICKNODE_LINK}\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"sepolia\":\"${SEPOLIA_QUICKNODE_LINK}\",\"polygon\":\"${POLYGON_QUICKNODE_LINK}\",\"arbitrum\":\"${ARBITRUM_QUICKNODE_LINK}\",\"base\":\"${BASE_QUICKNODE_LINK}\",\"scroll\":\"https://scroll.drpc.org\"}')[github.event.inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' diff --git a/.github/workflows/enact-migration.yaml b/.github/workflows/enact-migration.yaml index faa035cbf..73b48a0cb 100644 --- a/.github/workflows/enact-migration.yaml +++ b/.github/workflows/enact-migration.yaml @@ -105,7 +105,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"${RONIN_QUICKNODE_LINK}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"${MANTLE_QUICKNODE_LINK}\",\"optimism\":\"${OPTIMISM_QUICKNODE_LINK}\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"sepolia\":\"${SEPOLIA_QUICKNODE_LINK}\",\"polygon\":\"${POLYGON_QUICKNODE_LINK}\",\"arbitrum\":\"${ARBITRUM_QUICKNODE_LINK}\",\"base\":\"${BASE_QUICKNODE_LINK}\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"${RONIN_QUICKNODE_LINK}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"${MANTLE_QUICKNODE_LINK}\",\"optimism\":\"${OPTIMISM_QUICKNODE_LINK}\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"sepolia\":\"${SEPOLIA_QUICKNODE_LINK}\",\"polygon\":\"${POLYGON_QUICKNODE_LINK}\",\"arbitrum\":\"${ARBITRUM_QUICKNODE_LINK}\",\"base\":\"${BASE_QUICKNODE_LINK}\",\"scroll\":\"https://scroll.drpc.org\"}')[github.event.inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' diff --git a/.github/workflows/prepare-migration.yaml b/.github/workflows/prepare-migration.yaml index 042e66729..27392ffcc 100644 --- a/.github/workflows/prepare-migration.yaml +++ b/.github/workflows/prepare-migration.yaml @@ -75,7 +75,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"${RONIN_QUICKNODE_LINK}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"${MANTLE_QUICKNODE_LINK}\",\"optimism\":\"${OPTIMISM_QUICKNODE_LINK}\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"sepolia\":\"${SEPOLIA_QUICKNODE_LINK}\",\"polygon\":\"${POLYGON_QUICKNODE_LINK}\",\"arbitrum\":\"${ARBITRUM_QUICKNODE_LINK}\",\"base\":\"${BASE_QUICKNODE_LINK}\",\"scroll\":\"https://rpc.scroll.io\"}')[github.event.inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"${RONIN_QUICKNODE_LINK}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"${MANTLE_QUICKNODE_LINK}\",\"optimism\":\"${OPTIMISM_QUICKNODE_LINK}\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"sepolia\":\"${SEPOLIA_QUICKNODE_LINK}\",\"polygon\":\"${POLYGON_QUICKNODE_LINK}\",\"arbitrum\":\"${ARBITRUM_QUICKNODE_LINK}\",\"base\":\"${BASE_QUICKNODE_LINK}\",\"scroll\":\"https://scroll.drpc.org\"}')[github.event.inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' diff --git a/hardhat.config.ts b/hardhat.config.ts index 480c078b3..3b7861abd 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -198,7 +198,7 @@ export const networkConfigs: NetworkConfig[] = [ { network: 'scroll', chainId: 534352, - url: 'https://rpc.scroll.io', + url: 'https://scroll.drpc.org', }, ]; From ccc4855cc6b0ca7dea375a23e6d319646d516cfb Mon Sep 17 00:00:00 2001 From: Mykhailo Shabodyash Date: Fri, 24 Apr 2026 16:46:11 +0300 Subject: [PATCH 42/65] fix: update relations and cctp addresses --- deployments/arbitrum/usdc/relations.ts | 7 +++++++ deployments/arbitrum/usdc/roots.json | 3 ++- deployments/mainnet/usdc/relations.ts | 7 +++++++ deployments/mainnet/usdc/roots.json | 6 +++--- deployments/relations.ts | 12 ++++++++++++ src/deploy/index.ts | 3 ++- 6 files changed, 33 insertions(+), 5 deletions(-) diff --git a/deployments/arbitrum/usdc/relations.ts b/deployments/arbitrum/usdc/relations.ts index 9a8535766..0e4bb52be 100644 --- a/deployments/arbitrum/usdc/relations.ts +++ b/deployments/arbitrum/usdc/relations.ts @@ -11,6 +11,13 @@ export default { TransparentUpgradeableProxy: { artifact: 'contracts/ERC20.sol:ERC20' }, + AdminUpgradableProxy: { + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, // Native USDC '0xaf88d065e77c8cC2239327C5EDb3A432268e5831': { artifact: 'contracts/ERC20.sol:ERC20', diff --git a/deployments/arbitrum/usdc/roots.json b/deployments/arbitrum/usdc/roots.json index 54603b0c6..1ae6e7f63 100644 --- a/deployments/arbitrum/usdc/roots.json +++ b/deployments/arbitrum/usdc/roots.json @@ -4,5 +4,6 @@ "rewards": "0x88730d254A2f7e6AC8388c3198aFd694bA9f7fae", "bridgeReceiver": "0x42480C37B249e33aABaf4c22B20235656bd38068", "bulker": "0xbdE8F31D2DdDA895264e27DD990faB3DC87b372d", - "CCTPMessageTransmitter": "0xC30362313FBBA5cf9163F0bb16a0e01f01A896ca" + "CCTPTokenMessenger": "0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d", + "CCTPMessageTransmitter": "0x81D40F21F12A8F0E3252Bccb954D722d4c464B64" } \ No newline at end of file diff --git a/deployments/mainnet/usdc/relations.ts b/deployments/mainnet/usdc/relations.ts index 776d101e6..ef9403471 100644 --- a/deployments/mainnet/usdc/relations.ts +++ b/deployments/mainnet/usdc/relations.ts @@ -21,6 +21,13 @@ export default { } } }, + AdminUpgradableProxy: { + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, UUPSProxy: { artifact: 'contracts/ERC20.sol:ERC20', delegates: { diff --git a/deployments/mainnet/usdc/roots.json b/deployments/mainnet/usdc/roots.json index f01a53815..8cdf987c1 100644 --- a/deployments/mainnet/usdc/roots.json +++ b/deployments/mainnet/usdc/roots.json @@ -1,5 +1,4 @@ { - "l1TokenAdminRegistry": "0xb22764f98dD05c789929716D677382Df22C05Cb6", "comptrollerV2": "0x3d9819210a31b4961b30ef54be2aed79b9c9cd3b", "comet": "0xc3d688B66703497DAA19211EEdff47f25384cdc3", "configurator": "0x316f9708bB98af7dA9c68C1C3b5e79039cD336E3", @@ -8,8 +7,8 @@ "fxRoot": "0xfe5e5D361b2ad62c541bAb87C45a0B9B018389a2", "arbitrumInbox": "0x4Dbd4fc535Ac27206064B68FfCf827b0A60BAB3f", "arbitrumL1GatewayRouter": "0x72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef", - "CCTPTokenMessenger": "0xbd3fa81b58ba92a82136038b25adec7066af3155", - "CCTPMessageTransmitter": "0x0a992d191deec32afe36203ad87d7d289a738f81", + "CCTPTokenMessenger": "0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d", + "CCTPMessageTransmitter": "0x81D40F21F12A8F0E3252Bccb954D722d4c464B64", "baseL1CrossDomainMessenger": "0x866E82a600A1414e583f7F13623F1aC5d58b0Afa", "baseL1StandardBridge": "0x3154Cf16ccdb4C6d922629664174b904d80F2C35", "baseL1USDSBridge": "0xA5874756416Fa632257eEA380CAbd2E87cED352A", @@ -25,6 +24,7 @@ "lineaMessageService": "0xd19d4B5d358258f05D7B411E21A1460D11B0876F", "lineaL1TokenBridge": "0x051F1D88f0aF5763fB888eC4378b4D8B29ea3319", "lineaL1USDCBridge": "0x504A330327A089d8364C4ab3811Ee26976d388ce", + "l1TokenAdminRegistry": "0xb22764f98dD05c789929716D677382Df22C05Cb6", "roninl1CCIPOnRamp": "0xdC5b578ff3AFcC4A4a6E149892b9472390b50844", "roninl1NativeBridge": "0x64192819Ac13Ef72bF6b5AE239AC672B43a9AF08" } \ No newline at end of file diff --git a/deployments/relations.ts b/deployments/relations.ts index c7b823b32..b48345c0b 100644 --- a/deployments/relations.ts +++ b/deployments/relations.ts @@ -59,6 +59,12 @@ const relationConfigMap: RelationConfigMap = { if (address === '0xd09acb80c1e8f2291862c4978a008791c9167003') { return 'tETH'; } + if (address === '0x5a7facb970d094b6c7ff1df0ea68d99e6e73cbff') { + return 'weETH'; + } + if (address.toLowerCase() === '0x87eee96d50fb761ad85b1c982d28a042169d61b1') { + return 'wrsETH'; + } throw new Error(`Failed to get symbol for token ${token.address}: ${e.message}`); } @@ -85,6 +91,12 @@ const relationConfigMap: RelationConfigMap = { if (address === '0xd09acb80c1e8f2291862c4978a008791c9167003') { return 'tETH:priceFeed'; } + if (address === '0x5a7facb970d094b6c7ff1df0ea68d99e6e73cbff') { + return 'weETH:priceFeed'; + } + if (address === '0x87eee96d50fb761ad85b1c982d28a042169d61b1') { + return 'wrsETH:priceFeed'; + } throw new Error(`Failed to get symbol for token ${assets[i].address}: ${e.message}`); } diff --git a/src/deploy/index.ts b/src/deploy/index.ts index 4e96469ca..c6ed9019b 100644 --- a/src/deploy/index.ts +++ b/src/deploy/index.ts @@ -160,6 +160,7 @@ export const WHALES = { '0xcf3D55c10DB69f28fD1A75Bd73f3D8A2d9c595ad', // cbETH whale '0xb125E6687d4313864e53df431d5425969c15Eb2F', // cbETH whale '0x1539A4611f16a139891c14365Cab86599F3A8AFC', // tBTC whale + '0x0a1d576f3eFeF75b330424287a95A366e8281D54', // USDbC whale ], scroll: [ '0xaaaaAAAACB71BF2C8CaE522EA5fa455571A74106', // USDC whale @@ -281,7 +282,7 @@ export async function proposal( const { target, value, signature, calldata: cd } = action as TargetAction; targets.push(target); values.push(value ?? 0); - calldatas.push(utils.id(signature).slice(0, 10) + cd.slice(2)); + calldatas.push(signature ? utils.id(signature).slice(0, 10) + cd.slice(2) : cd); signatures.push(''); } } From e5144db3e7a7106113495bf999da50a001d46494 Mon Sep 17 00:00:00 2001 From: Mykhailo Shabodyash Date: Fri, 24 Apr 2026 20:22:23 +0300 Subject: [PATCH 43/65] fix --- scripts/exportNetworkConfigs.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/exportNetworkConfigs.js b/scripts/exportNetworkConfigs.js index e16da6da0..60d76183c 100644 --- a/scripts/exportNetworkConfigs.js +++ b/scripts/exportNetworkConfigs.js @@ -29,6 +29,9 @@ try { } function getUrl(network) { + if(network === 'scroll') { + return 'https://rpc.scroll.io'; + } const config = configs.find(cfg => cfg.network === network); return config ? config.url : ''; } From c98017580b26d09bdd22144e25e3effebcda8803 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Fri, 1 May 2026 18:41:36 +0300 Subject: [PATCH 44/65] fix: handle max gaslimit per tx --- scenario/utils/index.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scenario/utils/index.ts b/scenario/utils/index.ts index ed9cfd7c9..70355b942 100644 --- a/scenario/utils/index.ts +++ b/scenario/utils/index.ts @@ -1162,7 +1162,12 @@ export async function executeOpenProposal( console.log(`Updating CCIP prices...`); await updateCCIPStats(dm); - await governor.execute(id, { gasPrice: 0, gasLimit: 120000000 }); + const tx = await governor.execute(id, { gasPrice: 0, gasLimit: 120000000 }); + const receipt = await tx.wait(); + + if(receipt.gasUsed.toNumber() >= 16_777_215) { + throw new Error('Execution may have failed due to hitting gas limit'); + } } await redeployRenzoOracle(dm); From 750ede2069c7767eb62a1fd681dab4a61be22c5d Mon Sep 17 00:00:00 2001 From: Mykhailo Shabodyash Date: Fri, 1 May 2026 22:02:56 +0300 Subject: [PATCH 45/65] fix: slither --- .github/workflows/run-slither.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/run-slither.yaml b/.github/workflows/run-slither.yaml index 18355f755..b595e761c 100644 --- a/.github/workflows/run-slither.yaml +++ b/.github/workflows/run-slither.yaml @@ -18,9 +18,6 @@ jobs: with: python-version: '3.x' - - name: Install solc - run: sudo add-apt-repository ppa:ethereum/ethereum;sudo add-apt-repository ppa:ethereum/ethereum-dev;sudo apt-get update;sudo apt-get install solc - - name: Install packages run: pip install slither-analyzer solc-select From e02ba0dc298f5dbc499f0e040b8156c42d6a4b4d Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Wed, 13 May 2026 16:30:57 +0300 Subject: [PATCH 46/65] fix: change capo branch --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 9a5a6b038..3e0416b8c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,4 +4,4 @@ [submodule "contracts/capo"] path = contracts/capo url = git@github.com:woof-software/compound-capo.git - branch = lst-lrt-oracles + branch = main From e18d7a8f42e43c0ca0b5145436017d972bb86979 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Tue, 19 May 2026 23:16:48 +0300 Subject: [PATCH 47/65] fix: supply and withdraw scenario fixes --- scenario/AddMaticxCollateralScenario.ts | 2 +- scenario/SupplyScenario.ts | 2 +- scenario/WithdrawScenario.ts | 8 ++--- scenario/utils/scenarioHelper.ts | 43 +++++++++++++++++++++---- src/deploy/index.ts | 3 ++ 5 files changed, 45 insertions(+), 13 deletions(-) diff --git a/scenario/AddMaticxCollateralScenario.ts b/scenario/AddMaticxCollateralScenario.ts index 1619bd8e1..c1199fb89 100644 --- a/scenario/AddMaticxCollateralScenario.ts +++ b/scenario/AddMaticxCollateralScenario.ts @@ -95,7 +95,7 @@ scenario( // Try to supply new token and borrow base const baseAssetAddress = await comet.baseToken(); - const borrowAmount = 1000n * (await comet.baseScale()).toBigInt(); + const borrowAmount = 100n * (await comet.baseScale()).toBigInt(); const supplyAmount = exp(9000, 18); await maticx diff --git a/scenario/SupplyScenario.ts b/scenario/SupplyScenario.ts index 10a02a33f..c481702a0 100644 --- a/scenario/SupplyScenario.ts +++ b/scenario/SupplyScenario.ts @@ -46,7 +46,7 @@ async function testSupplyFromCollateral(context: CometContext, assetNum: number) const { asset: assetAddress, scale: scaleBN, supplyCap } = await comet.getAssetInfo(assetNum); const collateralAsset = context.getAssetByAddress(assetAddress); const scale = scaleBN.toBigInt(); - const toSupply = BigInt(getConfigForScenario(context).supplyCollateral) * scale; + const toSupply = BigInt(getConfigForScenario(context, assetNum).supplyCollateral) * scale; expect(await collateralAsset.balanceOf(albert.address)).to.be.equal(toSupply); expect(await comet.collateralBalanceOf(betty.address, collateralAsset.address)).to.be.equal(0n); diff --git a/scenario/WithdrawScenario.ts b/scenario/WithdrawScenario.ts index d04b2d02e..15a6c4cf5 100644 --- a/scenario/WithdrawScenario.ts +++ b/scenario/WithdrawScenario.ts @@ -48,10 +48,10 @@ for (let i = 0; i < MAX_ASSETS; i++) { scenario( `Comet#withdraw > collateral asset ${i}`, { - filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, getConfigForScenario(ctx).withdrawCollateral), + filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, getConfigForScenario(ctx, i).withdrawCollateral), cometBalances: async (ctx) => ( { - albert: { [`$asset${i}`]: getConfigForScenario(ctx).withdrawCollateral } + albert: { [`$asset${i}`]: getConfigForScenario(ctx, i).withdrawCollateral } } ), }, @@ -65,10 +65,10 @@ for (let i = 0; i < MAX_ASSETS; i++) { scenario( `Comet#withdrawFrom > collateral asset ${i}`, { - filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, getConfigForScenario(ctx).withdrawCollateral), + filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, getConfigForScenario(ctx, i).withdrawCollateral), cometBalances: async (ctx) => ( { - albert: { [`$asset${i}`]: getConfigForScenario(ctx).withdrawCollateral } + albert: { [`$asset${i}`]: getConfigForScenario(ctx, i).withdrawCollateral } } ), }, diff --git a/scenario/utils/scenarioHelper.ts b/scenario/utils/scenarioHelper.ts index 181a6e168..cdd3878b9 100644 --- a/scenario/utils/scenarioHelper.ts +++ b/scenario/utils/scenarioHelper.ts @@ -1,6 +1,6 @@ import { CometContext } from '../context/CometContext'; -const config = { +const defaultConfig = { bulkerBase: 1000000, bulkerBase1: 10, bulkerAsset: 5000, @@ -35,6 +35,7 @@ const config = { }; export function getConfigForScenario(ctx: CometContext, i?: number) { + const config = { ...defaultConfig }; if (ctx.world.base.network === 'mainnet' && ctx.world.base.deployment === 'wbtc') { config.bulkerBase = 200; config.bulkerAsset = 400; @@ -103,10 +104,17 @@ export function getConfigForScenario(ctx: CometContext, i?: number) { } if (ctx.world.base.network === 'optimism' && ctx.world.base.deployment === 'usdc') { - config.bulkerAsset = 10000; - config.bulkerAsset1 = 10000; - config.transferAsset1 = 10000; - config.withdrawAsset = 7000; + config.bulkerAsset = 100000; + config.bulkerAsset1 = 100000; + config.transferAsset = 100000; + config.transferAsset1 = 100000; + config.rewardsAsset = 100000; + config.withdrawAsset = 100000; + if(i == 4) { // wUSDM + config.supplyCollateral = 2; + config.transferCollateral = 2; + config.withdrawCollateral = 2; + } } if (ctx.world.base.network === 'optimism' && ctx.world.base.deployment === 'usdt') { @@ -127,6 +135,13 @@ export function getConfigForScenario(ctx: CometContext, i?: number) { config.transferAsset = 500000; config.transferAsset1 = 500000; config.transferBase = 100; + config.rewardsBase = 100; + config.withdrawBase = 100; + if(i == 7) { // tETH + config.supplyCollateral = 2; + config.transferCollateral = 2; + config.withdrawCollateral = 2; + } if(i == 8) { // tBTC config.supplyCollateral = 2; config.transferCollateral = 2; @@ -206,6 +221,14 @@ export function getConfigForScenario(ctx: CometContext, i?: number) { config.bulkerAsset1 = 10; } + if(ctx.world.base.network === 'mantle' && ctx.world.base.deployment === 'usde') { + if(i == 2) { // FBTC + config.supplyCollateral = 2; + config.transferCollateral = 2; + config.withdrawCollateral = 2; + } + } + if (ctx.world.base.network === 'linea' && ctx.world.base.deployment === 'usdc') { config.bulkerAsset = 500; config.bulkerAsset1 = 500; @@ -216,6 +239,7 @@ export function getConfigForScenario(ctx: CometContext, i?: number) { if (ctx.world.base.network === 'linea' && ctx.world.base.deployment === 'weth') { config.liquidationBase = 1000; + config.transferAsset1 = 2000; config.rewardsAsset = 1000; config.rewardsBase = 50; config.supplyCollateral = 10; @@ -227,13 +251,18 @@ export function getConfigForScenario(ctx: CometContext, i?: number) { config.liquidationBase = 250; config.liquidationBase1 = 350; config.liquidationAsset = 100; - config.bulkerAsset = 500; - config.bulkerComet = 500; + config.bulkerAsset = 100; + config.bulkerComet = 100; config.bulkerBorrowBase = 100; config.bulkerBorrowAsset = 50; config.supplyCollateral = 10; config.transferCollateral = 10; config.withdrawCollateral = 10; + if(i == 5) { // rsETH + config.supplyCollateral = 2; + config.transferCollateral = 2; + config.withdrawCollateral = 2; + } config.rewardsBase = 100; config.rewardsAsset = 250; config.transferBase = 100; diff --git a/src/deploy/index.ts b/src/deploy/index.ts index c6ed9019b..d105db072 100644 --- a/src/deploy/index.ts +++ b/src/deploy/index.ts @@ -169,6 +169,7 @@ export const WHALES = { optimism: [ '0x2A82Ae142b2e62Cb7D10b55E323ACB1Cab663a26', // OP whale '0x966A8bcE7dc11f4Ec5a8885a7d31F0f170e3E00d', // USDM whale + '0x5F82C97e9b1755237692a946aE814998Bc0e2124', // USDM whale '0x8af3827a41c26c7f32c81e93bb66e837e0210d5c', // USDC whale '0xc45A479877e1e9Dfe9FcD4056c699575a1045dAA', // wstETH whale '0x6e57181D6b4b7c138a6F956AD16DAF4f27FC5E04', // COMP whale @@ -176,6 +177,7 @@ export const WHALES = { ], mantle: [ '0x588846213A30fd36244e0ae0eBB2374516dA836C', // USDe whale + '0xd374a62AA68D01cdB420e17b9840706e86BC840B', // mETH whale '0x88a1493366D48225fc3cEFbdae9eBb23E323Ade3', // mETH whale '0xEe6281d94Fed46A90379F2033B6BbdcDa4EF462E', // mETH whale '0x651C9D1F9da787688225f49d63ad1623ba89A8D5', // FBTC whale @@ -192,6 +194,7 @@ export const WHALES = { '0x7Ae0911198AD568E1FE4af3cf81e36A29983778f', // wstETH whale '0x4B2cf5C94A88934870B523983B22e6d2dd1b6577', // wstETH whale '0x8f5ae9CddB9f68de460C77730b018Ae7E04a140A', // wstETH whale + '0xbaD024786995Fa29bc6311c9454d377D3B73F576', // wstETH whale ], linea: [ '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f', // ETH whale From a9747c9c15d81b479ae964f0a980116c090e19dd Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Thu, 21 May 2026 13:44:13 +0300 Subject: [PATCH 48/65] feat: recent proposals --- .../1772198347_upgrade_to_svr_price_feeds.ts | 245 ++++++++ .../1770307912_add_usde_collateral.ts | 135 +++++ ...777297641_update_supply_caps_on_mainnet.ts | 234 ++++++++ ...777297641_update_supply_caps_on_mainnet.ts | 234 ++++++++ .../1770317078_add_usde_collateral.ts | 134 +++++ ...777297641_update_supply_caps_on_mainnet.ts | 234 ++++++++ ...777625885_update_supply_caps_on_mainnet.ts | 279 +++++++++ .../1773227248_update_reth_pricefeed.ts | 135 +++++ ...777625885_update_supply_caps_on_mainnet.ts | 279 +++++++++ ...urn_rseth_pricefeeds_on_weth_and_wsteth.ts | 130 +++++ ...777625885_update_supply_caps_on_mainnet.ts | 279 +++++++++ ...urn_rseth_pricefeeds_on_weth_and_wsteth.ts | 130 +++++ ...pdate_comet_to_support_more_collaterals.ts | 23 +- ...pdate_comet_to_support_more_collaterals.ts | 48 +- .../1772805892_deprecate_stmatic.ts | 134 +++++ ...pdate_comet_to_support_more_collaterals.ts | 10 +- .../1772817323_deprecate_stmatic.ts | 118 ++++ .../migrations/1767882783_depreciate_comet.ts | 519 +++++++++++++++++ .../migrations/1767889363_depreciate_comet.ts | 534 ++++++++++++++++++ .../1772710499_update_usdc_price_feed.ts | 189 +++++++ scenario/LiquidationScenario.ts | 2 +- scenario/utils/index.ts | 6 + scenario/utils/scenarioHelper.ts | 17 +- src/deploy/index.ts | 5 +- 24 files changed, 4026 insertions(+), 27 deletions(-) create mode 100644 deployments/arbitrum/weth/migrations/1772198347_upgrade_to_svr_price_feeds.ts create mode 100644 deployments/mainnet/usdc/migrations/1770307912_add_usde_collateral.ts create mode 100644 deployments/mainnet/usdc/migrations/1777297641_update_supply_caps_on_mainnet.ts create mode 100644 deployments/mainnet/usds/migrations/1777297641_update_supply_caps_on_mainnet.ts create mode 100644 deployments/mainnet/usdt/migrations/1770317078_add_usde_collateral.ts create mode 100644 deployments/mainnet/usdt/migrations/1777297641_update_supply_caps_on_mainnet.ts create mode 100644 deployments/mainnet/wbtc/migrations/1777625885_update_supply_caps_on_mainnet.ts create mode 100644 deployments/mainnet/weth/migrations/1773227248_update_reth_pricefeed.ts create mode 100644 deployments/mainnet/weth/migrations/1777625885_update_supply_caps_on_mainnet.ts create mode 100644 deployments/mainnet/weth/migrations/1779099097_return_rseth_pricefeeds_on_weth_and_wsteth.ts create mode 100644 deployments/mainnet/wsteth/migrations/1777625885_update_supply_caps_on_mainnet.ts create mode 100644 deployments/mainnet/wsteth/migrations/1779099097_return_rseth_pricefeeds_on_weth_and_wsteth.ts create mode 100644 deployments/polygon/usdc/migrations/1772805892_deprecate_stmatic.ts create mode 100644 deployments/polygon/usdt/migrations/1772817323_deprecate_stmatic.ts create mode 100644 deployments/ronin/weth/migrations/1767882783_depreciate_comet.ts create mode 100644 deployments/ronin/wron/migrations/1767889363_depreciate_comet.ts create mode 100644 deployments/ronin/wron/migrations/1772710499_update_usdc_price_feed.ts diff --git a/deployments/arbitrum/weth/migrations/1772198347_upgrade_to_svr_price_feeds.ts b/deployments/arbitrum/weth/migrations/1772198347_upgrade_to_svr_price_feeds.ts new file mode 100644 index 000000000..9bbd2b43e --- /dev/null +++ b/deployments/arbitrum/weth/migrations/1772198347_upgrade_to_svr_price_feeds.ts @@ -0,0 +1,245 @@ +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { calldata, proposal, exp } from '../../../../src/deploy'; +import { Contract, utils } from 'ethers'; +import { AggregatorV3Interface } from '../../../../build/types'; +import { applyL1ToL2Alias, estimateL2Transaction } from '../../../../scenario/utils/arbitrumUtils'; + +const ETH_USD_SVR_PRICE_FEED = '0xe4dF63Bf89fD868A899F2422B030709FD79Be921'; +const BTC_USD_SVR_PRICE_FEED = '0x06047dD6f43552831BB51319917DC0C99c29A44c'; +const RSETH_ETH_PRICE_FEED = '0x3A917e6B5732dFCc4A45257e3930979fAE6a3737'; + +const FEED_DECIMALS = 8; +const blockToFetch = 420000000; + +let newRsETHPriceFeed: string; +let newWbtcPriceFeed: string; + +let oldRsETHPriceFeed: string; +let oldWbtcPriceFeed: string; + +export default migration('1772198347_upgrade_to_svr_price_feeds', { + async prepare(deploymentManager: DeploymentManager) { + + //1. WBTC + const _wbtcScalingPriceFeed = await deploymentManager.deploy( + 'WBTC:priceFeed', + 'pricefeeds/ReverseMultiplicativePriceFeed.sol', + [ + BTC_USD_SVR_PRICE_FEED, // WBTC / USD price feed + ETH_USD_SVR_PRICE_FEED, // ETH / USD price feed + FEED_DECIMALS, // decimals + 'WBTC / ETH SVR Price Feed', // description + ], + true + ); + + const { timelock } = await deploymentManager.getContracts(); + const blockToFetchTimestamp = (await deploymentManager.hre.ethers.provider.getBlock(blockToFetch))!.timestamp; + + const constantPriceFeed = await deploymentManager.fromDep('WETH:priceFeed', 'arbitrum', 'weth'); + const rateProviderRsEth = await deploymentManager.existing('rsETH:_rateProvider', RSETH_ETH_PRICE_FEED, 'arbitrum', 'contracts/capo/contracts/interfaces/AggregatorV3Interface.sol:AggregatorV3Interface') as AggregatorV3Interface; + const [, currentRatioRsEth] = await rateProviderRsEth.latestRoundData({blockTag: blockToFetch}); + const rsEthCapoPriceFeed = await deploymentManager.deploy( + 'rsETH:priceFeed', + 'capo/contracts/ChainlinkCorrelatedAssetsPriceOracle.sol', + [ + timelock.address, + constantPriceFeed.address, + RSETH_ETH_PRICE_FEED, + 'rsETH / ETH CAPO Price Feed', + FEED_DECIMALS, + 3600, + { + snapshotRatio: currentRatioRsEth, + snapshotTimestamp: blockToFetchTimestamp, + maxYearlyRatioGrowthPercent: exp(0.0554, 4) + } + ], + true + ); + + return { + wbtcPriceFeedAddress: _wbtcScalingPriceFeed.address, + rsEthCapoPriceFeedAddress: rsEthCapoPriceFeed.address + }; + }, + + async enact(deploymentManager: DeploymentManager, govDeploymentManager: DeploymentManager, { + wbtcPriceFeedAddress, + rsEthCapoPriceFeedAddress + }) { + newRsETHPriceFeed = rsEthCapoPriceFeedAddress; + newWbtcPriceFeed = wbtcPriceFeedAddress; + + const trace = deploymentManager.tracer(); + const { + bridgeReceiver, + timelock: l2Timelock, + comet, + cometAdmin, + rsETH, + WBTC, + configurator + } = await deploymentManager.getContracts(); + + const { + arbitrumInbox, + timelock, + governor + } = await govDeploymentManager.getContracts(); + + const updateRsEthPriceFeedCalldata = await calldata( + configurator.populateTransaction.updateAssetPriceFeed( + comet.address, + rsETH.address, + rsEthCapoPriceFeedAddress + ) + ); + + const updateWbtcPriceFeedCalldata = await calldata( + configurator.populateTransaction.updateAssetPriceFeed( + comet.address, + WBTC.address, + wbtcPriceFeedAddress + ) + ); + + const deployAndUpgradeToCalldata = await calldata( + cometAdmin.populateTransaction.deployAndUpgradeTo( + configurator.address, + comet.address + ) + ); + + const l2ProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [configurator.address, configurator.address, cometAdmin.address], + [0, 0, 0], + ['updateAssetPriceFeed(address,address,address)', 'updateAssetPriceFeed(address,address,address)', 'deployAndUpgradeTo(address,address)'], + [updateRsEthPriceFeedCalldata, updateWbtcPriceFeedCalldata, deployAndUpgradeToCalldata], + ] + ); + + [,, oldRsETHPriceFeed] = await comet.getAssetInfoByAddress(rsETH.address); + [,, oldWbtcPriceFeed] = await comet.getAssetInfoByAddress(WBTC.address); + + const createRetryableTicketGasParams = await estimateL2Transaction( + { + from: applyL1ToL2Alias(timelock.address), + to: bridgeReceiver.address, + data: l2ProposalData + }, + deploymentManager + ); + const refundAddress = l2Timelock.address; + const mainnetActions = [ + // 1. Set Comet configuration and deployAndUpgradeTo WETH Comet on Arbitrum. + { + contract: arbitrumInbox, + signature: 'createRetryableTicket(address,uint256,uint256,address,address,uint256,uint256,bytes)', + args: [ + bridgeReceiver.address, // address to, + 0, // uint256 l2CallValue, + createRetryableTicketGasParams.maxSubmissionCost, // uint256 maxSubmissionCost, + refundAddress, // address excessFeeRefundAddress, + refundAddress, // address callValueRefundAddress, + createRetryableTicketGasParams.gasLimit, // uint256 gasLimit, + createRetryableTicketGasParams.maxFeePerGas, // uint256 maxFeePerGas, + l2ProposalData, // bytes calldata data + ], + value: createRetryableTicketGasParams.deposit + }, + ]; + + const description = `# Update rsETH and WBTC price feeds in cWETHv3 on Arbitrum with SVR and CAPO price feeds. + +## Proposal summary + +This proposal updates existing price feeds for rsETH and WBTC assets on the WETH market on Arbitrum. + +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1092), [forum discussion for CAPO](https://www.comp.xyz/t/woof-correlated-assets-price-oracle-capo/6245) and [forum discussion for SVR](https://www.comp.xyz/t/request-for-proposal-rfp-oracle-extractable-value-oev-solution-for-compound-protocol/6786). + +### rsETH price feed change + +Previously the rsETH price feed had a wrsETH / rsETH oracle, this proposal will change it to rsETH / ETH CAPO price feed. + +### CAPO summary + +CAPO is a price oracle adapter designed to support assets that grow gradually relative to a base asset - such as liquid staking tokens that accumulate yield over time. It provides a mechanism to track this expected growth while protecting downstream protocol from sudden or manipulated price spikes. rsETH price feed is updated to its CAPO implementation. + +### CAPO audit + +CAPO has been audited by [OpenZeppelin](https://www.comp.xyz/t/capo-price-feed-audit/6631), as well as the LST / LRT implementation [here](https://www.comp.xyz/t/capo-lst-lrt-audit/7118). + +### SVR fee recipient + +SVR generates revenue from liquidators and Compound DAO will receive that revenue as part of the protocol fee. The fee recipient for SVR is set to Compound DAO multisig: 0xb3E79c7CaC540CA833015E63d96D3032Ba0C4129. + +## Proposal actions + +The first action updates rsETH price feed to the CAPO implementation and WBTC price feed to the SVR implementation. This sends the encoded 'updateAssetPriceFeed' and 'deployAndUpgradeTo' calls across the bridge to the governance receiver on Arbitrum. +`; + + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 300_000 + ); + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return false; + }, + + async verify(deploymentManager: DeploymentManager) { + const { comet, configurator, rsETH, WBTC } = await deploymentManager.getContracts(); + + const rsETHIndexInComet = await configurator.getAssetIndex(comet.address, rsETH.address); + const WBTCIndexInComet = await configurator.getAssetIndex(comet.address, WBTC.address); + + // rsETH + const rsETHInCometInfo = await comet.getAssetInfoByAddress(rsETH.address); + const rsETHInConfiguratorInfoWETHComet = (await configurator.getConfiguration(comet.address)).assetConfigs[rsETHIndexInComet]; + + expect(rsETHInCometInfo.priceFeed).to.eq(newRsETHPriceFeed); + expect(rsETHInConfiguratorInfoWETHComet.priceFeed).to.eq(newRsETHPriceFeed); + expect(await comet.getPrice(newRsETHPriceFeed)).to.be.closeTo(await comet.getPrice(oldRsETHPriceFeed), 1e5); + + const rsETHPriceFeed = new Contract( + rsETHInCometInfo.priceFeed, + [ + 'function ratioProvider() view returns (address)', + 'function maxYearlyRatioGrowthPercent() view returns (uint32)', + ], + await deploymentManager.getSigner() + ); + expect(await rsETHPriceFeed.ratioProvider()).to.eq(RSETH_ETH_PRICE_FEED); + expect(await rsETHPriceFeed.maxYearlyRatioGrowthPercent()).to.eq(554); + + // WBTC + const WBTCInCometInfo = await comet.getAssetInfoByAddress(WBTC.address); + const WBTCInConfiguratorInfoWETHComet = (await configurator.getConfiguration(comet.address)).assetConfigs[WBTCIndexInComet]; + + expect(WBTCInCometInfo.priceFeed).to.eq(newWbtcPriceFeed); + expect(WBTCInConfiguratorInfoWETHComet.priceFeed).to.eq(newWbtcPriceFeed); + expect(await comet.getPrice(newWbtcPriceFeed)).to.be.closeTo(await comet.getPrice(oldWbtcPriceFeed), 2e7); + + const wbtcPriceFeed = new Contract(WBTCInCometInfo.priceFeed, + [ + 'function priceFeedA() view returns (address)', + 'function priceFeedB() view returns (address)', + ], + await deploymentManager.getSigner() + ); + expect(await wbtcPriceFeed.priceFeedA()).to.eq(BTC_USD_SVR_PRICE_FEED); + expect(await wbtcPriceFeed.priceFeedB()).to.eq(ETH_USD_SVR_PRICE_FEED); + }, +}); diff --git a/deployments/mainnet/usdc/migrations/1770307912_add_usde_collateral.ts b/deployments/mainnet/usdc/migrations/1770307912_add_usde_collateral.ts new file mode 100644 index 000000000..ee8bc9744 --- /dev/null +++ b/deployments/mainnet/usdc/migrations/1770307912_add_usde_collateral.ts @@ -0,0 +1,135 @@ +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { exp, proposal } from '../../../../src/deploy'; + +const USDe_ADDRESS = '0x4c9EDD5852cd905f086C759E8383e09bff1E68B3'; +const USDe_TO_USD_PRICE_FEED = '0xa569d910839Ae8865Da8F8e70FfFb0cBA869F961'; + +export default migration('1770307912_add_usde_collateral', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const USDe = await deploymentManager.existing( + 'USDe', + USDe_ADDRESS, + 'mainnet', + 'contracts/ERC20.sol:ERC20' + ); + const USDePriceFeed = await deploymentManager.existing( + 'USDe:priceFeed', + USDe_TO_USD_PRICE_FEED, + 'mainnet' + ); + + const { + governor, + comet, + cometAdmin, + configurator, + } = await deploymentManager.getContracts(); + + const USDeAssetConfig = { + asset: USDe.address, + priceFeed: USDePriceFeed.address, + decimals: await USDe.decimals(), + borrowCollateralFactor: exp(0.89, 18), + liquidateCollateralFactor: exp(0.94, 18), + liquidationFactor: exp(0.96, 18), + supplyCap: exp(30_000_000, 18), + }; + + const mainnetActions = [ + // 1. Add USDe as asset + { + contract: configurator, + signature: 'addAsset(address,(address,address,uint8,uint64,uint64,uint64,uint128))', + args: [comet.address, USDeAssetConfig], + }, + // 2. Deploy and upgrade to a new version of Comet + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, comet.address], + }, + ]; + + const description = `# Add USDe as collateral into cUSDCv3 on Mainnet + +## Proposal summary + +WOOF! proposes to add USDe into cUSDCv3 on Ethereum network. This proposal takes the governance steps recommended and necessary to update a Compound III USDC market on Ethereum. Simulations have confirmed the market’s readiness, as much as possible, using the [Comet scenario suite](https://github.com/compound-finance/comet/tree/main/scenario). The new parameters include setting the risk parameters based on the [recommendations from Gauntlet](https://www.comp.xyz/t/gauntlet-parameter-recommendations-for-usde-on-mainnet-usdc-usdt-comets/7580/1). + +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1089) and [forum discussion](https://www.comp.xyz/t/gauntlet-parameter-recommendations-for-usde-on-mainnet-usdc-usdt-comets/7580). + + +## Proposal Actions + +The first action adds USDe asset as collateral with corresponding configurations. + +The second action deploys and upgrades Comet to a new version.`; + + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 300_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(deploymentManager: DeploymentManager): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + const { comet, configurator } = await deploymentManager.getContracts(); + + const USDeAssetIndex = Number(await comet.numAssets()) - 1; + + const USDe = await deploymentManager.existing( + 'USDe', + USDe_ADDRESS, + 'mainnet', + 'contracts/ERC20.sol:ERC20' + ); + const USDeAssetConfig = { + asset: USDe.address, + priceFeed: USDe_TO_USD_PRICE_FEED, + decimals: 18n, + borrowCollateralFactor: exp(0.89, 18), + liquidateCollateralFactor: exp(0.94, 18), + liquidationFactor: exp(0.96, 18), + supplyCap: exp(30_000_000, 18), + }; + + // 1. Compare USDe asset config with Comet and Configurator asset info + const cometUSDeAssetInfo = await comet.getAssetInfoByAddress(USDe_ADDRESS); + expect(USDeAssetIndex).to.be.equal(cometUSDeAssetInfo.offset); + expect(USDeAssetConfig.asset).to.be.equal(cometUSDeAssetInfo.asset); + expect(USDeAssetConfig.priceFeed).to.be.equal(cometUSDeAssetInfo.priceFeed); + expect(exp(1, USDeAssetConfig.decimals)).to.be.equal(cometUSDeAssetInfo.scale); + expect(USDeAssetConfig.borrowCollateralFactor).to.be.equal(cometUSDeAssetInfo.borrowCollateralFactor); + expect(USDeAssetConfig.liquidateCollateralFactor).to.be.equal(cometUSDeAssetInfo.liquidateCollateralFactor); + expect(USDeAssetConfig.liquidationFactor).to.be.equal(cometUSDeAssetInfo.liquidationFactor); + expect(USDeAssetConfig.supplyCap).to.be.equal(cometUSDeAssetInfo.supplyCap); + + const configuratorUSDeAssetConfig = (await configurator.getConfiguration(comet.address)).assetConfigs[USDeAssetIndex]; + expect(USDeAssetConfig.asset).to.be.equal(configuratorUSDeAssetConfig.asset); + expect(USDeAssetConfig.priceFeed).to.be.equal(configuratorUSDeAssetConfig.priceFeed); + expect(USDeAssetConfig.decimals).to.be.equal(configuratorUSDeAssetConfig.decimals); + expect(USDeAssetConfig.borrowCollateralFactor).to.be.equal(configuratorUSDeAssetConfig.borrowCollateralFactor); + expect(USDeAssetConfig.liquidateCollateralFactor).to.be.equal(configuratorUSDeAssetConfig.liquidateCollateralFactor); + expect(USDeAssetConfig.liquidationFactor).to.be.equal(configuratorUSDeAssetConfig.liquidationFactor); + expect(USDeAssetConfig.supplyCap).to.be.equal(configuratorUSDeAssetConfig.supplyCap); + }, +}); \ No newline at end of file diff --git a/deployments/mainnet/usdc/migrations/1777297641_update_supply_caps_on_mainnet.ts b/deployments/mainnet/usdc/migrations/1777297641_update_supply_caps_on_mainnet.ts new file mode 100644 index 000000000..69bee0570 --- /dev/null +++ b/deployments/mainnet/usdc/migrations/1777297641_update_supply_caps_on_mainnet.ts @@ -0,0 +1,234 @@ +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { exp, proposal } from '../../../../src/deploy'; +import { BigNumber, Contract } from 'ethers'; + +const USDC_COMET = '0xc3d688B66703497DAA19211EEdff47f25384cdc3'; +const USDT_COMET = '0x3Afdc9BCA9213A35503b077a6072F3D0d5AB0840'; +const USDS_COMET = '0x5D409e56D886231aDAf00c8775665AD0f9897b56'; + +const weETH = '0xcd5fe23c85820f7b72d0926fc9b05b43e359b7ee'; +const tBTC = '0x18084fbA666a33d37592fA2633fD49a74DD93a88'; +const mETH = '0xd5f7838f5c461feff7fe49ea5ebaf7728bb0adfa'; +const sFRAX = '0xa663b02cf0a4b149d2ad41910cb81e23e1c41c32'; +const UNI = '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984'; +const LINK = '0x514910771af9ca656af840dff83e8264ecf986ca'; + +export default migration('1777297641_update_supply_caps_on_mainnet', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const { + governor, + cometAdmin, + configurator, + } = await deploymentManager.getContracts(); + + const mainnetActions = [ + // 1. Update weETH supply cap on USDT Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDT_COMET, weETH, 0], + }, + // 2. Update mETH supply cap on USDT Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDT_COMET, mETH, 0], + }, + // 3. Update tBTC supply cap on USDT Comet to 73 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDT_COMET, tBTC, exp(73, 18)], + }, + // 4. Update sFRAX supply cap on USDT Comet to 33M + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDT_COMET, sFRAX, exp(33_000_000, 18)], + }, + // 5. Update UNI supply cap on USDT Comet to 310,336 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDT_COMET, UNI, exp(310_336, 18)], + }, + // 6. Update LINK supply cap on USDT Comet to 210,317 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDT_COMET, LINK, exp(210_317, 18)], + }, + // 7. Deploy and upgrade the USDT Comet implementation to apply the updates + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, USDT_COMET], + }, + // 8. Update weETH supply cap on USDS Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDS_COMET, weETH, 0], + }, + // 9. Update tBTC supply cap on USDS Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDS_COMET, tBTC, 0], + }, + // 10. Deploy and upgrade the USDS Comet implementation to apply the updates + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, USDS_COMET], + }, + // 11. Update tBTC supply cap on USDC Comet to 40 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDC_COMET, tBTC, exp(40, 18)], + }, + // 12. Update UNI supply cap on USDC Comet to 364,691 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDC_COMET, UNI, exp(364_691, 18)], + }, + // 13. Update LINK supply cap on USDC Comet to 585,990 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDC_COMET, LINK, exp(585_990, 18)], + }, + // 14. Deploy and upgrade the USDC Comet implementation to apply the updates + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, USDC_COMET], + }, + ]; + + const description = `# Ethereum Supply cap Reduction Across USD Based Comets + +## Proposal summary + +This proposal updates supply caps for a number of assets across the USD based Mainnet markets. The supply caps for the affected assets are being updated based on their current utilization and risk parameters. + +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1115) and [forum discussion](https://www.comp.xyz/t/ethereum-supply-cap-reduction-across-comets/7793). + +## Proposal actions + + +1 - 7. Updates supply caps for weETH and mETH to 0 and tBTC to 73, sFRAX to 33M, UNI to 310,336, and LINK to 210,317 on cUSDTv3 market and upgrades the Comet implementation to apply the changes. + +8 - 10. Updates supply caps for weETH and tBTC to 0 on cUSDSv3 market and upgrades the Comet implementation to apply the changes. + +11 - 14. Updates supply caps for tBTC to 40, UNI to 364,691, and LINK to 585,990 on cUSDCv3 market and upgrades the Comet implementation to apply the changes. +`; + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 600_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(deploymentManager: DeploymentManager): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + const { configurator } = await deploymentManager.getContracts(); + + // 1 - 7 Compare updated assets on USDT Comet + const cometUSDT = new Contract( + USDT_COMET, + [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))' + ], + await deploymentManager.getSigner() + ); + + const assetInfoForWeETHOnUSDTInComet = await cometUSDT.getAssetInfoByAddress(weETH); + expect(assetInfoForWeETHOnUSDTInComet.supplyCap).to.equal(0); + + const assetInfoForMETHOnUSDTInComet = await cometUSDT.getAssetInfoByAddress(mETH); + expect(assetInfoForMETHOnUSDTInComet.supplyCap).to.equal(0); + + const assetInfoForTBTCOnUSDTInComet = await cometUSDT.getAssetInfoByAddress(tBTC); + expect(assetInfoForTBTCOnUSDTInComet.supplyCap).to.equal(BigNumber.from(73).mul(assetInfoForTBTCOnUSDTInComet.scale)); + + const assetInfoForSFRAXOnUSDTInComet = await cometUSDT.getAssetInfoByAddress(sFRAX); + expect(assetInfoForSFRAXOnUSDTInComet.supplyCap).to.equal(BigNumber.from(33_000_000).mul(assetInfoForSFRAXOnUSDTInComet.scale)); + + const assetInfoForUNIOnUSDTInComet = await cometUSDT.getAssetInfoByAddress(UNI); + expect(assetInfoForUNIOnUSDTInComet.supplyCap).to.equal(BigNumber.from(310_336).mul(assetInfoForUNIOnUSDTInComet.scale)); + + const assetInfoForLINKOnUSDTInComet = await cometUSDT.getAssetInfoByAddress(LINK); + expect(assetInfoForLINKOnUSDTInComet.supplyCap).to.equal(BigNumber.from(210_317).mul(assetInfoForLINKOnUSDTInComet.scale)); + + const USDTConfiguration = await configurator.getConfiguration(USDT_COMET); + expect(USDTConfiguration.assetConfigs[assetInfoForWeETHOnUSDTInComet.offset].supplyCap).to.equal(0); + expect(USDTConfiguration.assetConfigs[assetInfoForMETHOnUSDTInComet.offset].supplyCap).to.equal(0); + expect(USDTConfiguration.assetConfigs[assetInfoForTBTCOnUSDTInComet.offset].supplyCap).to.equal(BigNumber.from(73).mul(assetInfoForTBTCOnUSDTInComet.scale)); + expect(USDTConfiguration.assetConfigs[assetInfoForSFRAXOnUSDTInComet.offset].supplyCap).to.equal(BigNumber.from(33_000_000).mul(assetInfoForSFRAXOnUSDTInComet.scale)); + expect(USDTConfiguration.assetConfigs[assetInfoForUNIOnUSDTInComet.offset].supplyCap).to.equal(BigNumber.from(310_336).mul(assetInfoForUNIOnUSDTInComet.scale)); + expect(USDTConfiguration.assetConfigs[assetInfoForLINKOnUSDTInComet.offset].supplyCap).to.equal(BigNumber.from(210_317).mul(assetInfoForLINKOnUSDTInComet.scale)); + + // 8 - 10 Compare updated assets on USDS Comet + const cometUSDS = new Contract( + USDS_COMET, + [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))' + ], + await deploymentManager.getSigner() + ); + + const assetInfoForWeETHOnUSDSInComet = await cometUSDS.getAssetInfoByAddress(weETH); + expect(assetInfoForWeETHOnUSDSInComet.supplyCap).to.equal(0); + + const assetInfoForTBTCOnUSDSInComet = await cometUSDS.getAssetInfoByAddress(tBTC); + expect(assetInfoForTBTCOnUSDSInComet.supplyCap).to.equal(0); + + const USDSConfiguration = await configurator.getConfiguration(USDS_COMET); + expect(USDSConfiguration.assetConfigs[assetInfoForWeETHOnUSDSInComet.offset].supplyCap).to.equal(0); + expect(USDSConfiguration.assetConfigs[assetInfoForTBTCOnUSDSInComet.offset].supplyCap).to.equal(0); + + // 11 - 14 Compare updated assets on USDC Comet + const cometUSDC = new Contract( + USDC_COMET, + [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))' + ], + await deploymentManager.getSigner() + ); + + const assetInfoForTBTCOnUSDCInComet = await cometUSDC.getAssetInfoByAddress(tBTC); + expect(assetInfoForTBTCOnUSDCInComet.supplyCap).to.equal(BigNumber.from(40).mul(assetInfoForTBTCOnUSDCInComet.scale)); + + const assetInfoForUNIOnUSDCInComet = await cometUSDC.getAssetInfoByAddress(UNI); + expect(assetInfoForUNIOnUSDCInComet.supplyCap).to.equal(BigNumber.from(364_691).mul(assetInfoForUNIOnUSDCInComet.scale)); + + const assetInfoForLINKOnUSDCInComet = await cometUSDC.getAssetInfoByAddress(LINK); + expect(assetInfoForLINKOnUSDCInComet.supplyCap).to.equal(BigNumber.from(585_990).mul(assetInfoForLINKOnUSDCInComet.scale)); + + const USDCConfiguration = await configurator.getConfiguration(cometUSDC.address); + expect(USDCConfiguration.assetConfigs[assetInfoForTBTCOnUSDCInComet.offset].supplyCap).to.equal(BigNumber.from(40).mul(assetInfoForTBTCOnUSDCInComet.scale)); + expect(USDCConfiguration.assetConfigs[assetInfoForUNIOnUSDCInComet.offset].supplyCap).to.equal(BigNumber.from(364_691).mul(assetInfoForUNIOnUSDCInComet.scale)); + expect(USDCConfiguration.assetConfigs[assetInfoForLINKOnUSDCInComet.offset].supplyCap).to.equal(BigNumber.from(585_990).mul(assetInfoForLINKOnUSDCInComet.scale)); + }, +}); diff --git a/deployments/mainnet/usds/migrations/1777297641_update_supply_caps_on_mainnet.ts b/deployments/mainnet/usds/migrations/1777297641_update_supply_caps_on_mainnet.ts new file mode 100644 index 000000000..f4afeca91 --- /dev/null +++ b/deployments/mainnet/usds/migrations/1777297641_update_supply_caps_on_mainnet.ts @@ -0,0 +1,234 @@ +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { exp, proposal } from '../../../../src/deploy'; +import { BigNumber, Contract } from 'ethers'; + +const USDC_COMET = '0xc3d688B66703497DAA19211EEdff47f25384cdc3'; +const USDT_COMET = '0x3Afdc9BCA9213A35503b077a6072F3D0d5AB0840'; +const USDS_COMET = '0x5D409e56D886231aDAf00c8775665AD0f9897b56'; + +const weETH = '0xcd5fe23c85820f7b72d0926fc9b05b43e359b7ee'; +const tBTC = '0x18084fbA666a33d37592fA2633fD49a74DD93a88'; +const mETH = '0xd5f7838f5c461feff7fe49ea5ebaf7728bb0adfa'; +const sFRAX = '0xa663b02cf0a4b149d2ad41910cb81e23e1c41c32'; +const UNI = '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984'; +const LINK = '0x514910771af9ca656af840dff83e8264ecf986ca'; + +export default migration('1777297641_update_supply_caps_on_mainnet', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const { + governor, + cometAdmin, + configurator, + } = await deploymentManager.getContracts(); + + const mainnetActions = [ + // 1. Update weETH supply cap on USDT Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDT_COMET, weETH, 0], + }, + // 2. Update mETH supply cap on USDT Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDT_COMET, mETH, 0], + }, + // 3. Update tBTC supply cap on USDT Comet to 73 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDT_COMET, tBTC, exp(73, 18)], + }, + // 4. Update sFRAX supply cap on USDT Comet to 33M + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDT_COMET, sFRAX, exp(33_000_000, 18)], + }, + // 5. Update UNI supply cap on USDT Comet to 310,336 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDT_COMET, UNI, exp(310_336, 18)], + }, + // 6. Update LINK supply cap on USDT Comet to 210,317 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDT_COMET, LINK, exp(210_317, 18)], + }, + // 7. Deploy and upgrade the USDT Comet implementation to apply the updates + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, USDT_COMET], + }, + // 8. Update weETH supply cap on USDS Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDS_COMET, weETH, 0], + }, + // 9. Update tBTC supply cap on USDS Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDS_COMET, tBTC, 0], + }, + // 10. Deploy and upgrade the USDS Comet implementation to apply the updates + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, USDS_COMET], + }, + // 11. Update tBTC supply cap on USDC Comet to 40 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDC_COMET, tBTC, exp(40, 18)], + }, + // 12. Update UNI supply cap on USDC Comet to 364,691 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDC_COMET, UNI, exp(364_691, 18)], + }, + // 13. Update LINK supply cap on USDC Comet to 585,990 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDC_COMET, LINK, exp(585_990, 18)], + }, + // 14. Deploy and upgrade the USDC Comet implementation to apply the updates + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, USDC_COMET], + }, + ]; + + const description = `# Ethereum Supply cap Reduction Across USD Based Comets + +## Proposal summary + +This proposal updates supply caps for a number of assets across the USD based Mainnet markets. The supply caps for the affected assets are being updated based on their current utilization and risk parameters. + +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1115) and [forum discussion](https://www.comp.xyz/t/ethereum-supply-cap-reduction-across-comets/7793). + +## Proposal actions + + +1 - 7. Updates supply caps for weETH and mETH to 0 and tBTC to 73, sFRAX to 33M, UNI to 310,336, and LINK to 210,317 on cUSDTv3 market and upgrades the Comet implementation to apply the changes. + +8 - 10. Updates supply caps for weETH and tBTC to 0 on cUSDSv3 market and upgrades the Comet implementation to apply the changes. + +11 - 14. Updates supply caps for tBTC to 40, UNI to 364,691, and LINK to 585,990 on cUSDCv3 market and upgrades the Comet implementation to apply the changes. +`; + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 600_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return false; + }, + + async verify(deploymentManager: DeploymentManager) { + const { configurator } = await deploymentManager.getContracts(); + + // 1 - 7 Compare updated assets on USDT Comet + const cometUSDT = new Contract( + USDT_COMET, + [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))' + ], + await deploymentManager.getSigner() + ); + + const assetInfoForWeETHOnUSDTInComet = await cometUSDT.getAssetInfoByAddress(weETH); + expect(assetInfoForWeETHOnUSDTInComet.supplyCap).to.equal(0); + + const assetInfoForMETHOnUSDTInComet = await cometUSDT.getAssetInfoByAddress(mETH); + expect(assetInfoForMETHOnUSDTInComet.supplyCap).to.equal(0); + + const assetInfoForTBTCOnUSDTInComet = await cometUSDT.getAssetInfoByAddress(tBTC); + expect(assetInfoForTBTCOnUSDTInComet.supplyCap).to.equal(BigNumber.from(73).mul(assetInfoForTBTCOnUSDTInComet.scale)); + + const assetInfoForSFRAXOnUSDTInComet = await cometUSDT.getAssetInfoByAddress(sFRAX); + expect(assetInfoForSFRAXOnUSDTInComet.supplyCap).to.equal(BigNumber.from(33_000_000).mul(assetInfoForSFRAXOnUSDTInComet.scale)); + + const assetInfoForUNIOnUSDTInComet = await cometUSDT.getAssetInfoByAddress(UNI); + expect(assetInfoForUNIOnUSDTInComet.supplyCap).to.equal(BigNumber.from(310_336).mul(assetInfoForUNIOnUSDTInComet.scale)); + + const assetInfoForLINKOnUSDTInComet = await cometUSDT.getAssetInfoByAddress(LINK); + expect(assetInfoForLINKOnUSDTInComet.supplyCap).to.equal(BigNumber.from(210_317).mul(assetInfoForLINKOnUSDTInComet.scale)); + + const USDTConfiguration = await configurator.getConfiguration(USDT_COMET); + expect(USDTConfiguration.assetConfigs[assetInfoForWeETHOnUSDTInComet.offset].supplyCap).to.equal(0); + expect(USDTConfiguration.assetConfigs[assetInfoForMETHOnUSDTInComet.offset].supplyCap).to.equal(0); + expect(USDTConfiguration.assetConfigs[assetInfoForTBTCOnUSDTInComet.offset].supplyCap).to.equal(BigNumber.from(73).mul(assetInfoForTBTCOnUSDTInComet.scale)); + expect(USDTConfiguration.assetConfigs[assetInfoForSFRAXOnUSDTInComet.offset].supplyCap).to.equal(BigNumber.from(33_000_000).mul(assetInfoForSFRAXOnUSDTInComet.scale)); + expect(USDTConfiguration.assetConfigs[assetInfoForUNIOnUSDTInComet.offset].supplyCap).to.equal(BigNumber.from(310_336).mul(assetInfoForUNIOnUSDTInComet.scale)); + expect(USDTConfiguration.assetConfigs[assetInfoForLINKOnUSDTInComet.offset].supplyCap).to.equal(BigNumber.from(210_317).mul(assetInfoForLINKOnUSDTInComet.scale)); + + // 8 - 10 Compare updated assets on USDS Comet + const cometUSDS = new Contract( + USDS_COMET, + [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))' + ], + await deploymentManager.getSigner() + ); + + const assetInfoForWeETHOnUSDSInComet = await cometUSDS.getAssetInfoByAddress(weETH); + expect(assetInfoForWeETHOnUSDSInComet.supplyCap).to.equal(0); + + const assetInfoForTBTCOnUSDSInComet = await cometUSDS.getAssetInfoByAddress(tBTC); + expect(assetInfoForTBTCOnUSDSInComet.supplyCap).to.equal(0); + + const USDSConfiguration = await configurator.getConfiguration(USDS_COMET); + expect(USDSConfiguration.assetConfigs[assetInfoForWeETHOnUSDSInComet.offset].supplyCap).to.equal(0); + expect(USDSConfiguration.assetConfigs[assetInfoForTBTCOnUSDSInComet.offset].supplyCap).to.equal(0); + + // 11 - 14 Compare updated assets on USDC Comet + const cometUSDC = new Contract( + USDC_COMET, + [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))' + ], + await deploymentManager.getSigner() + ); + + const assetInfoForTBTCOnUSDCInComet = await cometUSDC.getAssetInfoByAddress(tBTC); + expect(assetInfoForTBTCOnUSDCInComet.supplyCap).to.equal(BigNumber.from(40).mul(assetInfoForTBTCOnUSDCInComet.scale)); + + const assetInfoForUNIOnUSDCInComet = await cometUSDC.getAssetInfoByAddress(UNI); + expect(assetInfoForUNIOnUSDCInComet.supplyCap).to.equal(BigNumber.from(364_691).mul(assetInfoForUNIOnUSDCInComet.scale)); + + const assetInfoForLINKOnUSDCInComet = await cometUSDC.getAssetInfoByAddress(LINK); + expect(assetInfoForLINKOnUSDCInComet.supplyCap).to.equal(BigNumber.from(585_990).mul(assetInfoForLINKOnUSDCInComet.scale)); + + const USDCConfiguration = await configurator.getConfiguration(cometUSDC.address); + expect(USDCConfiguration.assetConfigs[assetInfoForTBTCOnUSDCInComet.offset].supplyCap).to.equal(BigNumber.from(40).mul(assetInfoForTBTCOnUSDCInComet.scale)); + expect(USDCConfiguration.assetConfigs[assetInfoForUNIOnUSDCInComet.offset].supplyCap).to.equal(BigNumber.from(364_691).mul(assetInfoForUNIOnUSDCInComet.scale)); + expect(USDCConfiguration.assetConfigs[assetInfoForLINKOnUSDCInComet.offset].supplyCap).to.equal(BigNumber.from(585_990).mul(assetInfoForLINKOnUSDCInComet.scale)); + }, +}); diff --git a/deployments/mainnet/usdt/migrations/1770317078_add_usde_collateral.ts b/deployments/mainnet/usdt/migrations/1770317078_add_usde_collateral.ts new file mode 100644 index 000000000..166125689 --- /dev/null +++ b/deployments/mainnet/usdt/migrations/1770317078_add_usde_collateral.ts @@ -0,0 +1,134 @@ +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { exp, proposal } from '../../../../src/deploy'; + +const USDe_ADDRESS = '0x4c9EDD5852cd905f086C759E8383e09bff1E68B3'; +const USDe_TO_USD_PRICE_FEED = '0xa569d910839Ae8865Da8F8e70FfFb0cBA869F961'; + +export default migration('1770317078_add_usde_collateral', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const USDe = await deploymentManager.existing( + 'USDe', + USDe_ADDRESS, + 'mainnet', + 'contracts/ERC20.sol:ERC20' + ); + const USDePriceFeed = await deploymentManager.existing( + 'USDe:priceFeed', + USDe_TO_USD_PRICE_FEED, + 'mainnet' + ); + + const { + governor, + comet, + cometAdmin, + configurator, + } = await deploymentManager.getContracts(); + + const USDeAssetConfig = { + asset: USDe.address, + priceFeed: USDePriceFeed.address, + decimals: await USDe.decimals(), + borrowCollateralFactor: exp(0.89, 18), + liquidateCollateralFactor: exp(0.94, 18), + liquidationFactor: exp(0.96, 18), + supplyCap: exp(30_000_000, 18), + }; + + const mainnetActions = [ + // 1. Add USDe as asset + { + contract: configurator, + signature: 'addAsset(address,(address,address,uint8,uint64,uint64,uint64,uint128))', + args: [comet.address, USDeAssetConfig], + }, + // 2. Deploy and upgrade to a new version of Comet + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, comet.address], + }, + ]; + + const description = `# Add USDe as collateral into cUSDTv3 on Mainnet + +## Proposal summary + +WOOF! proposes to add USDe into cUSDTv3 on Ethereum network. This proposal takes the governance steps recommended and necessary to update a Compound III USDT market on Ethereum. Simulations have confirmed the market’s readiness, as much as possible, using the [Comet scenario suite](https://github.com/compound-finance/comet/tree/main/scenario). The new parameters include setting the risk parameters based on the [recommendations from Gauntlet](https://www.comp.xyz/t/gauntlet-parameter-recommendations-for-usde-on-mainnet-usdc-usdt-comets/7580/1). +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1090) and [forum discussion](https://www.comp.xyz/t/gauntlet-parameter-recommendations-for-usde-on-mainnet-usdc-usdt-comets/7580). + + +## Proposal Actions + +The first action adds USDe asset as collateral with corresponding configurations. + +The second action deploys and upgrades Comet to a new version.`; + + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 300_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(deploymentManager: DeploymentManager): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + const { comet, configurator } = await deploymentManager.getContracts(); + + const USDeAssetIndex = Number(await comet.numAssets()) - 1; + + const USDe = await deploymentManager.existing( + 'USDe', + USDe_ADDRESS, + 'mainnet', + 'contracts/ERC20.sol:ERC20' + ); + const USDeAssetConfig = { + asset: USDe.address, + priceFeed: USDe_TO_USD_PRICE_FEED, + decimals: 18n, + borrowCollateralFactor: exp(0.89, 18), + liquidateCollateralFactor: exp(0.94, 18), + liquidationFactor: exp(0.96, 18), + supplyCap: exp(30_000_000, 18), + }; + + // 1. Compare USDe asset config with Comet and Configurator asset info + const cometUSDeAssetInfo = await comet.getAssetInfoByAddress(USDe_ADDRESS); + expect(USDeAssetIndex).to.be.equal(cometUSDeAssetInfo.offset); + expect(USDeAssetConfig.asset).to.be.equal(cometUSDeAssetInfo.asset); + expect(USDeAssetConfig.priceFeed).to.be.equal(cometUSDeAssetInfo.priceFeed); + expect(exp(1, USDeAssetConfig.decimals)).to.be.equal(cometUSDeAssetInfo.scale); + expect(USDeAssetConfig.borrowCollateralFactor).to.be.equal(cometUSDeAssetInfo.borrowCollateralFactor); + expect(USDeAssetConfig.liquidateCollateralFactor).to.be.equal(cometUSDeAssetInfo.liquidateCollateralFactor); + expect(USDeAssetConfig.liquidationFactor).to.be.equal(cometUSDeAssetInfo.liquidationFactor); + expect(USDeAssetConfig.supplyCap).to.be.equal(cometUSDeAssetInfo.supplyCap); + + const configuratorUSDeAssetConfig = (await configurator.getConfiguration(comet.address)).assetConfigs[USDeAssetIndex]; + expect(USDeAssetConfig.asset).to.be.equal(configuratorUSDeAssetConfig.asset); + expect(USDeAssetConfig.priceFeed).to.be.equal(configuratorUSDeAssetConfig.priceFeed); + expect(USDeAssetConfig.decimals).to.be.equal(configuratorUSDeAssetConfig.decimals); + expect(USDeAssetConfig.borrowCollateralFactor).to.be.equal(configuratorUSDeAssetConfig.borrowCollateralFactor); + expect(USDeAssetConfig.liquidateCollateralFactor).to.be.equal(configuratorUSDeAssetConfig.liquidateCollateralFactor); + expect(USDeAssetConfig.liquidationFactor).to.be.equal(configuratorUSDeAssetConfig.liquidationFactor); + expect(USDeAssetConfig.supplyCap).to.be.equal(configuratorUSDeAssetConfig.supplyCap); + }, +}); diff --git a/deployments/mainnet/usdt/migrations/1777297641_update_supply_caps_on_mainnet.ts b/deployments/mainnet/usdt/migrations/1777297641_update_supply_caps_on_mainnet.ts new file mode 100644 index 000000000..f4afeca91 --- /dev/null +++ b/deployments/mainnet/usdt/migrations/1777297641_update_supply_caps_on_mainnet.ts @@ -0,0 +1,234 @@ +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { exp, proposal } from '../../../../src/deploy'; +import { BigNumber, Contract } from 'ethers'; + +const USDC_COMET = '0xc3d688B66703497DAA19211EEdff47f25384cdc3'; +const USDT_COMET = '0x3Afdc9BCA9213A35503b077a6072F3D0d5AB0840'; +const USDS_COMET = '0x5D409e56D886231aDAf00c8775665AD0f9897b56'; + +const weETH = '0xcd5fe23c85820f7b72d0926fc9b05b43e359b7ee'; +const tBTC = '0x18084fbA666a33d37592fA2633fD49a74DD93a88'; +const mETH = '0xd5f7838f5c461feff7fe49ea5ebaf7728bb0adfa'; +const sFRAX = '0xa663b02cf0a4b149d2ad41910cb81e23e1c41c32'; +const UNI = '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984'; +const LINK = '0x514910771af9ca656af840dff83e8264ecf986ca'; + +export default migration('1777297641_update_supply_caps_on_mainnet', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const { + governor, + cometAdmin, + configurator, + } = await deploymentManager.getContracts(); + + const mainnetActions = [ + // 1. Update weETH supply cap on USDT Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDT_COMET, weETH, 0], + }, + // 2. Update mETH supply cap on USDT Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDT_COMET, mETH, 0], + }, + // 3. Update tBTC supply cap on USDT Comet to 73 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDT_COMET, tBTC, exp(73, 18)], + }, + // 4. Update sFRAX supply cap on USDT Comet to 33M + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDT_COMET, sFRAX, exp(33_000_000, 18)], + }, + // 5. Update UNI supply cap on USDT Comet to 310,336 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDT_COMET, UNI, exp(310_336, 18)], + }, + // 6. Update LINK supply cap on USDT Comet to 210,317 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDT_COMET, LINK, exp(210_317, 18)], + }, + // 7. Deploy and upgrade the USDT Comet implementation to apply the updates + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, USDT_COMET], + }, + // 8. Update weETH supply cap on USDS Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDS_COMET, weETH, 0], + }, + // 9. Update tBTC supply cap on USDS Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDS_COMET, tBTC, 0], + }, + // 10. Deploy and upgrade the USDS Comet implementation to apply the updates + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, USDS_COMET], + }, + // 11. Update tBTC supply cap on USDC Comet to 40 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDC_COMET, tBTC, exp(40, 18)], + }, + // 12. Update UNI supply cap on USDC Comet to 364,691 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDC_COMET, UNI, exp(364_691, 18)], + }, + // 13. Update LINK supply cap on USDC Comet to 585,990 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [USDC_COMET, LINK, exp(585_990, 18)], + }, + // 14. Deploy and upgrade the USDC Comet implementation to apply the updates + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, USDC_COMET], + }, + ]; + + const description = `# Ethereum Supply cap Reduction Across USD Based Comets + +## Proposal summary + +This proposal updates supply caps for a number of assets across the USD based Mainnet markets. The supply caps for the affected assets are being updated based on their current utilization and risk parameters. + +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1115) and [forum discussion](https://www.comp.xyz/t/ethereum-supply-cap-reduction-across-comets/7793). + +## Proposal actions + + +1 - 7. Updates supply caps for weETH and mETH to 0 and tBTC to 73, sFRAX to 33M, UNI to 310,336, and LINK to 210,317 on cUSDTv3 market and upgrades the Comet implementation to apply the changes. + +8 - 10. Updates supply caps for weETH and tBTC to 0 on cUSDSv3 market and upgrades the Comet implementation to apply the changes. + +11 - 14. Updates supply caps for tBTC to 40, UNI to 364,691, and LINK to 585,990 on cUSDCv3 market and upgrades the Comet implementation to apply the changes. +`; + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 600_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return false; + }, + + async verify(deploymentManager: DeploymentManager) { + const { configurator } = await deploymentManager.getContracts(); + + // 1 - 7 Compare updated assets on USDT Comet + const cometUSDT = new Contract( + USDT_COMET, + [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))' + ], + await deploymentManager.getSigner() + ); + + const assetInfoForWeETHOnUSDTInComet = await cometUSDT.getAssetInfoByAddress(weETH); + expect(assetInfoForWeETHOnUSDTInComet.supplyCap).to.equal(0); + + const assetInfoForMETHOnUSDTInComet = await cometUSDT.getAssetInfoByAddress(mETH); + expect(assetInfoForMETHOnUSDTInComet.supplyCap).to.equal(0); + + const assetInfoForTBTCOnUSDTInComet = await cometUSDT.getAssetInfoByAddress(tBTC); + expect(assetInfoForTBTCOnUSDTInComet.supplyCap).to.equal(BigNumber.from(73).mul(assetInfoForTBTCOnUSDTInComet.scale)); + + const assetInfoForSFRAXOnUSDTInComet = await cometUSDT.getAssetInfoByAddress(sFRAX); + expect(assetInfoForSFRAXOnUSDTInComet.supplyCap).to.equal(BigNumber.from(33_000_000).mul(assetInfoForSFRAXOnUSDTInComet.scale)); + + const assetInfoForUNIOnUSDTInComet = await cometUSDT.getAssetInfoByAddress(UNI); + expect(assetInfoForUNIOnUSDTInComet.supplyCap).to.equal(BigNumber.from(310_336).mul(assetInfoForUNIOnUSDTInComet.scale)); + + const assetInfoForLINKOnUSDTInComet = await cometUSDT.getAssetInfoByAddress(LINK); + expect(assetInfoForLINKOnUSDTInComet.supplyCap).to.equal(BigNumber.from(210_317).mul(assetInfoForLINKOnUSDTInComet.scale)); + + const USDTConfiguration = await configurator.getConfiguration(USDT_COMET); + expect(USDTConfiguration.assetConfigs[assetInfoForWeETHOnUSDTInComet.offset].supplyCap).to.equal(0); + expect(USDTConfiguration.assetConfigs[assetInfoForMETHOnUSDTInComet.offset].supplyCap).to.equal(0); + expect(USDTConfiguration.assetConfigs[assetInfoForTBTCOnUSDTInComet.offset].supplyCap).to.equal(BigNumber.from(73).mul(assetInfoForTBTCOnUSDTInComet.scale)); + expect(USDTConfiguration.assetConfigs[assetInfoForSFRAXOnUSDTInComet.offset].supplyCap).to.equal(BigNumber.from(33_000_000).mul(assetInfoForSFRAXOnUSDTInComet.scale)); + expect(USDTConfiguration.assetConfigs[assetInfoForUNIOnUSDTInComet.offset].supplyCap).to.equal(BigNumber.from(310_336).mul(assetInfoForUNIOnUSDTInComet.scale)); + expect(USDTConfiguration.assetConfigs[assetInfoForLINKOnUSDTInComet.offset].supplyCap).to.equal(BigNumber.from(210_317).mul(assetInfoForLINKOnUSDTInComet.scale)); + + // 8 - 10 Compare updated assets on USDS Comet + const cometUSDS = new Contract( + USDS_COMET, + [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))' + ], + await deploymentManager.getSigner() + ); + + const assetInfoForWeETHOnUSDSInComet = await cometUSDS.getAssetInfoByAddress(weETH); + expect(assetInfoForWeETHOnUSDSInComet.supplyCap).to.equal(0); + + const assetInfoForTBTCOnUSDSInComet = await cometUSDS.getAssetInfoByAddress(tBTC); + expect(assetInfoForTBTCOnUSDSInComet.supplyCap).to.equal(0); + + const USDSConfiguration = await configurator.getConfiguration(USDS_COMET); + expect(USDSConfiguration.assetConfigs[assetInfoForWeETHOnUSDSInComet.offset].supplyCap).to.equal(0); + expect(USDSConfiguration.assetConfigs[assetInfoForTBTCOnUSDSInComet.offset].supplyCap).to.equal(0); + + // 11 - 14 Compare updated assets on USDC Comet + const cometUSDC = new Contract( + USDC_COMET, + [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))' + ], + await deploymentManager.getSigner() + ); + + const assetInfoForTBTCOnUSDCInComet = await cometUSDC.getAssetInfoByAddress(tBTC); + expect(assetInfoForTBTCOnUSDCInComet.supplyCap).to.equal(BigNumber.from(40).mul(assetInfoForTBTCOnUSDCInComet.scale)); + + const assetInfoForUNIOnUSDCInComet = await cometUSDC.getAssetInfoByAddress(UNI); + expect(assetInfoForUNIOnUSDCInComet.supplyCap).to.equal(BigNumber.from(364_691).mul(assetInfoForUNIOnUSDCInComet.scale)); + + const assetInfoForLINKOnUSDCInComet = await cometUSDC.getAssetInfoByAddress(LINK); + expect(assetInfoForLINKOnUSDCInComet.supplyCap).to.equal(BigNumber.from(585_990).mul(assetInfoForLINKOnUSDCInComet.scale)); + + const USDCConfiguration = await configurator.getConfiguration(cometUSDC.address); + expect(USDCConfiguration.assetConfigs[assetInfoForTBTCOnUSDCInComet.offset].supplyCap).to.equal(BigNumber.from(40).mul(assetInfoForTBTCOnUSDCInComet.scale)); + expect(USDCConfiguration.assetConfigs[assetInfoForUNIOnUSDCInComet.offset].supplyCap).to.equal(BigNumber.from(364_691).mul(assetInfoForUNIOnUSDCInComet.scale)); + expect(USDCConfiguration.assetConfigs[assetInfoForLINKOnUSDCInComet.offset].supplyCap).to.equal(BigNumber.from(585_990).mul(assetInfoForLINKOnUSDCInComet.scale)); + }, +}); diff --git a/deployments/mainnet/wbtc/migrations/1777625885_update_supply_caps_on_mainnet.ts b/deployments/mainnet/wbtc/migrations/1777625885_update_supply_caps_on_mainnet.ts new file mode 100644 index 000000000..3961760b8 --- /dev/null +++ b/deployments/mainnet/wbtc/migrations/1777625885_update_supply_caps_on_mainnet.ts @@ -0,0 +1,279 @@ +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { exp, proposal } from '../../../../src/deploy'; +import { BigNumber, Contract } from 'ethers'; + +const WBTC_COMET = '0xe85Dc543813B8c2CFEaAc371517b925a166a9293'; +const WETH_COMET = '0xA17581A9E3356d9A858b789D68B4d866e593aE94'; +const WSTETH_COMET = '0x3D0bb1ccaB520A66e607822fC55BC921738fAFE3'; + +const weETH = '0xcd5fe23c85820f7b72d0926fc9b05b43e359b7ee'; +const ezETH = '0xbf5495Efe5DB9ce00f80364C8B423567e58d2110'; +const tETH = '0xd11c452fc99cf405034ee446803b6f6c1f6d5ed8'; +const wOETH = '0xdcee70654261af21c44c093c300ed3bb97b78192'; +const tBTC = '0x18084fbA666a33d37592fA2633fD49a74DD93a88'; +const rswETH = '0xFAe103DC9cf190eD75350761e95403b7b8aFa6c0'; +const rETH = '0xae78736cd615f374d3085123a210448e74fc6393'; +const osETH = '0xf1c9acdc66974dfb6decb12aa385b9cd01190e38'; +const ETHx = '0xA35b1B31Ce002FBF2058D22F30f95D405200A15b'; +const pufETH = '0xd9a442856c234a39a81a089c06451ebaa4306a72'; +const pumpBTC = '0xf469fbd2abcd6b9de8e169d128226c0fc90a012e'; +const LBTC = '0x8236a87084f8b84306f72007f36f2618a5634494'; + +export default migration('1777625885_update_supply_caps_on_mainnet', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const { + governor, + cometAdmin, + configurator, + } = await deploymentManager.getContracts(); + + const mainnetActions = [ + // 1. Update weETH supply cap on wstETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WSTETH_COMET, weETH, 0], + }, + // 2. Update ezETH supply cap on wstETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WSTETH_COMET, ezETH, 0], + }, + // 3. Update tETH supply cap on wstETH Comet to 44 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WSTETH_COMET, tETH, exp(44, 18)], + }, + // 4. Deploy and upgrade the wstETH Comet implementation to apply the updates + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, WSTETH_COMET], + }, + // 5. Update wOETH supply cap on WETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, wOETH, 0], + }, + // 6. Update tBTC supply cap on WETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, tBTC, 0], + }, + // 7. Update rswETH supply cap on WETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, rswETH, 0], + }, + // 8. Update rETH supply cap on WETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, rETH, 0], + }, + // 9. Update osETH supply cap on WETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, osETH, 0], + }, + // 10. Update ETHx supply cap on WETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, ETHx, 0], + }, + // 11. Update weETH supply cap on WETH Comet to 3,860 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, weETH, exp(3860, 18)], + }, + // 12. Update tETH supply cap on WETH Comet to 1,545 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, tETH, exp(1545, 18)], + }, + // 13. Update pufETH supply cap on WETH Comet to 105 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, pufETH, exp(105, 18)], + }, + // 14. Update ezETH supply cap on WETH Comet to 33,163 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, ezETH, exp(33163, 18)], + }, + // 15. Deploy and upgrade the WETH Comet implementation to apply the updates + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, WETH_COMET], + }, + // 16. Update pumpBTC supply cap on WBTC Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WBTC_COMET, pumpBTC, 0], + }, + // 17. Update LBTC supply cap on WBTC Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WBTC_COMET, LBTC, 0], + }, + // 18. Deploy and upgrade the WBTC Comet implementation to apply the updates + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, WBTC_COMET], + }, + ]; + + const description = `# Ethereum Supply cap Reduction Across Non-USD Based Comets + +## Proposal summary + +This proposal updates supply caps for a number of assets across the non-usd based Mainnet markets. The supply caps for the affected assets are being updated based on their current utilization and risk parameters. + +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1116) and [forum discussion](https://www.comp.xyz/t/ethereum-supply-cap-reduction-across-comets/7793). + +## Proposal actions + +1 - 4. Updates supply caps for weETH and ezETH to 0 and tETH to 44 on cWstETHv3 market and upgrades the Comet implementation to apply the changes. + +5 - 15. Updates supply caps for wOETH, tBTC, rswETH, rETH, osETH, and ETHx to 0 and weETH to 3,860, tETH to 1,545, pufETH to 105, and ezETH to 33,163 on cWETHv3 market and upgrades the Comet implementation to apply the changes. + +16 - 18. Updates supply caps for pumpBTC and LBTC to 0 on cWBTCv3 market and upgrades the Comet implementation to apply the changes. +`; + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 600_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return false; + }, + + async verify(deploymentManager: DeploymentManager) { + const { configurator } = await deploymentManager.getContracts(); + + // 1 - 4 Compare updated assets on wstETH Comet + const cometWstETH = new Contract( + WSTETH_COMET, + [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))' + ], + await deploymentManager.getSigner() + ); + + const assetInfoForWeETHOnWstETHInComet = await cometWstETH.getAssetInfoByAddress(weETH); + expect(assetInfoForWeETHOnWstETHInComet.supplyCap).to.equal(0); + + const assetInfoForEzETHOnWstETHInComet = await cometWstETH.getAssetInfoByAddress(ezETH); + expect(assetInfoForEzETHOnWstETHInComet.supplyCap).to.equal(0); + + const assetInfoForTETHOnWstETHInComet = await cometWstETH.getAssetInfoByAddress(tETH); + expect(assetInfoForTETHOnWstETHInComet.supplyCap).to.equal(BigNumber.from(44).mul(assetInfoForTETHOnWstETHInComet.scale)); + + const wstETHConfiguration = await configurator.getConfiguration(WSTETH_COMET); + expect(wstETHConfiguration.assetConfigs[assetInfoForWeETHOnWstETHInComet.offset].supplyCap).to.equal(0); + expect(wstETHConfiguration.assetConfigs[assetInfoForEzETHOnWstETHInComet.offset].supplyCap).to.equal(0); + expect(wstETHConfiguration.assetConfigs[assetInfoForTETHOnWstETHInComet.offset].supplyCap).to.equal(BigNumber.from(44).mul(assetInfoForTETHOnWstETHInComet.scale)); + + // 5 - 15 Compare updated assets on WETH Comet + const cometWETH = new Contract( + WETH_COMET, + [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))' + ], + await deploymentManager.getSigner() + ); + + const assetInfoForWOETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(wOETH); + expect(assetInfoForWOETHOnWETHInComet.supplyCap).to.equal(0); + + const assetInfoForTBTCOnWETHInComet = await cometWETH.getAssetInfoByAddress(tBTC); + expect(assetInfoForTBTCOnWETHInComet.supplyCap).to.equal(0); + + const assetInfoForRswETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(rswETH); + expect(assetInfoForRswETHOnWETHInComet.supplyCap).to.equal(0); + + const assetInfoForRETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(rETH); + expect(assetInfoForRETHOnWETHInComet.supplyCap).to.equal(0); + + const assetInfoForOsETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(osETH); + expect(assetInfoForOsETHOnWETHInComet.supplyCap).to.equal(0); + + const assetInfoForETHxOnWETHInComet = await cometWETH.getAssetInfoByAddress(ETHx); + expect(assetInfoForETHxOnWETHInComet.supplyCap).to.equal(0); + + const assetInfoForWeETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(weETH); + expect(assetInfoForWeETHOnWETHInComet.supplyCap).to.equal(BigNumber.from(3860).mul(assetInfoForWeETHOnWETHInComet.scale)); + + const assetInfoForTETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(tETH); + expect(assetInfoForTETHOnWETHInComet.supplyCap).to.equal(BigNumber.from(1545).mul(assetInfoForTETHOnWETHInComet.scale)); + + const assetInfoForPufETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(pufETH); + expect(assetInfoForPufETHOnWETHInComet.supplyCap).to.equal(BigNumber.from(105).mul(assetInfoForPufETHOnWETHInComet.scale)); + + const assetInfoForEzETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(ezETH); + expect(assetInfoForEzETHOnWETHInComet.supplyCap).to.equal(BigNumber.from(33163).mul(assetInfoForEzETHOnWETHInComet.scale)); + + const WETHConfiguration = await configurator.getConfiguration(WETH_COMET); + expect(WETHConfiguration.assetConfigs[assetInfoForWOETHOnWETHInComet.offset].supplyCap).to.equal(0); + expect(WETHConfiguration.assetConfigs[assetInfoForTBTCOnWETHInComet.offset].supplyCap).to.equal(0); + expect(WETHConfiguration.assetConfigs[assetInfoForRswETHOnWETHInComet.offset].supplyCap).to.equal(0); + expect(WETHConfiguration.assetConfigs[assetInfoForRETHOnWETHInComet.offset].supplyCap).to.equal(0); + expect(WETHConfiguration.assetConfigs[assetInfoForOsETHOnWETHInComet.offset].supplyCap).to.equal(0); + expect(WETHConfiguration.assetConfigs[assetInfoForETHxOnWETHInComet.offset].supplyCap).to.equal(0); + expect(WETHConfiguration.assetConfigs[assetInfoForWeETHOnWETHInComet.offset].supplyCap).to.equal(BigNumber.from(3860).mul(assetInfoForWeETHOnWETHInComet.scale)); + expect(WETHConfiguration.assetConfigs[assetInfoForTETHOnWETHInComet.offset].supplyCap).to.equal(BigNumber.from(1545).mul(assetInfoForTETHOnWETHInComet.scale)); + expect(WETHConfiguration.assetConfigs[assetInfoForPufETHOnWETHInComet.offset].supplyCap).to.equal(BigNumber.from(105).mul(assetInfoForPufETHOnWETHInComet.scale)); + expect(WETHConfiguration.assetConfigs[assetInfoForEzETHOnWETHInComet.offset].supplyCap).to.equal(BigNumber.from(33163).mul(assetInfoForEzETHOnWETHInComet.scale)); + + // 16 - 18 Compare updated assets on WBTC Comet + const cometWBTC = new Contract( + WBTC_COMET, + [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))' + ], + await deploymentManager.getSigner() + ); + + const assetInfoForPumpBTCOnWBTCInComet = await cometWBTC.getAssetInfoByAddress(pumpBTC); + expect(assetInfoForPumpBTCOnWBTCInComet.supplyCap).to.equal(0); + + const assetInfoForLBTCOnWBTCInComet = await cometWBTC.getAssetInfoByAddress(LBTC); + expect(assetInfoForLBTCOnWBTCInComet.supplyCap).to.equal(0); + + const WBTCConfiguration = await configurator.getConfiguration(WBTC_COMET); + expect(WBTCConfiguration.assetConfigs[assetInfoForPumpBTCOnWBTCInComet.offset].supplyCap).to.equal(0); + expect(WBTCConfiguration.assetConfigs[assetInfoForLBTCOnWBTCInComet.offset].supplyCap).to.equal(0); + }, +}); diff --git a/deployments/mainnet/weth/migrations/1773227248_update_reth_pricefeed.ts b/deployments/mainnet/weth/migrations/1773227248_update_reth_pricefeed.ts new file mode 100644 index 000000000..1443052f3 --- /dev/null +++ b/deployments/mainnet/weth/migrations/1773227248_update_reth_pricefeed.ts @@ -0,0 +1,135 @@ +import { Contract } from 'ethers'; +import { DeploymentManager, migration } from '../../../../plugins/deployment_manager'; +import { proposal, exp } from '../../../../src/deploy'; + +import { expect } from 'chai'; + +let newRETHPriceFeed: string; +let oldRETHPriceFeed: string; + +const FEED_DECIMALS = 8; +const blockToFetch = 24000000; + +export default migration('1773227248_update_reth_pricefeed', { + async prepare(deploymentManager: DeploymentManager) { + const { + rETH, + timelock, + 'WETH:priceFeed' : constantPriceFeed, + } = await deploymentManager.getContracts(); + const blockToFetchTimestamp = (await deploymentManager.hre.ethers.provider.getBlock(blockToFetch))!.timestamp; + + const currentRatioRETH = await rETH.getExchangeRate({blockTag: blockToFetch}); + const rEthCapoPriceFeed = await deploymentManager.deploy( + 'rETH:priceFeed', + 'capo/contracts/RETHCorrelatedAssetsPriceOracle.sol', + [ + timelock.address, + constantPriceFeed.address, + rETH.address, + 'rETH / ETH CAPO Price Feed', + FEED_DECIMALS, + 3600, + { + snapshotRatio: currentRatioRETH, + snapshotTimestamp: blockToFetchTimestamp, + maxYearlyRatioGrowthPercent: exp(0.0290, 4) + } + ], + true + ); + return { rETHPriceFeed: rEthCapoPriceFeed.address }; + }, + + async enact(deploymentManager: DeploymentManager, _, { rETHPriceFeed }) { + const trace = deploymentManager.tracer(); + + const { + governor, + comet, + configurator, + cometAdmin, + rETH + } = await deploymentManager.getContracts(); + + [,, oldRETHPriceFeed] = await comet.getAssetInfoByAddress(rETH.address); + + newRETHPriceFeed = rETHPriceFeed; + const mainnetActions = [ + // 1. Update the price feed for rETH + { + contract: configurator, + signature: 'updateAssetPriceFeed(address,address,address)', + args: [comet.address, rETH.address, rETHPriceFeed], + }, + // 2. Deploy and upgrade to a new version of Comet + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, comet.address], + }, + ]; + const description = `# Update rETH price feed in cWETHv3 on Mainnet + +## Proposal summary + +This proposal updates the rETH price feed in the Compound III WETH market on Ethereum. + +Due to the deprecation of the RETH / ETH Chainlink Oracle, the rETH price feed must be replaced with a new CAPO price feed that fetches the rETH / ETH exchange rate directly from the rETH contract. The new price feed retains the same CAPO parameters as the previous one. + +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1097) and [forum discussion for CAPO](https://www.comp.xyz/t/woof-correlated-assets-price-oracle-capo/6245). + +### New price feed audit + +New CAPO price feed for rETH has been audited by [Certora](https://www.certora.com/reports/compound-reth-capo) and no issues were found. + +## Proposal Actions + +The first action updates the rETH price feed to the new CAPO contract. + +The second action deploys and upgrades Comet to a new version.`; + + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 300_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(deploymentManager: DeploymentManager): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + const { + comet, + configurator, + rETH + } = await deploymentManager.getContracts(); + + const rETHId = await configurator.getAssetIndex(comet.address, rETH.address); + const configuration = await configurator.getConfiguration(comet.address); + expect(configuration.assetConfigs[rETHId].priceFeed).to.eq(newRETHPriceFeed); + expect((await comet.getAssetInfoByAddress(rETH.address)).priceFeed).to.equal(newRETHPriceFeed); + expect(oldRETHPriceFeed).to.not.equal(newRETHPriceFeed); + expect(await comet.getPrice(newRETHPriceFeed)).to.be.closeTo(await comet.getPrice(oldRETHPriceFeed), exp(0.01, 8)); + + const rETHPriceFeed = (await comet.getAssetInfoByAddress(rETH.address)).priceFeed; + expect(rETHPriceFeed).to.equal(newRETHPriceFeed); + + const newPriceFeedContract = new Contract( + newRETHPriceFeed, + ['function maxYearlyRatioGrowthPercent() view returns (uint32)'], + await deploymentManager.getSigner() + ); + + expect(await newPriceFeedContract.maxYearlyRatioGrowthPercent()).to.equal(290); + }, +}); diff --git a/deployments/mainnet/weth/migrations/1777625885_update_supply_caps_on_mainnet.ts b/deployments/mainnet/weth/migrations/1777625885_update_supply_caps_on_mainnet.ts new file mode 100644 index 000000000..421137207 --- /dev/null +++ b/deployments/mainnet/weth/migrations/1777625885_update_supply_caps_on_mainnet.ts @@ -0,0 +1,279 @@ +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { exp, proposal } from '../../../../src/deploy'; +import { BigNumber, Contract } from 'ethers'; + +const WBTC_COMET = '0xe85Dc543813B8c2CFEaAc371517b925a166a9293'; +const WETH_COMET = '0xA17581A9E3356d9A858b789D68B4d866e593aE94'; +const WSTETH_COMET = '0x3D0bb1ccaB520A66e607822fC55BC921738fAFE3'; + +const weETH = '0xcd5fe23c85820f7b72d0926fc9b05b43e359b7ee'; +const ezETH = '0xbf5495Efe5DB9ce00f80364C8B423567e58d2110'; +const tETH = '0xd11c452fc99cf405034ee446803b6f6c1f6d5ed8'; +const wOETH = '0xdcee70654261af21c44c093c300ed3bb97b78192'; +const tBTC = '0x18084fbA666a33d37592fA2633fD49a74DD93a88'; +const rswETH = '0xFAe103DC9cf190eD75350761e95403b7b8aFa6c0'; +const rETH = '0xae78736cd615f374d3085123a210448e74fc6393'; +const osETH = '0xf1c9acdc66974dfb6decb12aa385b9cd01190e38'; +const ETHx = '0xA35b1B31Ce002FBF2058D22F30f95D405200A15b'; +const pufETH = '0xd9a442856c234a39a81a089c06451ebaa4306a72'; +const pumpBTC = '0xf469fbd2abcd6b9de8e169d128226c0fc90a012e'; +const LBTC = '0x8236a87084f8b84306f72007f36f2618a5634494'; + +export default migration('1777625885_update_supply_caps_on_mainnet', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const { + governor, + cometAdmin, + configurator, + } = await deploymentManager.getContracts(); + + const mainnetActions = [ + // 1. Update weETH supply cap on wstETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WSTETH_COMET, weETH, 0], + }, + // 2. Update ezETH supply cap on wstETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WSTETH_COMET, ezETH, 0], + }, + // 3. Update tETH supply cap on wstETH Comet to 44 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WSTETH_COMET, tETH, exp(44, 18)], + }, + // 4. Deploy and upgrade the wstETH Comet implementation to apply the updates + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, WSTETH_COMET], + }, + // 5. Update wOETH supply cap on WETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, wOETH, 0], + }, + // 6. Update tBTC supply cap on WETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, tBTC, 0], + }, + // 7. Update rswETH supply cap on WETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, rswETH, 0], + }, + // 8. Update rETH supply cap on WETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, rETH, 0], + }, + // 9. Update osETH supply cap on WETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, osETH, 0], + }, + // 10. Update ETHx supply cap on WETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, ETHx, 0], + }, + // 11. Update weETH supply cap on WETH Comet to 3,860 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, weETH, exp(3860, 18)], + }, + // 12. Update tETH supply cap on WETH Comet to 1,545 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, tETH, exp(1545, 18)], + }, + // 13. Update pufETH supply cap on WETH Comet to 105 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, pufETH, exp(105, 18)], + }, + // 14. Update ezETH supply cap on WETH Comet to 33,163 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, ezETH, exp(33163, 18)], + }, + // 15. Deploy and upgrade the WETH Comet implementation to apply the updates + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, WETH_COMET], + }, + // 16. Update pumpBTC supply cap on WBTC Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WBTC_COMET, pumpBTC, 0], + }, + // 17. Update LBTC supply cap on WBTC Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WBTC_COMET, LBTC, 0], + }, + // 18. Deploy and upgrade the WBTC Comet implementation to apply the updates + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, WBTC_COMET], + }, + ]; + + const description = `# Ethereum Supply cap Reduction Across Non-USD Based Comets + +## Proposal summary + +This proposal updates supply caps for a number of assets across the non-usd based Mainnet markets. The supply caps for the affected assets are being updated based on their current utilization and risk parameters. + +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1116) and [forum discussion](https://www.comp.xyz/t/ethereum-supply-cap-reduction-across-comets/7793). + +## Proposal actions + +1 - 4. Updates supply caps for weETH and ezETH to 0 and tETH to 44 on cWstETHv3 market and upgrades the Comet implementation to apply the changes. + +5 - 15. Updates supply caps for wOETH, tBTC, rswETH, rETH, osETH, and ETHx to 0 and weETH to 3,860, tETH to 1,545, pufETH to 105, and ezETH to 33,163 on cWETHv3 market and upgrades the Comet implementation to apply the changes. + +16 - 18. Updates supply caps for pumpBTC and LBTC to 0 on cWBTCv3 market and upgrades the Comet implementation to apply the changes. +`; + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 600_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(deploymentManager: DeploymentManager): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + const { configurator } = await deploymentManager.getContracts(); + + // 1 - 4 Compare updated assets on wstETH Comet + const cometWstETH = new Contract( + WSTETH_COMET, + [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))' + ], + await deploymentManager.getSigner() + ); + + const assetInfoForWeETHOnWstETHInComet = await cometWstETH.getAssetInfoByAddress(weETH); + expect(assetInfoForWeETHOnWstETHInComet.supplyCap).to.equal(0); + + const assetInfoForEzETHOnWstETHInComet = await cometWstETH.getAssetInfoByAddress(ezETH); + expect(assetInfoForEzETHOnWstETHInComet.supplyCap).to.equal(0); + + const assetInfoForTETHOnWstETHInComet = await cometWstETH.getAssetInfoByAddress(tETH); + expect(assetInfoForTETHOnWstETHInComet.supplyCap).to.equal(BigNumber.from(44).mul(assetInfoForTETHOnWstETHInComet.scale)); + + const wstETHConfiguration = await configurator.getConfiguration(WSTETH_COMET); + expect(wstETHConfiguration.assetConfigs[assetInfoForWeETHOnWstETHInComet.offset].supplyCap).to.equal(0); + expect(wstETHConfiguration.assetConfigs[assetInfoForEzETHOnWstETHInComet.offset].supplyCap).to.equal(0); + expect(wstETHConfiguration.assetConfigs[assetInfoForTETHOnWstETHInComet.offset].supplyCap).to.equal(BigNumber.from(44).mul(assetInfoForTETHOnWstETHInComet.scale)); + + // 5 - 15 Compare updated assets on WETH Comet + const cometWETH = new Contract( + WETH_COMET, + [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))' + ], + await deploymentManager.getSigner() + ); + + const assetInfoForWOETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(wOETH); + expect(assetInfoForWOETHOnWETHInComet.supplyCap).to.equal(0); + + const assetInfoForTBTCOnWETHInComet = await cometWETH.getAssetInfoByAddress(tBTC); + expect(assetInfoForTBTCOnWETHInComet.supplyCap).to.equal(0); + + const assetInfoForRswETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(rswETH); + expect(assetInfoForRswETHOnWETHInComet.supplyCap).to.equal(0); + + const assetInfoForRETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(rETH); + expect(assetInfoForRETHOnWETHInComet.supplyCap).to.equal(0); + + const assetInfoForOsETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(osETH); + expect(assetInfoForOsETHOnWETHInComet.supplyCap).to.equal(0); + + const assetInfoForETHxOnWETHInComet = await cometWETH.getAssetInfoByAddress(ETHx); + expect(assetInfoForETHxOnWETHInComet.supplyCap).to.equal(0); + + const assetInfoForWeETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(weETH); + expect(assetInfoForWeETHOnWETHInComet.supplyCap).to.equal(BigNumber.from(3860).mul(assetInfoForWeETHOnWETHInComet.scale)); + + const assetInfoForTETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(tETH); + expect(assetInfoForTETHOnWETHInComet.supplyCap).to.equal(BigNumber.from(1545).mul(assetInfoForTETHOnWETHInComet.scale)); + + const assetInfoForPufETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(pufETH); + expect(assetInfoForPufETHOnWETHInComet.supplyCap).to.equal(BigNumber.from(105).mul(assetInfoForPufETHOnWETHInComet.scale)); + + const assetInfoForEzETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(ezETH); + expect(assetInfoForEzETHOnWETHInComet.supplyCap).to.equal(BigNumber.from(33163).mul(assetInfoForEzETHOnWETHInComet.scale)); + + const WETHConfiguration = await configurator.getConfiguration(WETH_COMET); + expect(WETHConfiguration.assetConfigs[assetInfoForWOETHOnWETHInComet.offset].supplyCap).to.equal(0); + expect(WETHConfiguration.assetConfigs[assetInfoForTBTCOnWETHInComet.offset].supplyCap).to.equal(0); + expect(WETHConfiguration.assetConfigs[assetInfoForRswETHOnWETHInComet.offset].supplyCap).to.equal(0); + expect(WETHConfiguration.assetConfigs[assetInfoForRETHOnWETHInComet.offset].supplyCap).to.equal(0); + expect(WETHConfiguration.assetConfigs[assetInfoForOsETHOnWETHInComet.offset].supplyCap).to.equal(0); + expect(WETHConfiguration.assetConfigs[assetInfoForETHxOnWETHInComet.offset].supplyCap).to.equal(0); + expect(WETHConfiguration.assetConfigs[assetInfoForWeETHOnWETHInComet.offset].supplyCap).to.equal(BigNumber.from(3860).mul(assetInfoForWeETHOnWETHInComet.scale)); + expect(WETHConfiguration.assetConfigs[assetInfoForTETHOnWETHInComet.offset].supplyCap).to.equal(BigNumber.from(1545).mul(assetInfoForTETHOnWETHInComet.scale)); + expect(WETHConfiguration.assetConfigs[assetInfoForPufETHOnWETHInComet.offset].supplyCap).to.equal(BigNumber.from(105).mul(assetInfoForPufETHOnWETHInComet.scale)); + expect(WETHConfiguration.assetConfigs[assetInfoForEzETHOnWETHInComet.offset].supplyCap).to.equal(BigNumber.from(33163).mul(assetInfoForEzETHOnWETHInComet.scale)); + + // 16 - 18 Compare updated assets on WBTC Comet + const cometWBTC = new Contract( + WBTC_COMET, + [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))' + ], + await deploymentManager.getSigner() + ); + + const assetInfoForPumpBTCOnWBTCInComet = await cometWBTC.getAssetInfoByAddress(pumpBTC); + expect(assetInfoForPumpBTCOnWBTCInComet.supplyCap).to.equal(0); + + const assetInfoForLBTCOnWBTCInComet = await cometWBTC.getAssetInfoByAddress(LBTC); + expect(assetInfoForLBTCOnWBTCInComet.supplyCap).to.equal(0); + + const WBTCConfiguration = await configurator.getConfiguration(WBTC_COMET); + expect(WBTCConfiguration.assetConfigs[assetInfoForPumpBTCOnWBTCInComet.offset].supplyCap).to.equal(0); + expect(WBTCConfiguration.assetConfigs[assetInfoForLBTCOnWBTCInComet.offset].supplyCap).to.equal(0); + }, +}); diff --git a/deployments/mainnet/weth/migrations/1779099097_return_rseth_pricefeeds_on_weth_and_wsteth.ts b/deployments/mainnet/weth/migrations/1779099097_return_rseth_pricefeeds_on_weth_and_wsteth.ts new file mode 100644 index 000000000..1b93c666c --- /dev/null +++ b/deployments/mainnet/weth/migrations/1779099097_return_rseth_pricefeeds_on_weth_and_wsteth.ts @@ -0,0 +1,130 @@ +import { expect } from 'chai'; +import { Contract } from 'ethers'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { proposal } from '../../../../src/deploy'; + +const MAINNET_WETH_COMET = '0xA17581A9E3356d9A858b789D68B4d866e593aE94'; +const MAINNET_WSTETH_COMET = '0x3D0bb1ccaB520A66e607822fC55BC921738fAFE3'; + +const mainnetWethPriceFeedAddress = '0x5AbcFC8A649Ac15Ff7d41c0Dd0d53aF3bBb7F876'; +const mainnetWstEthPriceFeedAddress = '0x0Af91E13383FD771f21B40b79421B2d59E8214C2'; + +export default migration('1779099097_return_rseth_pricefeeds_on_weth_and_wsteth', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const { + configurator, + cometAdmin, + rsETH, + governor, + } = await deploymentManager.getContracts(); + + const mainnetActions = [ + // 1. Update the price feed for rsETH in the WETH market on Mainnet + { + contract: configurator, + signature: 'updateAssetPriceFeed(address,address,address)', + args: [MAINNET_WETH_COMET, rsETH.address, mainnetWethPriceFeedAddress], + }, + // 2. Update the price feed for rsETH in the wstETH market on Mainnet + { + contract: configurator, + signature: 'updateAssetPriceFeed(address,address,address)', + args: [MAINNET_WSTETH_COMET, rsETH.address, mainnetWstEthPriceFeedAddress], + }, + // 3. Deploy and upgrade WETH Comet to a new version + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, MAINNET_WETH_COMET], + }, + // 4. Deploy and upgrade wstETH Comet to a new version + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, MAINNET_WSTETH_COMET], + }, + ]; + + const description = `# Return rsETH Price Feeds on WETH and wstETH Markets (Mainnet) + +## Summary + +This proposal is a follow-up to the emergency rsETH oracle migration and returns the Mainnet WETH and wstETH Comets to their prior rsETH price feed configuration. + +The earlier migration to a MinMaxConstantPriceFeed was introduced as a temporary risk-control measure after the April 18 Kelp rsETH bridge exploit. With conditions now stabilized, this proposal removes the temporary setup and restores the previous feed configuration. + +Implementation details: [PR #1122](https://github.com/compound-finance/comet/pull/1122). + +## Proposal Actions + +1. Update the rsETH price feed on the Mainnet WETH market. +2. Update the rsETH price feed on the Mainnet wstETH market. +3. Deploy and upgrade the WETH Comet to apply the configuration change. +4. Deploy and upgrade the wstETH Comet to apply the configuration change. +`; + + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 600_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return false; + }, + + async verify(deploymentManager: DeploymentManager) { + const { + rsETH + } = await deploymentManager.getContracts(); + + const cometWETH = new Contract(MAINNET_WETH_COMET, [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))', + ], await deploymentManager.getSigner()); + + const wethCometAssetInfo = await cometWETH.getAssetInfoByAddress(rsETH.address); + expect(wethCometAssetInfo.priceFeed).to.equal(mainnetWethPriceFeedAddress); + + const priceFeedWeth = new Contract( + wethCometAssetInfo.priceFeed, + [ + 'function latestRoundData() external view returns(uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)', + 'function decimals() external view returns (uint8)', + ], + await deploymentManager.getSigner()); + expect(await priceFeedWeth.decimals()).to.equal(8); + expect((await priceFeedWeth.latestRoundData()).answer).to.not.equal(0); + + const wstEthComet = new Contract(MAINNET_WSTETH_COMET, [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))', + ], await deploymentManager.getSigner()); + + const wstEthCometAssetInfo = await wstEthComet.getAssetInfoByAddress(rsETH.address); + expect(wstEthCometAssetInfo.priceFeed).to.equal(mainnetWstEthPriceFeedAddress); + + const priceFeedWstEth = new Contract( + wstEthCometAssetInfo.priceFeed, + [ + 'function latestRoundData() external view returns(uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)', + 'function decimals() external view returns (uint8)', + ], + await deploymentManager.getSigner()); + expect(await priceFeedWstEth.decimals()).to.equal(8); + expect((await priceFeedWstEth.latestRoundData()).answer).to.not.equal(0); + }, +}); diff --git a/deployments/mainnet/wsteth/migrations/1777625885_update_supply_caps_on_mainnet.ts b/deployments/mainnet/wsteth/migrations/1777625885_update_supply_caps_on_mainnet.ts new file mode 100644 index 000000000..3961760b8 --- /dev/null +++ b/deployments/mainnet/wsteth/migrations/1777625885_update_supply_caps_on_mainnet.ts @@ -0,0 +1,279 @@ +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { exp, proposal } from '../../../../src/deploy'; +import { BigNumber, Contract } from 'ethers'; + +const WBTC_COMET = '0xe85Dc543813B8c2CFEaAc371517b925a166a9293'; +const WETH_COMET = '0xA17581A9E3356d9A858b789D68B4d866e593aE94'; +const WSTETH_COMET = '0x3D0bb1ccaB520A66e607822fC55BC921738fAFE3'; + +const weETH = '0xcd5fe23c85820f7b72d0926fc9b05b43e359b7ee'; +const ezETH = '0xbf5495Efe5DB9ce00f80364C8B423567e58d2110'; +const tETH = '0xd11c452fc99cf405034ee446803b6f6c1f6d5ed8'; +const wOETH = '0xdcee70654261af21c44c093c300ed3bb97b78192'; +const tBTC = '0x18084fbA666a33d37592fA2633fD49a74DD93a88'; +const rswETH = '0xFAe103DC9cf190eD75350761e95403b7b8aFa6c0'; +const rETH = '0xae78736cd615f374d3085123a210448e74fc6393'; +const osETH = '0xf1c9acdc66974dfb6decb12aa385b9cd01190e38'; +const ETHx = '0xA35b1B31Ce002FBF2058D22F30f95D405200A15b'; +const pufETH = '0xd9a442856c234a39a81a089c06451ebaa4306a72'; +const pumpBTC = '0xf469fbd2abcd6b9de8e169d128226c0fc90a012e'; +const LBTC = '0x8236a87084f8b84306f72007f36f2618a5634494'; + +export default migration('1777625885_update_supply_caps_on_mainnet', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const { + governor, + cometAdmin, + configurator, + } = await deploymentManager.getContracts(); + + const mainnetActions = [ + // 1. Update weETH supply cap on wstETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WSTETH_COMET, weETH, 0], + }, + // 2. Update ezETH supply cap on wstETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WSTETH_COMET, ezETH, 0], + }, + // 3. Update tETH supply cap on wstETH Comet to 44 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WSTETH_COMET, tETH, exp(44, 18)], + }, + // 4. Deploy and upgrade the wstETH Comet implementation to apply the updates + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, WSTETH_COMET], + }, + // 5. Update wOETH supply cap on WETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, wOETH, 0], + }, + // 6. Update tBTC supply cap on WETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, tBTC, 0], + }, + // 7. Update rswETH supply cap on WETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, rswETH, 0], + }, + // 8. Update rETH supply cap on WETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, rETH, 0], + }, + // 9. Update osETH supply cap on WETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, osETH, 0], + }, + // 10. Update ETHx supply cap on WETH Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, ETHx, 0], + }, + // 11. Update weETH supply cap on WETH Comet to 3,860 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, weETH, exp(3860, 18)], + }, + // 12. Update tETH supply cap on WETH Comet to 1,545 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, tETH, exp(1545, 18)], + }, + // 13. Update pufETH supply cap on WETH Comet to 105 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, pufETH, exp(105, 18)], + }, + // 14. Update ezETH supply cap on WETH Comet to 33,163 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WETH_COMET, ezETH, exp(33163, 18)], + }, + // 15. Deploy and upgrade the WETH Comet implementation to apply the updates + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, WETH_COMET], + }, + // 16. Update pumpBTC supply cap on WBTC Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WBTC_COMET, pumpBTC, 0], + }, + // 17. Update LBTC supply cap on WBTC Comet to 0 + { + contract: configurator, + signature: 'updateAssetSupplyCap(address,address,uint128)', + args: [WBTC_COMET, LBTC, 0], + }, + // 18. Deploy and upgrade the WBTC Comet implementation to apply the updates + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, WBTC_COMET], + }, + ]; + + const description = `# Ethereum Supply cap Reduction Across Non-USD Based Comets + +## Proposal summary + +This proposal updates supply caps for a number of assets across the non-usd based Mainnet markets. The supply caps for the affected assets are being updated based on their current utilization and risk parameters. + +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1116) and [forum discussion](https://www.comp.xyz/t/ethereum-supply-cap-reduction-across-comets/7793). + +## Proposal actions + +1 - 4. Updates supply caps for weETH and ezETH to 0 and tETH to 44 on cWstETHv3 market and upgrades the Comet implementation to apply the changes. + +5 - 15. Updates supply caps for wOETH, tBTC, rswETH, rETH, osETH, and ETHx to 0 and weETH to 3,860, tETH to 1,545, pufETH to 105, and ezETH to 33,163 on cWETHv3 market and upgrades the Comet implementation to apply the changes. + +16 - 18. Updates supply caps for pumpBTC and LBTC to 0 on cWBTCv3 market and upgrades the Comet implementation to apply the changes. +`; + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 600_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return false; + }, + + async verify(deploymentManager: DeploymentManager) { + const { configurator } = await deploymentManager.getContracts(); + + // 1 - 4 Compare updated assets on wstETH Comet + const cometWstETH = new Contract( + WSTETH_COMET, + [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))' + ], + await deploymentManager.getSigner() + ); + + const assetInfoForWeETHOnWstETHInComet = await cometWstETH.getAssetInfoByAddress(weETH); + expect(assetInfoForWeETHOnWstETHInComet.supplyCap).to.equal(0); + + const assetInfoForEzETHOnWstETHInComet = await cometWstETH.getAssetInfoByAddress(ezETH); + expect(assetInfoForEzETHOnWstETHInComet.supplyCap).to.equal(0); + + const assetInfoForTETHOnWstETHInComet = await cometWstETH.getAssetInfoByAddress(tETH); + expect(assetInfoForTETHOnWstETHInComet.supplyCap).to.equal(BigNumber.from(44).mul(assetInfoForTETHOnWstETHInComet.scale)); + + const wstETHConfiguration = await configurator.getConfiguration(WSTETH_COMET); + expect(wstETHConfiguration.assetConfigs[assetInfoForWeETHOnWstETHInComet.offset].supplyCap).to.equal(0); + expect(wstETHConfiguration.assetConfigs[assetInfoForEzETHOnWstETHInComet.offset].supplyCap).to.equal(0); + expect(wstETHConfiguration.assetConfigs[assetInfoForTETHOnWstETHInComet.offset].supplyCap).to.equal(BigNumber.from(44).mul(assetInfoForTETHOnWstETHInComet.scale)); + + // 5 - 15 Compare updated assets on WETH Comet + const cometWETH = new Contract( + WETH_COMET, + [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))' + ], + await deploymentManager.getSigner() + ); + + const assetInfoForWOETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(wOETH); + expect(assetInfoForWOETHOnWETHInComet.supplyCap).to.equal(0); + + const assetInfoForTBTCOnWETHInComet = await cometWETH.getAssetInfoByAddress(tBTC); + expect(assetInfoForTBTCOnWETHInComet.supplyCap).to.equal(0); + + const assetInfoForRswETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(rswETH); + expect(assetInfoForRswETHOnWETHInComet.supplyCap).to.equal(0); + + const assetInfoForRETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(rETH); + expect(assetInfoForRETHOnWETHInComet.supplyCap).to.equal(0); + + const assetInfoForOsETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(osETH); + expect(assetInfoForOsETHOnWETHInComet.supplyCap).to.equal(0); + + const assetInfoForETHxOnWETHInComet = await cometWETH.getAssetInfoByAddress(ETHx); + expect(assetInfoForETHxOnWETHInComet.supplyCap).to.equal(0); + + const assetInfoForWeETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(weETH); + expect(assetInfoForWeETHOnWETHInComet.supplyCap).to.equal(BigNumber.from(3860).mul(assetInfoForWeETHOnWETHInComet.scale)); + + const assetInfoForTETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(tETH); + expect(assetInfoForTETHOnWETHInComet.supplyCap).to.equal(BigNumber.from(1545).mul(assetInfoForTETHOnWETHInComet.scale)); + + const assetInfoForPufETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(pufETH); + expect(assetInfoForPufETHOnWETHInComet.supplyCap).to.equal(BigNumber.from(105).mul(assetInfoForPufETHOnWETHInComet.scale)); + + const assetInfoForEzETHOnWETHInComet = await cometWETH.getAssetInfoByAddress(ezETH); + expect(assetInfoForEzETHOnWETHInComet.supplyCap).to.equal(BigNumber.from(33163).mul(assetInfoForEzETHOnWETHInComet.scale)); + + const WETHConfiguration = await configurator.getConfiguration(WETH_COMET); + expect(WETHConfiguration.assetConfigs[assetInfoForWOETHOnWETHInComet.offset].supplyCap).to.equal(0); + expect(WETHConfiguration.assetConfigs[assetInfoForTBTCOnWETHInComet.offset].supplyCap).to.equal(0); + expect(WETHConfiguration.assetConfigs[assetInfoForRswETHOnWETHInComet.offset].supplyCap).to.equal(0); + expect(WETHConfiguration.assetConfigs[assetInfoForRETHOnWETHInComet.offset].supplyCap).to.equal(0); + expect(WETHConfiguration.assetConfigs[assetInfoForOsETHOnWETHInComet.offset].supplyCap).to.equal(0); + expect(WETHConfiguration.assetConfigs[assetInfoForETHxOnWETHInComet.offset].supplyCap).to.equal(0); + expect(WETHConfiguration.assetConfigs[assetInfoForWeETHOnWETHInComet.offset].supplyCap).to.equal(BigNumber.from(3860).mul(assetInfoForWeETHOnWETHInComet.scale)); + expect(WETHConfiguration.assetConfigs[assetInfoForTETHOnWETHInComet.offset].supplyCap).to.equal(BigNumber.from(1545).mul(assetInfoForTETHOnWETHInComet.scale)); + expect(WETHConfiguration.assetConfigs[assetInfoForPufETHOnWETHInComet.offset].supplyCap).to.equal(BigNumber.from(105).mul(assetInfoForPufETHOnWETHInComet.scale)); + expect(WETHConfiguration.assetConfigs[assetInfoForEzETHOnWETHInComet.offset].supplyCap).to.equal(BigNumber.from(33163).mul(assetInfoForEzETHOnWETHInComet.scale)); + + // 16 - 18 Compare updated assets on WBTC Comet + const cometWBTC = new Contract( + WBTC_COMET, + [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))' + ], + await deploymentManager.getSigner() + ); + + const assetInfoForPumpBTCOnWBTCInComet = await cometWBTC.getAssetInfoByAddress(pumpBTC); + expect(assetInfoForPumpBTCOnWBTCInComet.supplyCap).to.equal(0); + + const assetInfoForLBTCOnWBTCInComet = await cometWBTC.getAssetInfoByAddress(LBTC); + expect(assetInfoForLBTCOnWBTCInComet.supplyCap).to.equal(0); + + const WBTCConfiguration = await configurator.getConfiguration(WBTC_COMET); + expect(WBTCConfiguration.assetConfigs[assetInfoForPumpBTCOnWBTCInComet.offset].supplyCap).to.equal(0); + expect(WBTCConfiguration.assetConfigs[assetInfoForLBTCOnWBTCInComet.offset].supplyCap).to.equal(0); + }, +}); diff --git a/deployments/mainnet/wsteth/migrations/1779099097_return_rseth_pricefeeds_on_weth_and_wsteth.ts b/deployments/mainnet/wsteth/migrations/1779099097_return_rseth_pricefeeds_on_weth_and_wsteth.ts new file mode 100644 index 000000000..1b93c666c --- /dev/null +++ b/deployments/mainnet/wsteth/migrations/1779099097_return_rseth_pricefeeds_on_weth_and_wsteth.ts @@ -0,0 +1,130 @@ +import { expect } from 'chai'; +import { Contract } from 'ethers'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { proposal } from '../../../../src/deploy'; + +const MAINNET_WETH_COMET = '0xA17581A9E3356d9A858b789D68B4d866e593aE94'; +const MAINNET_WSTETH_COMET = '0x3D0bb1ccaB520A66e607822fC55BC921738fAFE3'; + +const mainnetWethPriceFeedAddress = '0x5AbcFC8A649Ac15Ff7d41c0Dd0d53aF3bBb7F876'; +const mainnetWstEthPriceFeedAddress = '0x0Af91E13383FD771f21B40b79421B2d59E8214C2'; + +export default migration('1779099097_return_rseth_pricefeeds_on_weth_and_wsteth', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const { + configurator, + cometAdmin, + rsETH, + governor, + } = await deploymentManager.getContracts(); + + const mainnetActions = [ + // 1. Update the price feed for rsETH in the WETH market on Mainnet + { + contract: configurator, + signature: 'updateAssetPriceFeed(address,address,address)', + args: [MAINNET_WETH_COMET, rsETH.address, mainnetWethPriceFeedAddress], + }, + // 2. Update the price feed for rsETH in the wstETH market on Mainnet + { + contract: configurator, + signature: 'updateAssetPriceFeed(address,address,address)', + args: [MAINNET_WSTETH_COMET, rsETH.address, mainnetWstEthPriceFeedAddress], + }, + // 3. Deploy and upgrade WETH Comet to a new version + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, MAINNET_WETH_COMET], + }, + // 4. Deploy and upgrade wstETH Comet to a new version + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, MAINNET_WSTETH_COMET], + }, + ]; + + const description = `# Return rsETH Price Feeds on WETH and wstETH Markets (Mainnet) + +## Summary + +This proposal is a follow-up to the emergency rsETH oracle migration and returns the Mainnet WETH and wstETH Comets to their prior rsETH price feed configuration. + +The earlier migration to a MinMaxConstantPriceFeed was introduced as a temporary risk-control measure after the April 18 Kelp rsETH bridge exploit. With conditions now stabilized, this proposal removes the temporary setup and restores the previous feed configuration. + +Implementation details: [PR #1122](https://github.com/compound-finance/comet/pull/1122). + +## Proposal Actions + +1. Update the rsETH price feed on the Mainnet WETH market. +2. Update the rsETH price feed on the Mainnet wstETH market. +3. Deploy and upgrade the WETH Comet to apply the configuration change. +4. Deploy and upgrade the wstETH Comet to apply the configuration change. +`; + + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 600_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return false; + }, + + async verify(deploymentManager: DeploymentManager) { + const { + rsETH + } = await deploymentManager.getContracts(); + + const cometWETH = new Contract(MAINNET_WETH_COMET, [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))', + ], await deploymentManager.getSigner()); + + const wethCometAssetInfo = await cometWETH.getAssetInfoByAddress(rsETH.address); + expect(wethCometAssetInfo.priceFeed).to.equal(mainnetWethPriceFeedAddress); + + const priceFeedWeth = new Contract( + wethCometAssetInfo.priceFeed, + [ + 'function latestRoundData() external view returns(uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)', + 'function decimals() external view returns (uint8)', + ], + await deploymentManager.getSigner()); + expect(await priceFeedWeth.decimals()).to.equal(8); + expect((await priceFeedWeth.latestRoundData()).answer).to.not.equal(0); + + const wstEthComet = new Contract(MAINNET_WSTETH_COMET, [ + 'function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))', + ], await deploymentManager.getSigner()); + + const wstEthCometAssetInfo = await wstEthComet.getAssetInfoByAddress(rsETH.address); + expect(wstEthCometAssetInfo.priceFeed).to.equal(mainnetWstEthPriceFeedAddress); + + const priceFeedWstEth = new Contract( + wstEthCometAssetInfo.priceFeed, + [ + 'function latestRoundData() external view returns(uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)', + 'function decimals() external view returns (uint8)', + ], + await deploymentManager.getSigner()); + expect(await priceFeedWstEth.decimals()).to.equal(8); + expect((await priceFeedWstEth.latestRoundData()).answer).to.not.equal(0); + }, +}); diff --git a/deployments/mantle/usde/migrations/1735299778_update_comet_to_support_more_collaterals.ts b/deployments/mantle/usde/migrations/1735299778_update_comet_to_support_more_collaterals.ts index 5a8b9ba0c..121e2bf7d 100644 --- a/deployments/mantle/usde/migrations/1735299778_update_comet_to_support_more_collaterals.ts +++ b/deployments/mantle/usde/migrations/1735299778_update_comet_to_support_more_collaterals.ts @@ -13,13 +13,15 @@ export default migration('1735299778_update_comet_to_support_more_collaterals', const _assetListFactory = await deploymentManager.deploy( 'assetListFactory', 'AssetListFactory.sol', - [] + [], + true ); const cometFactoryWithExtendedAssetList = await deploymentManager.deploy( 'cometFactoryWithExtendedAssetList', 'CometFactoryWithExtendedAssetList.sol', - [] + [], + true ); const { comet @@ -102,7 +104,7 @@ export default migration('1735299778_update_comet_to_support_more_collaterals', ); const mainnetActions = [ - // 1. Set Comet configuration + deployAndUpgradeTo new Comet and set reward config on Mantle. + // 1. Sets new factory and extension delegate, deploys new Comet implementation and upgrades to it { contract: mantleL1CrossDomainMessenger, signature: 'sendMessage(address,bytes,uint32)', @@ -110,7 +112,16 @@ export default migration('1735299778_update_comet_to_support_more_collaterals', }, ]; - const description = '# Update USDe Comet on Mantle to support more collaterals\n\n## Proposal summary\n\nCompound Growth Program [AlphaGrowth] proposes to update Mantle cUSDeV3 Comet to a new version, which supports up to 24 collaterals. This proposal takes the governance steps recommended and necessary to update Compound III USDe markets on Mantle. Simulations have confirmed the market’s readiness, as much as possible, using the [Comet scenario suite](https://github.com/compound-finance/comet/tree/main/scenario).\n\nDetailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/904) and [forum discussion](https://www.comp.xyz/t/increase-amount-of-collaterals-in-comet/5465).\n\n\n## Proposal Actions\n\nThe first action sets the factory to the newly deployed factory, extension delegate to the newly deployed contract and deploys and upgrades Comet to a new version.'; + const description = `# Update USDe Comet on Mantle to support more collaterals + +## Proposal summary + +WOOF! proposes to update Mantle cUSDev3 Comet to a new version, which supports up to 24 collaterals. This proposal takes the governance steps recommended and necessary to update Compound III USDe markets on Mantle. Simulations have confirmed the market’s readiness, as much as possible, using the [Comet scenario suite](https://github.com/compound-finance/comet/tree/main/scenario). +Detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1070) and [forum discussion](https://www.comp.xyz/t/increase-amount-of-collaterals-in-comet/5465). + +## Proposal Actions + +The first action sets the factory to the newly deployed factory, extension delegate to the newly deployed contract and deploys and upgrades Comet to a new version.`; const txn = await deploymentManager.retry(async () => trace( await governor.propose(...(await proposal(mainnetActions, description))) @@ -118,13 +129,13 @@ export default migration('1735299778_update_comet_to_support_more_collaterals', ); const event = txn.events.find( - (event) => event.event === 'ProposalCreated' + (event: { event: string }) => event.event === 'ProposalCreated' ); const [proposalId] = event.args; trace(`Created proposal ${proposalId}.`); }, - async enacted(): Promise { + async enacted(deploymentManager: DeploymentManager): Promise { return true; }, diff --git a/deployments/polygon/usdc/migrations/1735299827_update_comet_to_support_more_collaterals.ts b/deployments/polygon/usdc/migrations/1735299827_update_comet_to_support_more_collaterals.ts index 352376e70..d853f6df1 100644 --- a/deployments/polygon/usdc/migrations/1735299827_update_comet_to_support_more_collaterals.ts +++ b/deployments/polygon/usdc/migrations/1735299827_update_comet_to_support_more_collaterals.ts @@ -17,13 +17,15 @@ export default migration('1735299827_update_comet_to_support_more_collaterals', const _assetListFactory = await deploymentManager.deploy( 'assetListFactory', 'AssetListFactory.sol', - [] + [], + true ); const cometFactoryWithExtendedAssetList = await deploymentManager.deploy( 'cometFactoryWithExtendedAssetList', 'CometFactoryWithExtendedAssetList.sol', - [] + [], + true ); const { comet @@ -77,6 +79,7 @@ export default migration('1735299827_update_comet_to_support_more_collaterals', ], true ); + return { cometFactoryWithExtendedAssetList: cometFactoryWithExtendedAssetList.address, newCometExtUSDC: _newCometExtUSDC.address, @@ -89,7 +92,6 @@ export default migration('1735299827_update_comet_to_support_more_collaterals', newCometExtUSDC, newCometExtUSDT }) { - const trace = deploymentManager.tracer(); const { comet, @@ -113,7 +115,6 @@ export default migration('1735299827_update_comet_to_support_more_collaterals', [configurator.address, comet.address] ); - const setFactoryCalldataUSDT = await calldata( configurator.populateTransaction.setFactory(USDT_COMET, cometFactoryWithExtendedAssetList) ); @@ -160,21 +161,33 @@ export default migration('1735299827_update_comet_to_support_more_collaterals', }, ]; - const description = '# Update USDC and USDT Comets on Polygon to support more collaterals\n\n## Proposal summary\n\nCompound Growth Program [AlphaGrowth] proposes to update 2 Comets to a new version, which supports up to 24 collaterals. This proposal takes the governance steps recommended and necessary to update Compound III USDT and USDC markets on Polygon. Simulations have confirmed the market’s readiness, as much as possible, using the [Comet scenario suite](https://github.com/compound-finance/comet/tree/main/scenario).\n\nDetailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/904) and [forum discussion](https://www.comp.xyz/t/increase-amount-of-collaterals-in-comet/5465).\n\n\n## Proposal Actions\n\nThe first action sets the factory to the newly deployed factory, extension delegate to the newly deployed contract and deploys and upgrades Comet to a new version for all 2 comets: cUSDTv3 and cUSDCv3.'; + const description = `# Update USDC and USDT Comets on Polygon to support more collaterals + +## Proposal summary + +WOOF! proposes to update both Polygon Comets to a new version, which supports up to 24 collaterals. This proposal takes the governance steps recommended and necessary to update Compound III USDT and USDC markets on Polygon. Simulations have confirmed the market’s readiness, as much as possible, using the [Comet scenario suite](https://github.com/compound-finance/comet/tree/main/scenario). + +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1071) and [forum discussion](https://www.comp.xyz/t/increase-amount-of-collaterals-in-comet/5465). + +## Proposal Actions + +The first action sets the factory to the newly deployed factory, extension delegate to the newly deployed contract and deploys and upgrades Comet to a new version for all 2 comets: cUSDTv3 and cUSDCv3.`; + const txn = await deploymentManager.retry(async () => trace( await governor.propose(...(await proposal(mainnetActions, description))) - ) + ), 0, 300_000 ); + const event = txn.events.find( - (event) => event.event === 'ProposalCreated' + (event: { event: string }) => event.event === 'ProposalCreated' ); const [proposalId] = event.args; trace(`Created proposal ${proposalId}.`); }, - async enacted(): Promise { + async enacted(deploymentManager: DeploymentManager): Promise { return true; }, @@ -193,6 +206,16 @@ export default migration('1735299827_update_comet_to_support_more_collaterals', expect(assetListAddress).to.not.be.equal(ethers.constants.AddressZero); expect(await comet.extensionDelegate()).to.be.equal(newCometExtAddressUSDC); + + const extensionDelegateUSDC = new Contract( + await comet.extensionDelegate(), + [ + 'function name() external view returns (string)', + 'function symbol() external view returns (string)', + ], + await deploymentManager.getSigner() + ); + expect(await extensionDelegateUSDC.name()).to.be.equal('Compound USDC'); const cometNewUSDT = new Contract( USDT_COMET, @@ -207,5 +230,14 @@ export default migration('1735299827_update_comet_to_support_more_collaterals', expect(assetListAddressUSDT).to.not.be.equal(ethers.constants.AddressZero); expect(await cometNewUSDT.extensionDelegate()).to.be.equal(newCometExtAddressUSDT); + const extensionDelegateUSDT = new Contract( + await cometNewUSDT.extensionDelegate(), + [ + 'function name() external view returns (string)', + 'function symbol() external view returns (string)', + ], + await deploymentManager.getSigner() + ); + expect(await extensionDelegateUSDT.name()).to.be.equal('Compound USDT'); }, }); diff --git a/deployments/polygon/usdc/migrations/1772805892_deprecate_stmatic.ts b/deployments/polygon/usdc/migrations/1772805892_deprecate_stmatic.ts new file mode 100644 index 000000000..d2e3c37e8 --- /dev/null +++ b/deployments/polygon/usdc/migrations/1772805892_deprecate_stmatic.ts @@ -0,0 +1,134 @@ +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { calldata, proposal } from '../../../../src/deploy'; +import { utils } from 'ethers'; + + +let newStMaticPriceFeed: string; + +export default migration('1772805892_deprecate_stmatic', { + async prepare(deploymentManager: DeploymentManager) { + const _stMaticConstantPriceFeed = await deploymentManager.deploy( + 'stMatic:priceFeed', + 'pricefeeds/ConstantPriceFeed.sol', + [ + 8, // decimals + 1 // constantPrice + ], + true + ); + + return { + stMaticConstantPriceFeedAddress: _stMaticConstantPriceFeed.address + }; + }, + + async enact(deploymentManager: DeploymentManager, govDeploymentManager: DeploymentManager, { + stMaticConstantPriceFeedAddress + }) { + newStMaticPriceFeed = stMaticConstantPriceFeedAddress; + + const trace = deploymentManager.tracer(); + + const { + configurator, + comet, + bridgeReceiver, + cometAdmin, + stMATIC + } = await deploymentManager.getContracts(); + + const { + governor, + fxRoot + } = await govDeploymentManager.getContracts(); + + const updateStMaticPriceFeedCalldata = await calldata( + configurator.populateTransaction.updateAssetPriceFeed( + comet.address, + stMATIC.address, + newStMaticPriceFeed + ) + ); + + const updateStMaticSupplyCapCalldata = await calldata( + configurator.populateTransaction.updateAssetSupplyCap( + comet.address, + stMATIC.address, + 0 + ) + ); + + const deployAndUpgradeToCalldata = await calldata( + cometAdmin.populateTransaction.deployAndUpgradeTo( + configurator.address, + comet.address + ) + ); + + const l2ProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [configurator.address, configurator.address, cometAdmin.address], + [0, 0, 0], + ['updateAssetPriceFeed(address,address,address)', 'updateAssetSupplyCap(address,address,uint128)', 'deployAndUpgradeTo(address,address)'], + [updateStMaticPriceFeedCalldata, updateStMaticSupplyCapCalldata, deployAndUpgradeToCalldata], + ] + ); + + const mainnetActions = [ + // 1. Set Comet configuration and deployAndUpgradeTo new Comet on Polygon. + { + contract: fxRoot, + signature: 'sendMessageToChild(address,bytes)', + args: [bridgeReceiver.address, l2ProposalData], + }, + ]; + + const description = `# Deprecate stMATIC in cUSDCv3 on Polygon + +## Proposal summary + +WOOF! propose to deprecate stMATIC as collateral in cUSDCv3 on Polygon by updating its price feed to a constant price feed with a price of 1 wei and set its supply cap to 0. + +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1094) and [forum discussion](https://www.comp.xyz/t/gauntlet-depreciating-stmatic-on-polygon-usdt-and-usdc-e-comets/7083). + +## Proposal actions + +The first action updates stMATIC price feed to the constant price feed with a price of 1 wei and sets its supply cap to 0. This sends the encoded 'updateAssetPriceFeed', 'updateAssetSupplyCap' and 'deployAndUpgradeTo' calls across the bridge to the governance receiver on Polygon. +`; + + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 300_000 + ); + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(deploymentManager: DeploymentManager): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + const { comet, configurator, stMATIC } = await deploymentManager.getContracts(); + + const stMaticIndexInComet = await configurator.getAssetIndex(comet.address, stMATIC.address); + + // Check if the price feeds are set correctly. + const stMaticInCometInfo = await comet.getAssetInfoByAddress(stMATIC.address); + const stMaticInConfiguratorInfo = (await configurator.getConfiguration(comet.address)).assetConfigs[stMaticIndexInComet]; + + expect(stMaticInCometInfo.priceFeed).to.eq(newStMaticPriceFeed); + expect(stMaticInConfiguratorInfo.priceFeed).to.eq(newStMaticPriceFeed); + expect(await comet.getPrice(newStMaticPriceFeed)).to.equal(1); + + expect(stMaticInCometInfo.supplyCap).to.eq(0); + expect(stMaticInConfiguratorInfo.supplyCap).to.eq(0); + }, +}); diff --git a/deployments/polygon/usdt/migrations/1735299832_update_comet_to_support_more_collaterals.ts b/deployments/polygon/usdt/migrations/1735299832_update_comet_to_support_more_collaterals.ts index d7a8b7c8e..19c66fdb9 100644 --- a/deployments/polygon/usdt/migrations/1735299832_update_comet_to_support_more_collaterals.ts +++ b/deployments/polygon/usdt/migrations/1735299832_update_comet_to_support_more_collaterals.ts @@ -13,13 +13,15 @@ export default migration('1735299832_update_comet_to_support_more_collaterals', const _assetListFactory = await deploymentManager.deploy( 'assetListFactory', 'AssetListFactory.sol', - [] + [], + true ); const cometFactoryWithExtendedAssetList = await deploymentManager.deploy( 'cometFactoryWithExtendedAssetList', 'CometFactoryWithExtendedAssetList.sol', - [] + [], + true ); const { comet @@ -110,11 +112,11 @@ export default migration('1735299832_update_comet_to_support_more_collaterals', const txn = await deploymentManager.retry(async () => trace( await governor.propose(...(await proposal(mainnetActions, description))) - ) + ), 0, 300_000 ); const event = txn.events.find( - (event) => event.event === 'ProposalCreated' + (event: { event: string }) => event.event === 'ProposalCreated' ); const [proposalId] = event.args; trace(`Created proposal ${proposalId}.`); diff --git a/deployments/polygon/usdt/migrations/1772817323_deprecate_stmatic.ts b/deployments/polygon/usdt/migrations/1772817323_deprecate_stmatic.ts new file mode 100644 index 000000000..715046e49 --- /dev/null +++ b/deployments/polygon/usdt/migrations/1772817323_deprecate_stmatic.ts @@ -0,0 +1,118 @@ +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { calldata, proposal } from '../../../../src/deploy'; +import { utils } from 'ethers'; + +const CONSTANT_PRICE_FEED = '0x5D173813B4505701e79E654b36A95E6c1FAD4448'; + +export default migration('1772817323_deprecate_stmatic', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager, govDeploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const { + configurator, + comet, + bridgeReceiver, + cometAdmin, + stMATIC + } = await deploymentManager.getContracts(); + + const { + governor, + fxRoot + } = await govDeploymentManager.getContracts(); + + const updateStMaticPriceFeedCalldata = await calldata( + configurator.populateTransaction.updateAssetPriceFeed( + comet.address, + stMATIC.address, + CONSTANT_PRICE_FEED + ) + ); + + const updateStMaticSupplyCapCalldata = await calldata( + configurator.populateTransaction.updateAssetSupplyCap( + comet.address, + stMATIC.address, + 0 + ) + ); + + const deployAndUpgradeToCalldata = await calldata( + cometAdmin.populateTransaction.deployAndUpgradeTo( + configurator.address, + comet.address + ) + ); + + const l2ProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [configurator.address, configurator.address, cometAdmin.address], + [0, 0, 0], + ['updateAssetPriceFeed(address,address,address)', 'updateAssetSupplyCap(address,address,uint128)', 'deployAndUpgradeTo(address,address)'], + [updateStMaticPriceFeedCalldata, updateStMaticSupplyCapCalldata, deployAndUpgradeToCalldata], + ] + ); + + const mainnetActions = [ + // 1. Set Comet configuration and deployAndUpgradeTo new Comet on Polygon. + { + contract: fxRoot, + signature: 'sendMessageToChild(address,bytes)', + args: [bridgeReceiver.address, l2ProposalData], + }, + ]; + + const description = `# Deprecate stMATIC in cUSDTv3 on Polygon + +## Proposal summary + +WOOF! propose to deprecate stMATIC as collateral in cUSDTv3 on Polygon by updating its price feed to a constant price feed with a price of 1 wei and set its supply cap to 0. + +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1095) and [forum discussion](https://www.comp.xyz/t/gauntlet-depreciating-stmatic-on-polygon-usdt-and-usdc-e-comets/7083). + +## Proposal actions + +The first action updates stMATIC price feed to the constant price feed with a price of 1 wei and sets its supply cap to 0. This sends the encoded 'updateAssetPriceFeed', 'updateAssetSupplyCap' and 'deployAndUpgradeTo' calls across the bridge to the governance receiver on Polygon. +`; + + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 300_000 + ); + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(deploymentManager: DeploymentManager): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + const { comet, configurator, stMATIC } = await deploymentManager.getContracts(); + + const stMaticIndexInComet = await configurator.getAssetIndex(comet.address, stMATIC.address); + + // Check if the price feeds are set correctly. + const stMaticInCometInfo = await comet.getAssetInfoByAddress(stMATIC.address); + const stMaticInConfiguratorInfo = (await configurator.getConfiguration(comet.address)).assetConfigs[stMaticIndexInComet]; + + expect(stMaticInCometInfo.priceFeed).to.eq(CONSTANT_PRICE_FEED); + expect(stMaticInConfiguratorInfo.priceFeed).to.eq(CONSTANT_PRICE_FEED); + expect(await comet.getPrice(CONSTANT_PRICE_FEED)).to.equal(1); + + expect(stMaticInCometInfo.supplyCap).to.eq(0); + expect(stMaticInConfiguratorInfo.supplyCap).to.eq(0); + }, +}); diff --git a/deployments/ronin/weth/migrations/1767882783_depreciate_comet.ts b/deployments/ronin/weth/migrations/1767882783_depreciate_comet.ts new file mode 100644 index 000000000..282cd96d4 --- /dev/null +++ b/deployments/ronin/weth/migrations/1767882783_depreciate_comet.ts @@ -0,0 +1,519 @@ +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { calldata, proposal, exp } from '../../../../src/deploy'; +import { utils } from 'ethers'; + +const destinationChainSelector = '6916147374840168594'; + +const USDC_TO_USD_API3_PRICE_FEED_ADDRESS = '0xf061d556F5136263c4d66d9fFCADE8Ab43a3a704'; +const RON_TO_USD_API3_PRICE_FEED_ADDRESS = '0xA708247a64Fad46874A57BA274451a8a1A1daa0c'; +const ETH_TO_USD_API3_PRICE_FEED_ADDRESS = '0xbBF6e0D078c7F5750d0732cD8f3EACe9A87b2b58'; + +const GHO_STABLE_TOKEN = '0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f'; + +let newPriceFeedUSDCAddress: string; +let newPriceFeedWRONAddress: string; +let newPriceFeedAXSAddress: string; + +let oldUSDCPriceFeed: string; +let oldWRONPriceFeed: string; +let oldAXSPriceFeed: string; + +export default migration('1767882783_depreciate_comet', { + async prepare(deploymentManager: DeploymentManager) { + const _usdcPriceFeed = await deploymentManager.deploy( + 'USDC:priceFeed', + 'pricefeeds/ReverseMultiplicativePriceFeed.sol', + [ + USDC_TO_USD_API3_PRICE_FEED_ADDRESS, // USDC / USD price feed + ETH_TO_USD_API3_PRICE_FEED_ADDRESS, // USD / ETH price feed + 8, // decimals + 'USDC / ETH Price Feed', // description + ], + true + ); + + const _wronPriceFeed = await deploymentManager.deploy( + 'WRON:priceFeed', + 'pricefeeds/ReverseMultiplicativePriceFeed.sol', + [ + RON_TO_USD_API3_PRICE_FEED_ADDRESS, // WRON / USD price feed + ETH_TO_USD_API3_PRICE_FEED_ADDRESS, // USD / ETH price feed + 8, // decimals + 'RON / ETH Price Feed', // description + ], + true + ); + + const { + 'WETH:priceFeed': wethPriceFeed + } = await deploymentManager.getContracts(); + + const _axsPriceFeed = await deploymentManager.deploy( + 'AXS:priceFeed', + 'pricefeeds/ReverseMultiplicativePriceFeed.sol', + [ + wethPriceFeed.address, // AXS / USD price feed (its a constant $1 price feed) + ETH_TO_USD_API3_PRICE_FEED_ADDRESS, // USD / ETH price feed + 8, // decimals + 'AXS / ETH Price Feed', // description + ], + true + ); + + return { + USDCPriceFeedAddress: _usdcPriceFeed.address, + WRONPriceFeedAddress: _wronPriceFeed.address, + AXSPriceFeedAddress: _axsPriceFeed.address, + }; + }, + + enact: async ( + deploymentManager: DeploymentManager, + govDeploymentManager: DeploymentManager, + { + USDCPriceFeedAddress, + WRONPriceFeedAddress, + AXSPriceFeedAddress + } + ) => { + const trace = deploymentManager.tracer(); + newPriceFeedUSDCAddress = USDCPriceFeedAddress; + newPriceFeedWRONAddress = WRONPriceFeedAddress; + newPriceFeedAXSAddress = AXSPriceFeedAddress; + + const { + bridgeReceiver, + comet, + cometAdmin, + configurator, + USDC, + AXS, + WRON, + } = await deploymentManager.getContracts(); + + const { + governor, + l1CCIPRouter + } = await govDeploymentManager.getContracts(); + + const usdcAssetConfig = { + asset: USDC.address, + priceFeed: newPriceFeedUSDCAddress, + decimals: await USDC.decimals(), + borrowCollateralFactor: exp(0.60, 18), + liquidateCollateralFactor: exp(0.90, 18), + liquidationFactor: exp(0.85, 18), + supplyCap: 0, + }; + + const wronAssetConfig = { + asset: WRON.address, + priceFeed: newPriceFeedWRONAddress, + decimals: await WRON.decimals(), + borrowCollateralFactor: exp(0.50, 18), + liquidateCollateralFactor: exp(0.80, 18), + liquidationFactor: exp(0.8, 18), + supplyCap: 0, + }; + + const axsAssetConfig = { + asset: AXS.address, + priceFeed: newPriceFeedAXSAddress, + decimals: await AXS.decimals(), + borrowCollateralFactor: exp(0.50, 18), + liquidateCollateralFactor: exp(0.75, 18), + liquidationFactor: exp(0.75, 18), + supplyCap: 0, + }; + + const updateUSDCAssetCalldata = await calldata( + configurator.populateTransaction.updateAsset( + comet.address, + usdcAssetConfig + ) + ); + + const updateWRONAssetCalldata = await calldata( + configurator.populateTransaction.updateAsset( + comet.address, + wronAssetConfig + ) + ); + + const updateAXSAssetCalldata = await calldata( + configurator.populateTransaction.updateAsset( + comet.address, + axsAssetConfig + ) + ); + + const setBorrowPerYearInterestRateBaseCalldata = await calldata( + configurator.populateTransaction.setBorrowPerYearInterestRateBase( + comet.address, + exp(0.025, 18) // 2.5% supply interest rate + ) + ); + + const setBorrowPerYearInterestRateSlopeLowCalldata = await calldata( + configurator.populateTransaction.setBorrowPerYearInterestRateSlopeLow( + comet.address, + exp(0.017647, 18) // 1.7647% borrow interest rate slope low + ) + ); + + const setBorrowKinkCalldata = await calldata( + configurator.populateTransaction.setBorrowKink( + comet.address, + exp(0.85, 18) // 85% borrow kink + ) + ); + + const setBorrowPerYearInterestRateSlopeHighCalldata = await calldata( + configurator.populateTransaction.setBorrowPerYearInterestRateSlopeHigh( + comet.address, + exp(0.732667, 18) // 73.2667% borrow interest rate slope high + ) + ); + + const setSupplyPerYearInterestRateBaseCalldata = await calldata( + configurator.populateTransaction.setSupplyPerYearInterestRateBase( + comet.address, + 0 // 0% supply interest rate + ) + ); + + const setSupplyPerYearInterestRateSlopeLowCalldata = await calldata( + configurator.populateTransaction.setSupplyPerYearInterestRateSlopeLow( + comet.address, + exp(0.02, 18) // 2% supply interest rate slope low + ) + ); + + const setSupplyKinkCalldata = await calldata( + configurator.populateTransaction.setSupplyKink( + comet.address, + exp(0.85, 18) // 85% supply kink + ) + ); + + const setSupplyPerYearInterestRateSlopeHighCalldata = await calldata( + configurator.populateTransaction.setSupplyPerYearInterestRateSlopeHigh( + comet.address, + exp(0.868012, 18) // 86.8012% supply interest rate slope high + ) + ); + + const deployAndUpgradeToCalldata = await calldata( + cometAdmin.populateTransaction.deployAndUpgradeTo( + configurator.address, + comet.address + ) + ); + + const l2ProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + configurator.address, + configurator.address, + configurator.address, + configurator.address, + configurator.address, + configurator.address, + configurator.address, + configurator.address, + configurator.address, + configurator.address, + configurator.address, + cometAdmin.address + ], + [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ], + [ + 'updateAsset(address,(address,address,uint8,uint64,uint64,uint64,uint128))', + 'updateAsset(address,(address,address,uint8,uint64,uint64,uint64,uint128))', + 'updateAsset(address,(address,address,uint8,uint64,uint64,uint64,uint128))', + 'setBorrowPerYearInterestRateBase(address,uint64)', + 'setBorrowPerYearInterestRateSlopeLow(address,uint64)', + 'setBorrowKink(address,uint64)', + 'setBorrowPerYearInterestRateSlopeHigh(address,uint64)', + 'setSupplyPerYearInterestRateBase(address,uint64)', + 'setSupplyPerYearInterestRateSlopeLow(address,uint64)', + 'setSupplyKink(address,uint64)', + 'setSupplyPerYearInterestRateSlopeHigh(address,uint64)', + 'deployAndUpgradeTo(address,address)' + ], + [ + updateUSDCAssetCalldata, + updateWRONAssetCalldata, + updateAXSAssetCalldata, + setBorrowPerYearInterestRateBaseCalldata, + setBorrowPerYearInterestRateSlopeLowCalldata, + setBorrowKinkCalldata, + setBorrowPerYearInterestRateSlopeHighCalldata, + setSupplyPerYearInterestRateBaseCalldata, + setSupplyPerYearInterestRateSlopeLowCalldata, + setSupplyKinkCalldata, + setSupplyPerYearInterestRateSlopeHighCalldata, + deployAndUpgradeToCalldata + ], + ] + ); + + [,, oldUSDCPriceFeed] = await comet.getAssetInfoByAddress(USDC.address); + [,, oldWRONPriceFeed] = await comet.getAssetInfoByAddress(WRON.address); + [,, oldAXSPriceFeed] = await comet.getAssetInfoByAddress(AXS.address); + + const fee = await l1CCIPRouter.getFee(destinationChainSelector, [ + utils.defaultAbiCoder.encode(['address'], [bridgeReceiver.address]), + l2ProposalData, + [], + GHO_STABLE_TOKEN, + '0x' + ]); + + const mainnetActions = [ + // 1. Approve GHO stable token transfer to pay for the proposal execution fee on Ronin. + { + target: GHO_STABLE_TOKEN, + signature: 'approve(address,uint256)', + calldata: utils.defaultAbiCoder.encode(['address', 'uint256'], [l1CCIPRouter.address, fee.mul(2)]) // approve 20% more than the estimated fee to account for potential fluctuations in fee estimation + }, + // 2. Set Comet configuration and deployAndUpgradeTo WETH Comet on Ronin. + { + contract: l1CCIPRouter, + signature: 'ccipSend(uint64,(bytes,bytes,(address,uint256)[],address,bytes))', + args: + [ + destinationChainSelector, + [ + utils.defaultAbiCoder.encode(['address'], [bridgeReceiver.address]), + l2ProposalData, + [], + GHO_STABLE_TOKEN, + '0x' + ] + ], + }, + ]; + + const description = `# Depreciate cWETHv3 on Ronin + +## Proposal summary + +This proposal updates price feeds to API3, since Chainlink soon will no longer support Ronin and updates interest rate curve parameters for WETH market on Ronin. + +It is done to prevent new suppliers from entering the market, reduces capital efficiency, making the market less appealing without causing users to become liquidatable and raises liquidation penalty to further disincentivizes usage by increasing the cost of liquidation, while reducing risk to the comet. + +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1083) and [forum discussion](https://www.comp.xyz/t/gauntlet-depreciating-ronin-weth-and-wron-comets/7308). + +## Proposal actions + +The first proposal action approves the L1CCIPRouter to transfer GHO stable token from the timelock to pay for the proposal execution fee on Ronin. + +The second proposal action sends the following encoded calls to the governance receiver on Ronin: +- Update USDC, AXS, and WRON price feeds to API3 oracle +- Set supply caps to 0 for all collateral assets +- Reduce collateral factors +- Increase liquidation penalties +- Update interest rate curve parameters: + - \`setBorrowPerYearInterestRateBase\` + - \`setBorrowPerYearInterestRateSlopeLow\` + - \`setBorrowKink\` + - \`setBorrowPerYearInterestRateSlopeHigh\` + - \`setSupplyPerYearInterestRateBase\` + - \`setSupplyPerYearInterestRateSlopeLow\` + - \`setSupplyKink\` + - \`setSupplyPerYearInterestRateSlopeHigh\` +- Deploy and upgrade to new configuration via \`deployAndUpgradeTo\`. +`; + const txn = await govDeploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 300_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(deploymentManager: DeploymentManager): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + const { + comet, + configurator, + USDC, + WRON, + AXS, + } = await deploymentManager.getContracts(); + + const usdcAssetConfig = { + asset: USDC.address, + priceFeed: newPriceFeedUSDCAddress, + decimals: 6, + borrowCollateralFactor: exp(0.60, 18), + liquidateCollateralFactor: exp(0.90, 18), + liquidationFactor: exp(0.85, 18), + supplyCap: 0, + }; + + const wronAssetConfig = { + asset: WRON.address, + priceFeed: newPriceFeedWRONAddress, + decimals: 18, + borrowCollateralFactor: exp(0.50, 18), + liquidateCollateralFactor: exp(0.80, 18), + liquidationFactor: exp(0.8, 18), + supplyCap: 0, + }; + + const axsAssetConfig = { + asset: AXS.address, + priceFeed: newPriceFeedAXSAddress, + decimals: 18, + borrowCollateralFactor: exp(0.50, 18), + liquidateCollateralFactor: exp(0.75, 18), + liquidationFactor: exp(0.75, 18), + supplyCap: 0, + }; + // 1. USDC + const USDCIndexInComet = await configurator.getAssetIndex( + comet.address, + USDC.address + ); + const USDCInCometInfo = await comet.getAssetInfoByAddress(USDC.address); + const USDCInConfiguratorInfoComet = ( + await configurator.getConfiguration(comet.address) + ).assetConfigs[USDCIndexInComet]; + + expect(usdcAssetConfig.asset).to.be.equal(USDCInCometInfo.asset); + expect(usdcAssetConfig.priceFeed).to.eq(USDCInCometInfo.priceFeed); + expect(exp(1, usdcAssetConfig.decimals)).to.be.equal(USDCInCometInfo.scale); + expect(usdcAssetConfig.borrowCollateralFactor).to.be.equal(USDCInCometInfo.borrowCollateralFactor); + expect(usdcAssetConfig.liquidateCollateralFactor).to.be.equal(USDCInCometInfo.liquidateCollateralFactor); + expect(usdcAssetConfig.liquidationFactor).to.be.equal(USDCInCometInfo.liquidationFactor); + expect(usdcAssetConfig.supplyCap).to.be.equal(USDCInCometInfo.supplyCap); + + expect(usdcAssetConfig.asset).to.be.equal(USDCInConfiguratorInfoComet.asset); + expect(usdcAssetConfig.priceFeed).to.eq(USDCInConfiguratorInfoComet.priceFeed); + expect(usdcAssetConfig.decimals).to.be.equal(USDCInConfiguratorInfoComet.decimals); + expect(usdcAssetConfig.borrowCollateralFactor).to.be.equal(USDCInConfiguratorInfoComet.borrowCollateralFactor); + expect(usdcAssetConfig.liquidateCollateralFactor).to.be.equal(USDCInConfiguratorInfoComet.liquidateCollateralFactor); + expect(usdcAssetConfig.liquidationFactor).to.be.equal(USDCInConfiguratorInfoComet.liquidationFactor); + expect(usdcAssetConfig.supplyCap).to.be.equal(USDCInConfiguratorInfoComet.supplyCap); + + expect(await comet.getPrice(newPriceFeedUSDCAddress)).to.be.closeTo(await comet.getPrice(oldUSDCPriceFeed), 1e6); + + // 2. WRON + const WRONIndexInComet = await configurator.getAssetIndex( + comet.address, + WRON.address + ); + const WRONInCometInfo = await comet.getAssetInfoByAddress(WRON.address); + const WRONInConfiguratorInfoWRONComet = ( + await configurator.getConfiguration(comet.address) + ).assetConfigs[WRONIndexInComet]; + + expect(wronAssetConfig.asset).to.be.equal(WRONInCometInfo.asset); + expect(wronAssetConfig.priceFeed).to.eq(WRONInCometInfo.priceFeed); + expect(exp(1, wronAssetConfig.decimals)).to.be.equal(WRONInCometInfo.scale); + expect(wronAssetConfig.borrowCollateralFactor).to.be.equal(WRONInCometInfo.borrowCollateralFactor); + expect(wronAssetConfig.liquidateCollateralFactor).to.be.equal(WRONInCometInfo.liquidateCollateralFactor); + expect(wronAssetConfig.liquidationFactor).to.be.equal(WRONInCometInfo.liquidationFactor); + expect(wronAssetConfig.supplyCap).to.be.equal(WRONInCometInfo.supplyCap); + + expect(wronAssetConfig.asset).to.be.equal(WRONInConfiguratorInfoWRONComet.asset); + expect(wronAssetConfig.priceFeed).to.eq(WRONInConfiguratorInfoWRONComet.priceFeed); + expect(wronAssetConfig.decimals).to.be.equal(WRONInConfiguratorInfoWRONComet.decimals); + expect(wronAssetConfig.borrowCollateralFactor).to.be.equal(WRONInConfiguratorInfoWRONComet.borrowCollateralFactor); + expect(wronAssetConfig.liquidateCollateralFactor).to.be.equal(WRONInConfiguratorInfoWRONComet.liquidateCollateralFactor); + expect(wronAssetConfig.liquidationFactor).to.be.equal(WRONInConfiguratorInfoWRONComet.liquidationFactor); + expect(wronAssetConfig.supplyCap).to.be.equal(WRONInConfiguratorInfoWRONComet.supplyCap); + + expect(await comet.getPrice(newPriceFeedWRONAddress)).to.be.closeTo(await comet.getPrice(oldWRONPriceFeed), 1e6); + + // 3. AXS + const AXSIndexInComet = await configurator.getAssetIndex( + comet.address, + AXS.address + ); + const AXSInCometInfo = await comet.getAssetInfoByAddress(AXS.address); + const AXSInConfiguratorInfoAXSComet = ( + await configurator.getConfiguration(comet.address) + ).assetConfigs[AXSIndexInComet]; + + expect(axsAssetConfig.asset).to.be.equal(AXSInCometInfo.asset); + expect(axsAssetConfig.priceFeed).to.eq(AXSInCometInfo.priceFeed); + expect(exp(1, axsAssetConfig.decimals)).to.be.equal(AXSInCometInfo.scale); + expect(axsAssetConfig.borrowCollateralFactor).to.be.equal(AXSInCometInfo.borrowCollateralFactor); + expect(axsAssetConfig.liquidateCollateralFactor).to.be.equal(AXSInCometInfo.liquidateCollateralFactor); + expect(axsAssetConfig.liquidationFactor).to.be.equal(AXSInCometInfo.liquidationFactor); + expect(axsAssetConfig.supplyCap).to.be.equal(AXSInCometInfo.supplyCap); + + expect(axsAssetConfig.asset).to.be.equal(AXSInConfiguratorInfoAXSComet.asset); + expect(axsAssetConfig.priceFeed).to.eq(AXSInConfiguratorInfoAXSComet.priceFeed); + expect(axsAssetConfig.decimals).to.be.equal(AXSInConfiguratorInfoAXSComet.decimals); + expect(axsAssetConfig.borrowCollateralFactor).to.be.equal(AXSInConfiguratorInfoAXSComet.borrowCollateralFactor); + expect(axsAssetConfig.liquidateCollateralFactor).to.be.equal(AXSInConfiguratorInfoAXSComet.liquidateCollateralFactor); + expect(axsAssetConfig.liquidationFactor).to.be.equal(AXSInConfiguratorInfoAXSComet.liquidationFactor); + expect(axsAssetConfig.supplyCap).to.be.equal(AXSInConfiguratorInfoAXSComet.supplyCap); + + expect(await comet.getPrice(newPriceFeedAXSAddress)).to.be.closeTo(await comet.getPrice(oldAXSPriceFeed), 1e6); + + const newConfig = { + borrowRateBase: exp(0.025, 18), + borrowRateSlopeLow: exp(0.017647, 18), + borrowKink: exp(0.85, 18), + borrowRateSlopeHigh: exp(0.732667, 18), + supplyRateBase: 0n, + supplyRateSlopeLow: exp(0.02, 18), + supplyKink: exp(0.85, 18), + supplyRateSlopeHigh: exp(0.868012, 18), + }; + + const borrowPerSecondInterestRateBase = await comet.borrowPerSecondInterestRateBase(); + expect(borrowPerSecondInterestRateBase).to.be.equal( + newConfig.borrowRateBase / (86400n * 365n) + ); + + const borrowPerSecondInterestRateSlopeLow = await comet.borrowPerSecondInterestRateSlopeLow(); + expect(borrowPerSecondInterestRateSlopeLow).to.be.equal( + newConfig.borrowRateSlopeLow / (86400n * 365n) + ); + + const borrowKink = await comet.borrowKink(); + expect(borrowKink).to.be.equal(newConfig.borrowKink); + + const borrowPerSecondInterestRateSlopeHigh = await comet.borrowPerSecondInterestRateSlopeHigh(); + expect(borrowPerSecondInterestRateSlopeHigh).to.be.equal( + newConfig.borrowRateSlopeHigh / (86400n * 365n) + ); + + const supplyPerSecondInterestRateBase = await comet.supplyPerSecondInterestRateBase(); + expect(supplyPerSecondInterestRateBase).to.be.equal( + newConfig.supplyRateBase / (86400n * 365n) + ); + + const supplyPerSecondInterestRateSlopeLow = await comet.supplyPerSecondInterestRateSlopeLow(); + expect(supplyPerSecondInterestRateSlopeLow).to.be.equal( + newConfig.supplyRateSlopeLow / (86400n * 365n) + ); + + const supplyKink = await comet.supplyKink(); + expect(supplyKink).to.be.equal(newConfig.supplyKink); + + const supplyPerSecondInterestRateSlopeHigh = await comet.supplyPerSecondInterestRateSlopeHigh(); + expect(supplyPerSecondInterestRateSlopeHigh).to.be.equal( + newConfig.supplyRateSlopeHigh / (86400n * 365n) + ); + }, +}); diff --git a/deployments/ronin/wron/migrations/1767889363_depreciate_comet.ts b/deployments/ronin/wron/migrations/1767889363_depreciate_comet.ts new file mode 100644 index 000000000..19bd50318 --- /dev/null +++ b/deployments/ronin/wron/migrations/1767889363_depreciate_comet.ts @@ -0,0 +1,534 @@ +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { calldata, proposal, exp } from '../../../../src/deploy'; +import { utils } from 'ethers'; + +const destinationChainSelector = '6916147374840168594'; + +const USDC_TO_USD_API3_PRICE_FEED_ADDRESS = '0xf061d556F5136263c4d66d9fFCADE8Ab43a3a704'; +const RON_TO_USD_API3_PRICE_FEED_ADDRESS = '0xA708247a64Fad46874A57BA274451a8a1A1daa0c'; +const ETH_TO_USD_API3_PRICE_FEED_ADDRESS = '0xbBF6e0D078c7F5750d0732cD8f3EACe9A87b2b58'; + +const CONSTANT_PRICE_FEED = '0x8AC2b57d15c84755A3333aD68025d2496AE3BeBD'; + +const GHO_STABLE_TOKEN = '0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f'; + +let newPriceFeedUSDCAddress: string; +let newPriceFeedWRONAddress: string; +let newPriceFeedWETHAddress: string; +let newPriceFeedAXSAddress: string; + +let oldUSDCPriceFeed: string; +let oldWRONPriceFeed: string; +let oldWETHPriceFeed: string; + +export default migration('1767889363_depreciate_comet', { + async prepare(deploymentManager: DeploymentManager) { + const _usdcPriceFeed = await deploymentManager.deploy( + 'USDC:priceFeed', + 'pricefeeds/ScalingPriceFeed.sol', + [ + USDC_TO_USD_API3_PRICE_FEED_ADDRESS, // USDC / USD price feed + 8 // decimals + ] + ); + + const _wronPriceFeed = await deploymentManager.deploy( + 'WRON:priceFeed', + 'pricefeeds/ScalingPriceFeed.sol', + [ + RON_TO_USD_API3_PRICE_FEED_ADDRESS, // WRON / USD price feed + 8, // decimals + ], + true + ); + + const _wethPriceFeed = await deploymentManager.deploy( + 'WETH:priceFeed', + 'pricefeeds/ScalingPriceFeed.sol', + [ + ETH_TO_USD_API3_PRICE_FEED_ADDRESS, // WETH / USD price feed + 8, // decimals + ], + true + ); + + return { + USDCPriceFeedAddress: _usdcPriceFeed.address, + WRONPriceFeedAddress: _wronPriceFeed.address, + WETHPriceFeedAddress: _wethPriceFeed.address, + }; + }, + + enact: async ( + deploymentManager: DeploymentManager, + govDeploymentManager: DeploymentManager, + { + USDCPriceFeedAddress, + WRONPriceFeedAddress, + WETHPriceFeedAddress, + } + ) => { + const trace = deploymentManager.tracer(); + newPriceFeedUSDCAddress = USDCPriceFeedAddress; + newPriceFeedWRONAddress = WRONPriceFeedAddress; + newPriceFeedWETHAddress = WETHPriceFeedAddress; + newPriceFeedAXSAddress = CONSTANT_PRICE_FEED; + + const { + bridgeReceiver, + comet, + cometAdmin, + configurator, + USDC, + AXS, + WETH, + } = await deploymentManager.getContracts(); + + const { + governor, + l1CCIPRouter + } = await govDeploymentManager.getContracts(); + + const usdcAssetConfig = { + asset: USDC.address, + priceFeed: newPriceFeedUSDCAddress, + decimals: await USDC.decimals(), + borrowCollateralFactor: exp(0.50, 18), + liquidateCollateralFactor: exp(0.80, 18), + liquidationFactor: exp(0.80, 18), + supplyCap: 0, + }; + + const wethAssetConfig = { + asset: WETH.address, + priceFeed: newPriceFeedWETHAddress, + decimals: await WETH.decimals(), + borrowCollateralFactor: exp(0.50, 18), + liquidateCollateralFactor: exp(0.80, 18), + liquidationFactor: exp(0.80, 18), + supplyCap: 0, + }; + + const axsAssetConfig = { + asset: AXS.address, + priceFeed: newPriceFeedAXSAddress, + decimals: await AXS.decimals(), + borrowCollateralFactor: exp(0.50, 18), + liquidateCollateralFactor: exp(0.78, 18), + liquidationFactor: exp(0.75, 18), + supplyCap: 0, + }; + + const updateWRONPriceFeedCalldata = await calldata( + configurator.populateTransaction.setBaseTokenPriceFeed( + comet.address, + newPriceFeedWRONAddress + ) + ); + + const updateUSDCAssetCalldata = await calldata( + configurator.populateTransaction.updateAsset( + comet.address, + usdcAssetConfig + ) + ); + + const updateWETHAssetCalldata = await calldata( + configurator.populateTransaction.updateAsset( + comet.address, + wethAssetConfig + ) + ); + + const updateAXSAssetCalldata = await calldata( + configurator.populateTransaction.updateAsset( + comet.address, + axsAssetConfig + ) + ); + + const setBorrowPerYearInterestRateBaseCalldata = await calldata( + configurator.populateTransaction.setBorrowPerYearInterestRateBase( + comet.address, + exp(0.025, 18) // 2.5% supply interest rate + ) + ); + + const setBorrowPerYearInterestRateSlopeLowCalldata = await calldata( + configurator.populateTransaction.setBorrowPerYearInterestRateSlopeLow( + comet.address, + exp(0.017647, 18) // 1.7647% borrow interest rate slope low + ) + ); + + const setBorrowKinkCalldata = await calldata( + configurator.populateTransaction.setBorrowKink( + comet.address, + exp(0.85, 18) // 85% borrow kink + ) + ); + + const setBorrowPerYearInterestRateSlopeHighCalldata = await calldata( + configurator.populateTransaction.setBorrowPerYearInterestRateSlopeHigh( + comet.address, + exp(0.732667, 18) // 73.2667% borrow interest rate slope high + ) + ); + + const setSupplyPerYearInterestRateBaseCalldata = await calldata( + configurator.populateTransaction.setSupplyPerYearInterestRateBase( + comet.address, + 0 // 0% supply interest rate + ) + ); + + const setSupplyPerYearInterestRateSlopeLowCalldata = await calldata( + configurator.populateTransaction.setSupplyPerYearInterestRateSlopeLow( + comet.address, + exp(0.02, 18) // 2% supply interest rate slope low + ) + ); + + const setSupplyKinkCalldata = await calldata( + configurator.populateTransaction.setSupplyKink( + comet.address, + exp(0.85, 18) // 85% supply kink + ) + ); + + const setSupplyPerYearInterestRateSlopeHighCalldata = await calldata( + configurator.populateTransaction.setSupplyPerYearInterestRateSlopeHigh( + comet.address, + exp(0.868012, 18) // 86.8012% supply interest rate slope high + ) + ); + + const deployAndUpgradeToCalldata = await calldata( + cometAdmin.populateTransaction.deployAndUpgradeTo( + configurator.address, + comet.address + ) + ); + + const l2ProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + configurator.address, + configurator.address, + configurator.address, + configurator.address, + configurator.address, + configurator.address, + configurator.address, + configurator.address, + configurator.address, + configurator.address, + configurator.address, + configurator.address, + cometAdmin.address + ], + [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ], + [ + 'setBaseTokenPriceFeed(address,address)', + 'updateAsset(address,(address,address,uint8,uint64,uint64,uint64,uint128))', + 'updateAsset(address,(address,address,uint8,uint64,uint64,uint64,uint128))', + 'updateAsset(address,(address,address,uint8,uint64,uint64,uint64,uint128))', + 'setBorrowPerYearInterestRateBase(address,uint64)', + 'setBorrowPerYearInterestRateSlopeLow(address,uint64)', + 'setBorrowKink(address,uint64)', + 'setBorrowPerYearInterestRateSlopeHigh(address,uint64)', + 'setSupplyPerYearInterestRateBase(address,uint64)', + 'setSupplyPerYearInterestRateSlopeLow(address,uint64)', + 'setSupplyKink(address,uint64)', + 'setSupplyPerYearInterestRateSlopeHigh(address,uint64)', + 'deployAndUpgradeTo(address,address)' + ], + [ + updateWRONPriceFeedCalldata, + updateUSDCAssetCalldata, + updateWETHAssetCalldata, + updateAXSAssetCalldata, + setBorrowPerYearInterestRateBaseCalldata, + setBorrowPerYearInterestRateSlopeLowCalldata, + setBorrowKinkCalldata, + setBorrowPerYearInterestRateSlopeHighCalldata, + setSupplyPerYearInterestRateBaseCalldata, + setSupplyPerYearInterestRateSlopeLowCalldata, + setSupplyKinkCalldata, + setSupplyPerYearInterestRateSlopeHighCalldata, + deployAndUpgradeToCalldata + ], + ] + ); + + [,, oldUSDCPriceFeed] = await comet.getAssetInfoByAddress(USDC.address); + oldWRONPriceFeed = await comet.baseTokenPriceFeed(); + [,, oldWETHPriceFeed] = await comet.getAssetInfoByAddress(WETH.address); + + const fee = await l1CCIPRouter.getFee(destinationChainSelector, [ + utils.defaultAbiCoder.encode(['address'], [bridgeReceiver.address]), + l2ProposalData, + [], + GHO_STABLE_TOKEN, + '0x' + ]); + + const mainnetActions = [ + // 1. Approve GHO stable token transfer to pay for the proposal execution fee on Ronin. + { + target: GHO_STABLE_TOKEN, + signature: 'approve(address,uint256)', + calldata: utils.defaultAbiCoder.encode(['address', 'uint256'], [l1CCIPRouter.address, fee.mul(2)]) + }, + // 2. Set Comet configuration and deployAndUpgradeTo WETH Comet on Ronin. + { + contract: l1CCIPRouter, + signature: 'ccipSend(uint64,(bytes,bytes,(address,uint256)[],address,bytes))', + args: + [ + destinationChainSelector, + [ + utils.defaultAbiCoder.encode(['address'], [bridgeReceiver.address]), + l2ProposalData, + [], + GHO_STABLE_TOKEN, + '0x' + ] + ] + }, + ]; + + const description = `# Depreciate cWRONv3 on Ronin + +## Proposal summary + +This proposal updates price feeds to API3, since Chainlink soon will no longer support Ronin and updates interest rate curve parameters for WRON market on Ronin. + +It is done to prevent new suppliers from entering the market, reduces capital efficiency, making the market less appealing without causing users to become liquidatable and raises liquidation penalty to further disincentivizes usage by increasing the cost of liquidation, while reducing risk to the comet. + +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1084) and [forum discussion](https://www.comp.xyz/t/gauntlet-depreciating-ronin-weth-and-wron-comets/7308). + +## Proposal actions + +The first proposal action approves the L1CCIPRouter to transfer GHO stable token from the timelock to pay for the proposal execution fee on Ronin. + +The second proposal action sends the following encoded calls to the governance receiver on Ronin: +- Update USDC, WETH, AXS, and WRON price feeds to API3 oracle +- Set supply caps to 0 for all collateral assets +- Reduce collateral factors +- Increase liquidation penalties +- Update interest rate curve parameters: + - \`setBorrowPerYearInterestRateBase\` + - \`setBorrowPerYearInterestRateSlopeLow\` + - \`setBorrowKink\` + - \`setBorrowPerYearInterestRateSlopeHigh\` + - \`setSupplyPerYearInterestRateBase\` + - \`setSupplyPerYearInterestRateSlopeLow\` + - \`setSupplyKink\` + - \`setSupplyPerYearInterestRateSlopeHigh\` +- Deploy and upgrade to new configuration via \`deployAndUpgradeTo\`. +`; + + const txn = await govDeploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 300_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(deploymentManager: DeploymentManager): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + const { + comet, + configurator, + USDC, + WETH, + AXS, + } = await deploymentManager.getContracts(); + + const usdcAssetConfig = { + asset: USDC.address, + priceFeed: newPriceFeedUSDCAddress, + decimals: 6, + borrowCollateralFactor: exp(0.50, 18), + liquidateCollateralFactor: exp(0.80, 18), + liquidationFactor: exp(0.80, 18), + supplyCap: 0, + }; + + const wethAssetConfig = { + asset: WETH.address, + priceFeed: newPriceFeedWETHAddress, + decimals: 18, + borrowCollateralFactor: exp(0.50, 18), + liquidateCollateralFactor: exp(0.80, 18), + liquidationFactor: exp(0.80, 18), + supplyCap: 0, + }; + + const axsAssetConfig = { + asset: AXS.address, + priceFeed: newPriceFeedAXSAddress, + decimals: 18, + borrowCollateralFactor: exp(0.50, 18), + liquidateCollateralFactor: exp(0.78, 18), + liquidationFactor: exp(0.75, 18), + supplyCap: 0, + }; + + // 1. WRON + const WRONPriceFeedFromComet = await comet.baseTokenPriceFeed(); + const WRONPriceFeedFromConfigurator = ( + await configurator.getConfiguration(comet.address) + ).baseTokenPriceFeed; + + expect(WRONPriceFeedFromComet).to.eq(newPriceFeedWRONAddress); + expect(WRONPriceFeedFromConfigurator).to.eq(newPriceFeedWRONAddress); + expect(await comet.getPrice(newPriceFeedWRONAddress)).to.be.closeTo(await comet.getPrice(oldWRONPriceFeed), 1e6); + + // 2. USDC + const USDCIndexInComet = await configurator.getAssetIndex( + comet.address, + USDC.address + ); + const USDCInCometInfo = await comet.getAssetInfoByAddress(USDC.address); + const USDCInConfiguratorInfoComet = ( + await configurator.getConfiguration(comet.address) + ).assetConfigs[USDCIndexInComet]; + + expect(usdcAssetConfig.asset).to.be.equal(USDCInCometInfo.asset); + expect(usdcAssetConfig.priceFeed).to.eq(USDCInCometInfo.priceFeed); + expect(exp(1, usdcAssetConfig.decimals)).to.be.equal(USDCInCometInfo.scale); + expect(usdcAssetConfig.borrowCollateralFactor).to.be.equal(USDCInCometInfo.borrowCollateralFactor); + expect(usdcAssetConfig.liquidateCollateralFactor).to.be.equal(USDCInCometInfo.liquidateCollateralFactor); + expect(usdcAssetConfig.liquidationFactor).to.be.equal(USDCInCometInfo.liquidationFactor); + expect(usdcAssetConfig.supplyCap).to.be.equal(USDCInCometInfo.supplyCap); + + expect(usdcAssetConfig.asset).to.be.equal(USDCInConfiguratorInfoComet.asset); + expect(usdcAssetConfig.priceFeed).to.eq(USDCInConfiguratorInfoComet.priceFeed); + expect(usdcAssetConfig.decimals).to.be.equal(USDCInConfiguratorInfoComet.decimals); + expect(usdcAssetConfig.borrowCollateralFactor).to.be.equal(USDCInConfiguratorInfoComet.borrowCollateralFactor); + expect(usdcAssetConfig.liquidateCollateralFactor).to.be.equal(USDCInConfiguratorInfoComet.liquidateCollateralFactor); + expect(usdcAssetConfig.liquidationFactor).to.be.equal(USDCInConfiguratorInfoComet.liquidationFactor); + expect(usdcAssetConfig.supplyCap).to.be.equal(USDCInConfiguratorInfoComet.supplyCap); + + expect(await comet.getPrice(newPriceFeedUSDCAddress)).to.be.closeTo(await comet.getPrice(oldUSDCPriceFeed), 1e6); + + // 3. WETH + const WETHIndexInComet = await configurator.getAssetIndex( + comet.address, + WETH.address + ); + const WETHInCometInfo = await comet.getAssetInfoByAddress(WETH.address); + const WETHInConfiguratorInfoWETHComet = ( + await configurator.getConfiguration(comet.address) + ).assetConfigs[WETHIndexInComet]; + + expect(wethAssetConfig.asset).to.be.equal(WETHInCometInfo.asset); + expect(wethAssetConfig.priceFeed).to.eq(WETHInCometInfo.priceFeed); + expect(exp(1, wethAssetConfig.decimals)).to.be.equal(WETHInCometInfo.scale); + expect(wethAssetConfig.borrowCollateralFactor).to.be.equal(WETHInCometInfo.borrowCollateralFactor); + expect(wethAssetConfig.liquidateCollateralFactor).to.be.equal(WETHInCometInfo.liquidateCollateralFactor); + expect(wethAssetConfig.liquidationFactor).to.be.equal(WETHInCometInfo.liquidationFactor); + expect(wethAssetConfig.supplyCap).to.be.equal(WETHInCometInfo.supplyCap); + + expect(wethAssetConfig.asset).to.be.equal(WETHInConfiguratorInfoWETHComet.asset); + expect(wethAssetConfig.priceFeed).to.eq(WETHInConfiguratorInfoWETHComet.priceFeed); + expect(wethAssetConfig.decimals).to.be.equal(WETHInConfiguratorInfoWETHComet.decimals); + expect(wethAssetConfig.borrowCollateralFactor).to.be.equal(WETHInConfiguratorInfoWETHComet.borrowCollateralFactor); + expect(wethAssetConfig.liquidateCollateralFactor).to.be.equal(WETHInConfiguratorInfoWETHComet.liquidateCollateralFactor); + expect(wethAssetConfig.liquidationFactor).to.be.equal(WETHInConfiguratorInfoWETHComet.liquidationFactor); + expect(wethAssetConfig.supplyCap).to.be.equal(WETHInConfiguratorInfoWETHComet.supplyCap); + + expect(await comet.getPrice(newPriceFeedWETHAddress)).to.be.closeTo(await comet.getPrice(oldWETHPriceFeed), 20e8); // $20 + + // 4. AXS + const AXSIndexInComet = await configurator.getAssetIndex( + comet.address, + AXS.address + ); + const AXSInCometInfo = await comet.getAssetInfoByAddress(AXS.address); + const AXSInConfiguratorInfoAXSComet = ( + await configurator.getConfiguration(comet.address) + ).assetConfigs[AXSIndexInComet]; + + expect(axsAssetConfig.asset).to.be.equal(AXSInCometInfo.asset); + expect(axsAssetConfig.priceFeed).to.eq(AXSInCometInfo.priceFeed); + expect(exp(1, axsAssetConfig.decimals)).to.be.equal(AXSInCometInfo.scale); + expect(axsAssetConfig.borrowCollateralFactor).to.be.equal(AXSInCometInfo.borrowCollateralFactor); + expect(axsAssetConfig.liquidateCollateralFactor).to.be.equal(AXSInCometInfo.liquidateCollateralFactor); + expect(axsAssetConfig.liquidationFactor).to.be.equal(AXSInCometInfo.liquidationFactor); + expect(axsAssetConfig.supplyCap).to.be.equal(AXSInCometInfo.supplyCap); + + expect(axsAssetConfig.asset).to.be.equal(AXSInConfiguratorInfoAXSComet.asset); + expect(axsAssetConfig.priceFeed).to.eq(AXSInConfiguratorInfoAXSComet.priceFeed); + expect(axsAssetConfig.decimals).to.be.equal(AXSInConfiguratorInfoAXSComet.decimals); + expect(axsAssetConfig.borrowCollateralFactor).to.be.equal(AXSInConfiguratorInfoAXSComet.borrowCollateralFactor); + expect(axsAssetConfig.liquidateCollateralFactor).to.be.equal(AXSInConfiguratorInfoAXSComet.liquidateCollateralFactor); + expect(axsAssetConfig.liquidationFactor).to.be.equal(AXSInConfiguratorInfoAXSComet.liquidationFactor); + expect(axsAssetConfig.supplyCap).to.be.equal(AXSInConfiguratorInfoAXSComet.supplyCap); + + expect(await comet.getPrice(newPriceFeedAXSAddress)).to.be.equal(exp(1, 8)); + + const newConfig = { + borrowRateBase: exp(0.025, 18), + borrowRateSlopeLow: exp(0.017647, 18), + borrowKink: exp(0.85, 18), + borrowRateSlopeHigh: exp(0.732667, 18), + supplyRateBase: 0n, + supplyRateSlopeLow: exp(0.02, 18), + supplyKink: exp(0.85, 18), + supplyRateSlopeHigh: exp(0.868012, 18), + }; + + const borrowPerSecondInterestRateBase = await comet.borrowPerSecondInterestRateBase(); + expect(borrowPerSecondInterestRateBase).to.be.equal( + newConfig.borrowRateBase / (86400n * 365n) + ); + + const borrowPerSecondInterestRateSlopeLow = await comet.borrowPerSecondInterestRateSlopeLow(); + expect(borrowPerSecondInterestRateSlopeLow).to.be.equal( + newConfig.borrowRateSlopeLow / (86400n * 365n) + ); + + const borrowKink = await comet.borrowKink(); + expect(borrowKink).to.be.equal(newConfig.borrowKink); + + const borrowPerSecondInterestRateSlopeHigh = await comet.borrowPerSecondInterestRateSlopeHigh(); + expect(borrowPerSecondInterestRateSlopeHigh).to.be.equal( + newConfig.borrowRateSlopeHigh / (86400n * 365n) + ); + + const supplyPerSecondInterestRateBase = await comet.supplyPerSecondInterestRateBase(); + expect(supplyPerSecondInterestRateBase).to.be.equal( + newConfig.supplyRateBase / (86400n * 365n) + ); + + const supplyPerSecondInterestRateSlopeLow = await comet.supplyPerSecondInterestRateSlopeLow(); + expect(supplyPerSecondInterestRateSlopeLow).to.be.equal( + newConfig.supplyRateSlopeLow / (86400n * 365n) + ); + + const supplyKink = await comet.supplyKink(); + expect(supplyKink).to.be.equal(newConfig.supplyKink); + + const supplyPerSecondInterestRateSlopeHigh = await comet.supplyPerSecondInterestRateSlopeHigh(); + expect(supplyPerSecondInterestRateSlopeHigh).to.be.equal( + newConfig.supplyRateSlopeHigh / (86400n * 365n) + ); + }, +}); diff --git a/deployments/ronin/wron/migrations/1772710499_update_usdc_price_feed.ts b/deployments/ronin/wron/migrations/1772710499_update_usdc_price_feed.ts new file mode 100644 index 000000000..e296a442d --- /dev/null +++ b/deployments/ronin/wron/migrations/1772710499_update_usdc_price_feed.ts @@ -0,0 +1,189 @@ +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { calldata, proposal } from '../../../../src/deploy'; +import { utils, Contract } from 'ethers'; + +const destinationChainSelector = '6916147374840168594'; + +const USDC_TO_USD_API3_PRICE_FEED_ADDRESS = '0xf061d556F5136263c4d66d9fFCADE8Ab43a3a704'; + +const GHO_STABLE_TOKEN = '0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f'; + +let newPriceFeedUSDCAddress: string; +let oldUSDCPriceFeed: string; + +export default migration('1772710499_update_usdc_price_feed', { + async prepare(deploymentManager: DeploymentManager) { + const _usdcPriceFeed = await deploymentManager.deploy( + 'USDC:priceFeed', + 'pricefeeds/ScalingPriceFeed.sol', + [ + USDC_TO_USD_API3_PRICE_FEED_ADDRESS, // USDC / USD price feed + 8 // decimals + ], + true + ); + return { + USDCPriceFeedAddress: _usdcPriceFeed.address + }; + }, + + enact: async ( + deploymentManager: DeploymentManager, + govDeploymentManager: DeploymentManager, + { + USDCPriceFeedAddress + } + ) => { + const trace = deploymentManager.tracer(); + newPriceFeedUSDCAddress = USDCPriceFeedAddress; + + const { + bridgeReceiver, + comet, + cometAdmin, + configurator, + USDC + } = await deploymentManager.getContracts(); + + const { + governor, + l1CCIPRouter + } = await govDeploymentManager.getContracts(); + + const updateUSDCAssetCalldata = await calldata( + configurator.populateTransaction.updateAssetPriceFeed( + comet.address, + USDC.address, + newPriceFeedUSDCAddress + ) + ); + + const deployAndUpgradeToCalldata = await calldata( + cometAdmin.populateTransaction.deployAndUpgradeTo( + configurator.address, + comet.address + ) + ); + + const l2ProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + configurator.address, + cometAdmin.address + ], + [ 0, 0 ], + [ + 'updateAssetPriceFeed(address,address,address)', + 'deployAndUpgradeTo(address,address)' + ], + [ + updateUSDCAssetCalldata, + deployAndUpgradeToCalldata + ], + ] + ); + + [,, oldUSDCPriceFeed] = await comet.getAssetInfoByAddress(USDC.address); + + const fee = await l1CCIPRouter.getFee(destinationChainSelector, [ + utils.defaultAbiCoder.encode(['address'], [bridgeReceiver.address]), + l2ProposalData, + [], + GHO_STABLE_TOKEN, + '0x' + ]); + + const mainnetActions = [ + // 1. Approve GHO stable token transfer to pay for the proposal execution fee on Ronin. + { + target: GHO_STABLE_TOKEN, + signature: 'approve(address,uint256)', + calldata: utils.defaultAbiCoder.encode(['address', 'uint256'], [l1CCIPRouter.address, fee.mul(2)]) + }, + // 2. Set Comet configuration and deployAndUpgradeTo WETH Comet on Ronin. + { + contract: l1CCIPRouter, + signature: 'ccipSend(uint64,(bytes,bytes,(address,uint256)[],address,bytes))', + args: + [ + destinationChainSelector, + [ + utils.defaultAbiCoder.encode(['address'], [bridgeReceiver.address]), + l2ProposalData, + [], + GHO_STABLE_TOKEN, + '0x' + ] + ] + }, + ]; + + const description = `# Update USDC price feed on cWRONv3 on Ronin + +## Proposal summary + +This proposal updates USDC price feeds to API3, since Chainlink is no longer supported on Ronin. + +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1093). + +## Proposal actions + +The first proposal action approves the L1CCIPRouter to transfer GHO stable token from the timelock to pay for the proposal execution fee on Ronin. + +The second proposal action sends the following encoded calls to the governance receiver on Ronin: +- Update USDC price feed to API3 oracle +- Deploy and upgrade to new configuration via \`deployAndUpgradeTo\`. +`; + + const txn = await govDeploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 300_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(deploymentManager: DeploymentManager): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + const { + comet, + configurator, + USDC + } = await deploymentManager.getContracts(); + + const USDCIndexInComet = await configurator.getAssetIndex( + comet.address, + USDC.address + ); + const USDCInComet = await comet.getAssetInfoByAddress(USDC.address); + const USDCInConfigurator = ( + await configurator.getConfiguration(comet.address) + ).assetConfigs[USDCIndexInComet]; + + expect(USDC.address).to.be.equal(USDCInComet.asset); + expect(newPriceFeedUSDCAddress).to.eq(USDCInComet.priceFeed); + + expect(USDC.address).to.be.equal(USDCInConfigurator.asset); + expect(newPriceFeedUSDCAddress).to.eq(USDCInConfigurator.priceFeed); + + const newPriceFeedContract = new Contract(newPriceFeedUSDCAddress, [ + 'function underlyingPriceFeed() external view returns (address)' + ], + await deploymentManager.getSigner() + ); + expect(await newPriceFeedContract.underlyingPriceFeed()).to.be.equal(USDC_TO_USD_API3_PRICE_FEED_ADDRESS); + + expect(await comet.getPrice(newPriceFeedUSDCAddress)).to.be.closeTo(await comet.getPrice(oldUSDCPriceFeed), 1e6); + }, +}); \ No newline at end of file diff --git a/scenario/LiquidationScenario.ts b/scenario/LiquidationScenario.ts index c22c0e133..be64732a7 100644 --- a/scenario/LiquidationScenario.ts +++ b/scenario/LiquidationScenario.ts @@ -212,7 +212,7 @@ scenario( { filter: async (ctx) => !matchesDeployment(ctx, [ { network: 'base', deployment: 'usds' }, - { network: 'ronin' }, + { network: 'ronin', deployment: 'weth' }, ]), tokenBalances: async (ctx) => ( { diff --git a/scenario/utils/index.ts b/scenario/utils/index.ts index 70355b942..61e8f2c91 100644 --- a/scenario/utils/index.ts +++ b/scenario/utils/index.ts @@ -862,6 +862,7 @@ export async function tenderlyExecute( state_objects: statePatch, save: true, gas_price: 0, + gas_limit: 16_777_215, })), { network_id: chainId1.toString(), @@ -873,6 +874,7 @@ export async function tenderlyExecute( state_objects: statePatch, save: true, gas_price: 0, + gas_limit: 16_777_215, }, ...whales.map((w) => ({ network_id: chainId1.toString(), @@ -885,6 +887,7 @@ export async function tenderlyExecute( save: true, save_if_fails: true, gas_price: 0, + gas_limit: 16_777_215, })), { network_id: chainId1.toString(), @@ -897,6 +900,7 @@ export async function tenderlyExecute( save: true, save_if_fails: true, gas_price: 0, + gas_limit: 16_777_215, }, { network_id: chainId1.toString(), @@ -909,6 +913,7 @@ export async function tenderlyExecute( save: true, save_if_fails: true, gas_price: 0, + gas_limit: 16_777_215, }, ]; @@ -960,6 +965,7 @@ export async function tenderlyExecute( save: true, save_if_fails: true, gas_price: 0, + gas_limit: 16_777_215, }; }); diff --git a/scenario/utils/scenarioHelper.ts b/scenario/utils/scenarioHelper.ts index cdd3878b9..e8d64fa40 100644 --- a/scenario/utils/scenarioHelper.ts +++ b/scenario/utils/scenarioHelper.ts @@ -37,12 +37,12 @@ const defaultConfig = { export function getConfigForScenario(ctx: CometContext, i?: number) { const config = { ...defaultConfig }; if (ctx.world.base.network === 'mainnet' && ctx.world.base.deployment === 'wbtc') { - config.bulkerBase = 200; - config.bulkerAsset = 400; - config.bulkerAsset1 = 400; - config.bulkerComet = 200; - config.bulkerBorrowBase = 100; - config.withdrawBase = 100; + config.bulkerBase = 50; + config.bulkerAsset = 200; + config.bulkerAsset1 = 200; + config.bulkerComet = 50; + config.bulkerBorrowBase = 25; + config.withdrawBase = 25; config.withdrawAsset = 200; config.bulkerBorrowAsset = 50; config.liquidationBase = 1000; @@ -207,9 +207,12 @@ export function getConfigForScenario(ctx: CometContext, i?: number) { } if (ctx.world.base.network === 'polygon' && ctx.world.base.deployment === 'usdt') { - config.withdrawAsset = 10000; + config.withdrawAsset = 20000; + config.withdrawBase = 100; config.transferAsset = 500000; config.transferBase = 100; + config.rewardsAsset = 20000; + config.rewardsBase = 1000; } if (ctx.world.base.network === 'scroll' && ctx.world.base.deployment === 'usdc') { diff --git a/src/deploy/index.ts b/src/deploy/index.ts index d105db072..92559e8c5 100644 --- a/src/deploy/index.ts +++ b/src/deploy/index.ts @@ -111,6 +111,7 @@ export const WHALES = { '0xdCa0A2341ed5438E06B9982243808A76B9ADD6d0', // woETH whale '0x34C0bD5877A5Ee7099D0f5688D65F4bB9158BDE2', // sFRAX whale '0x9152e9C04e8fE8373EDaa8f5841E25d4015658B7', // pumpBTC whale + '0xd4Cc9b31e9eF33E392FF2f81AD52BE8523e0993b', // pumpBTC whale '0x65906988ADEe75306021C417a1A3458040239602', // LBTC whale '0x7667095Caa12b79fCa489ff6E2198Ca01fDAe057', ], @@ -180,13 +181,15 @@ export const WHALES = { '0xd374a62AA68D01cdB420e17b9840706e86BC840B', // mETH whale '0x88a1493366D48225fc3cEFbdae9eBb23E323Ade3', // mETH whale '0xEe6281d94Fed46A90379F2033B6BbdcDa4EF462E', // mETH whale - '0x651C9D1F9da787688225f49d63ad1623ba89A8D5', // FBTC whale '0xC455fE28a76da80022d4C35A37eB08FF405Eb78f', // FBTC whale '0x524db930F0886CdE7B5FFFc920Aae85e98C2abfb', // FBTC whale '0x651C9D1F9da787688225f49d63ad1623ba89A8D5', // FBTC whale '0x72c7d27320e042417506e594697324dB5Fbf334C', // FBTC whale '0x3880233e78966eb13a9c2881d5f162d646633178', // FBTC whale '0x233493E9DC68e548AC27E4933A600A3A4682c0c3', // FBTC whale + '0xd8169F099ce16C87A99d2A8494023574B5eEA9c5', // mETH whale + '0x15Bb5D31048381c84a157526cEF9513531b8BE1e', // FBTC whale + '0xfa14c9DE267b59A586043372bd98Ed99e3Ee0533', // FBTC whale '0xCd83CbBFCE149d141A5171C3D6a0F0fCCeE225Ab', // COMP whale ], 'unichain': [ From c1c411ace52fb7d90a5877050bcd2d7b7927b0ca Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Thu, 21 May 2026 15:35:22 +0300 Subject: [PATCH 49/65] fix: speed up gas tests --- plugins/deployment_manager/Deploy.ts | 1 + plugins/deployment_manager/Verify.ts | 3 ++- plugins/deployment_manager/test/DeploymentManagerTest.ts | 6 ++++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/plugins/deployment_manager/Deploy.ts b/plugins/deployment_manager/Deploy.ts index e8601ef34..95b4d4256 100644 --- a/plugins/deployment_manager/Deploy.ts +++ b/plugins/deployment_manager/Deploy.ts @@ -129,6 +129,7 @@ export async function deploy( via: 'artifacts', address: contract.address, constructorArguments: deployArgs, + contract: `contracts/${contractFile}:${contractName}`, }; await retry(async () => { diff --git a/plugins/deployment_manager/Verify.ts b/plugins/deployment_manager/Verify.ts index 8d53f3694..273da8a19 100644 --- a/plugins/deployment_manager/Verify.ts +++ b/plugins/deployment_manager/Verify.ts @@ -6,7 +6,7 @@ import { BuildFile } from './Types'; import { debug } from './Utils'; export type VerifyArgs = - | { via: 'artifacts', address: string, constructorArguments: any } + | { via: 'artifacts', address: string, constructorArguments: any, contract?: string } | { via: 'buildfile', contract: Contract, buildFile: BuildFile, deployArgs: any[] }; export type VerificationStrategy = 'none' | 'eager' | 'lazy'; @@ -25,6 +25,7 @@ export async function verifyContract( await hre.run('verify:verify', { address: verifyArgs.address, constructorArguments: verifyArgs.constructorArguments, + ...(verifyArgs.contract !== undefined && { contract: verifyArgs.contract }), }); } else if (verifyArgs.via === 'buildfile') { address = verifyArgs.contract.address; diff --git a/plugins/deployment_manager/test/DeploymentManagerTest.ts b/plugins/deployment_manager/test/DeploymentManagerTest.ts index e7caea616..e49d95a26 100644 --- a/plugins/deployment_manager/test/DeploymentManagerTest.ts +++ b/plugins/deployment_manager/test/DeploymentManagerTest.ts @@ -134,7 +134,8 @@ describe('DeploymentManager', () => { }); describe('verifyContracts', () => { - it('should verify contracts successfully', async () => { + it('should verify contracts successfully', async function () { + this.timeout(300_000); let deploymentManager = new DeploymentManager('test-network', 'test-deployment', hre, { importRetries: 0, writeCacheToDisk: true, @@ -145,7 +146,8 @@ describe('DeploymentManager', () => { let verifyArgs: VerifyArgs = { via: 'artifacts', address: token.address, - constructorArguments: tokenArgs + constructorArguments: tokenArgs, + contract: 'contracts/test/FaucetToken.sol:FaucetToken', }; await putVerifyArgs( deploymentManager.cache, From 2c7d1980aee7c3f34d3bc01eb51c823e5092a2cc Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Thu, 21 May 2026 15:43:14 +0300 Subject: [PATCH 50/65] fix: set enacted to true --- .../weth/migrations/1772198347_upgrade_to_svr_price_feeds.ts | 2 +- .../usds/migrations/1777297641_update_supply_caps_on_mainnet.ts | 2 +- .../usdt/migrations/1777297641_update_supply_caps_on_mainnet.ts | 2 +- .../mainnet/wbtc/migrations/1737396251_configurate_and_ens.ts | 2 +- .../wbtc/migrations/1777625885_update_supply_caps_on_mainnet.ts | 2 +- .../1779099097_return_rseth_pricefeeds_on_weth_and_wsteth.ts | 2 +- .../migrations/1777625885_update_supply_caps_on_mainnet.ts | 2 +- .../1779099097_return_rseth_pricefeeds_on_weth_and_wsteth.ts | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/deployments/arbitrum/weth/migrations/1772198347_upgrade_to_svr_price_feeds.ts b/deployments/arbitrum/weth/migrations/1772198347_upgrade_to_svr_price_feeds.ts index 9bbd2b43e..560092aae 100644 --- a/deployments/arbitrum/weth/migrations/1772198347_upgrade_to_svr_price_feeds.ts +++ b/deployments/arbitrum/weth/migrations/1772198347_upgrade_to_svr_price_feeds.ts @@ -196,7 +196,7 @@ The first action updates rsETH price feed to the CAPO implementation and WBTC pr }, async enacted(): Promise { - return false; + return true; }, async verify(deploymentManager: DeploymentManager) { diff --git a/deployments/mainnet/usds/migrations/1777297641_update_supply_caps_on_mainnet.ts b/deployments/mainnet/usds/migrations/1777297641_update_supply_caps_on_mainnet.ts index f4afeca91..a4247c132 100644 --- a/deployments/mainnet/usds/migrations/1777297641_update_supply_caps_on_mainnet.ts +++ b/deployments/mainnet/usds/migrations/1777297641_update_supply_caps_on_mainnet.ts @@ -148,7 +148,7 @@ Further detailed information can be found on the corresponding [proposal pull re }, async enacted(): Promise { - return false; + return true; }, async verify(deploymentManager: DeploymentManager) { diff --git a/deployments/mainnet/usdt/migrations/1777297641_update_supply_caps_on_mainnet.ts b/deployments/mainnet/usdt/migrations/1777297641_update_supply_caps_on_mainnet.ts index f4afeca91..a4247c132 100644 --- a/deployments/mainnet/usdt/migrations/1777297641_update_supply_caps_on_mainnet.ts +++ b/deployments/mainnet/usdt/migrations/1777297641_update_supply_caps_on_mainnet.ts @@ -148,7 +148,7 @@ Further detailed information can be found on the corresponding [proposal pull re }, async enacted(): Promise { - return false; + return true; }, async verify(deploymentManager: DeploymentManager) { diff --git a/deployments/mainnet/wbtc/migrations/1737396251_configurate_and_ens.ts b/deployments/mainnet/wbtc/migrations/1737396251_configurate_and_ens.ts index f892db584..721281206 100644 --- a/deployments/mainnet/wbtc/migrations/1737396251_configurate_and_ens.ts +++ b/deployments/mainnet/wbtc/migrations/1737396251_configurate_and_ens.ts @@ -129,7 +129,7 @@ export default migration('1737396251_configurate_and_ens', { }, async enacted(): Promise { - return false; + return true; }, async verify(deploymentManager: DeploymentManager) { diff --git a/deployments/mainnet/wbtc/migrations/1777625885_update_supply_caps_on_mainnet.ts b/deployments/mainnet/wbtc/migrations/1777625885_update_supply_caps_on_mainnet.ts index 3961760b8..1cf232b8e 100644 --- a/deployments/mainnet/wbtc/migrations/1777625885_update_supply_caps_on_mainnet.ts +++ b/deployments/mainnet/wbtc/migrations/1777625885_update_supply_caps_on_mainnet.ts @@ -177,7 +177,7 @@ Further detailed information can be found on the corresponding [proposal pull re }, async enacted(): Promise { - return false; + return true; }, async verify(deploymentManager: DeploymentManager) { diff --git a/deployments/mainnet/weth/migrations/1779099097_return_rseth_pricefeeds_on_weth_and_wsteth.ts b/deployments/mainnet/weth/migrations/1779099097_return_rseth_pricefeeds_on_weth_and_wsteth.ts index 1b93c666c..37acd6738 100644 --- a/deployments/mainnet/weth/migrations/1779099097_return_rseth_pricefeeds_on_weth_and_wsteth.ts +++ b/deployments/mainnet/weth/migrations/1779099097_return_rseth_pricefeeds_on_weth_and_wsteth.ts @@ -85,7 +85,7 @@ Implementation details: [PR #1122](https://github.com/compound-finance/comet/pul }, async enacted(): Promise { - return false; + return true; }, async verify(deploymentManager: DeploymentManager) { diff --git a/deployments/mainnet/wsteth/migrations/1777625885_update_supply_caps_on_mainnet.ts b/deployments/mainnet/wsteth/migrations/1777625885_update_supply_caps_on_mainnet.ts index 3961760b8..1cf232b8e 100644 --- a/deployments/mainnet/wsteth/migrations/1777625885_update_supply_caps_on_mainnet.ts +++ b/deployments/mainnet/wsteth/migrations/1777625885_update_supply_caps_on_mainnet.ts @@ -177,7 +177,7 @@ Further detailed information can be found on the corresponding [proposal pull re }, async enacted(): Promise { - return false; + return true; }, async verify(deploymentManager: DeploymentManager) { diff --git a/deployments/mainnet/wsteth/migrations/1779099097_return_rseth_pricefeeds_on_weth_and_wsteth.ts b/deployments/mainnet/wsteth/migrations/1779099097_return_rseth_pricefeeds_on_weth_and_wsteth.ts index 1b93c666c..37acd6738 100644 --- a/deployments/mainnet/wsteth/migrations/1779099097_return_rseth_pricefeeds_on_weth_and_wsteth.ts +++ b/deployments/mainnet/wsteth/migrations/1779099097_return_rseth_pricefeeds_on_weth_and_wsteth.ts @@ -85,7 +85,7 @@ Implementation details: [PR #1122](https://github.com/compound-finance/comet/pul }, async enacted(): Promise { - return false; + return true; }, async verify(deploymentManager: DeploymentManager) { From 7b738e5e6f8acddd123756e83a76416c81e9d9a2 Mon Sep 17 00:00:00 2001 From: Mykhailo Shabodyash Date: Fri, 22 May 2026 12:13:08 +0300 Subject: [PATCH 51/65] fix: remove redundant migrations --- .../1761125221_upgrade_to_capo_price_feeds.ts | 160 ------------------ ...pdate_comet_to_support_more_collaterals.ts | 148 ---------------- 2 files changed, 308 deletions(-) delete mode 100644 deployments/base/aero/migrations/1761125221_upgrade_to_capo_price_feeds.ts delete mode 100644 deployments/base/usdbc/migrations/1735299714_update_comet_to_support_more_collaterals.ts diff --git a/deployments/base/aero/migrations/1761125221_upgrade_to_capo_price_feeds.ts b/deployments/base/aero/migrations/1761125221_upgrade_to_capo_price_feeds.ts deleted file mode 100644 index d58fd5fb7..000000000 --- a/deployments/base/aero/migrations/1761125221_upgrade_to_capo_price_feeds.ts +++ /dev/null @@ -1,160 +0,0 @@ -import { expect } from 'chai'; -import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; -import { migration } from '../../../../plugins/deployment_manager/Migration'; -import { calldata, proposal, exp } from '../../../../src/deploy'; -import { utils } from 'ethers'; -import { AggregatorV3Interface } from '../../../../build/types'; - -const ETH_USD_PRICE_FEED = '0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70'; - -const WSTETH_ADDRESS = '0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452'; -const WSTETH_STETH_PRICE_FEED_ADDRESS = '0xB88BAc61a4Ca37C43a3725912B1f472c9A5bc061'; - -const FEED_DECIMALS = 8; -const blockToFetch = 36000000; - -let newWstETHPriceFeed: string; -let oldWstETHPriceFeed: string; - -export default migration('1761125221_upgrade_to_capo_price_feeds', { - async prepare(deploymentManager: DeploymentManager) { - const { timelock } = await deploymentManager.getContracts(); - const blockToFetchTimestamp = (await deploymentManager.hre.ethers.provider.getBlock(blockToFetch))!.timestamp; - - //1. wstEth - const rateProviderWstEth = await deploymentManager.existing('wstEth:priceFeed', WSTETH_STETH_PRICE_FEED_ADDRESS, 'base', 'contracts/capo/contracts/interfaces/AggregatorV3Interface.sol:AggregatorV3Interface') as AggregatorV3Interface; - const [, currentRatioWstEth] = await rateProviderWstEth.latestRoundData({ blockTag: blockToFetch }); - - const wstEthCapoPriceFeed = await deploymentManager.deploy( - 'wstETH:priceFeed', - 'capo/contracts/ChainlinkCorrelatedAssetsPriceOracle.sol', - [ - timelock.address, - ETH_USD_PRICE_FEED, - WSTETH_STETH_PRICE_FEED_ADDRESS, - 'wstETH / USD CAPO Price Feed', - FEED_DECIMALS, - 3600, - { - snapshotRatio: currentRatioWstEth, - snapshotTimestamp: blockToFetchTimestamp, - maxYearlyRatioGrowthPercent: exp(0.0404, 4) - } - ], - true - ); - - return { - wstEthCapoPriceFeedAddress: wstEthCapoPriceFeed.address - }; - }, - - async enact(deploymentManager: DeploymentManager, govDeploymentManager: DeploymentManager, { - wstEthCapoPriceFeedAddress - }) { - newWstETHPriceFeed = wstEthCapoPriceFeedAddress; - - const trace = deploymentManager.tracer(); - - const { - configurator, - comet, - bridgeReceiver, - cometAdmin - } = await deploymentManager.getContracts(); - - const { - governor, - baseL1CrossDomainMessenger - } = await govDeploymentManager.getContracts(); - - const updateWstEthPriceFeedCalldata = await calldata( - configurator.populateTransaction.updateAssetPriceFeed( - comet.address, - WSTETH_ADDRESS, - wstEthCapoPriceFeedAddress - ) - ); - - const deployAndUpgradeToCalldata = await calldata( - cometAdmin.populateTransaction.deployAndUpgradeTo( - configurator.address, - comet.address - ) - ); - - const l2ProposalData = utils.defaultAbiCoder.encode( - ['address[]', 'uint256[]', 'string[]', 'bytes[]'], - [ - [configurator.address, cometAdmin.address], - [0, 0], - ['updateAssetPriceFeed(address,address,address)', 'deployAndUpgradeTo(address,address)'], - [updateWstEthPriceFeedCalldata, deployAndUpgradeToCalldata], - ] - ); - - [,, oldWstETHPriceFeed] = await comet.getAssetInfoByAddress(WSTETH_ADDRESS); - - const mainnetActions = [ - { - contract: baseL1CrossDomainMessenger, - signature: 'sendMessage(address,bytes,uint32)', - args: [ - bridgeReceiver.address, - l2ProposalData, - 3_000_000 - ] - }, - ]; - - const description = `# Update wstETH price feed in cAEROv3 on Base with CAPO implementation. - -## Proposal summary - -This proposal updates existing price feeds for wstETH on the AERO market on Base. - -### CAPO summary - -CAPO is a price oracle adapter designed to support assets that grow gradually relative to a base asset - such as liquid staking tokens that accumulate yield over time. It provides a mechanism to track this expected growth while protecting downstream protocol from sudden or manipulated price spikes. wstETH price feed is updated to their CAPO implementations. - -Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1038) and [forum discussion for CAPO](https://www.comp.xyz/t/woof-correlated-assets-price-oracle-capo/6245). - -### CAPO audit - -CAPO has been audited by [OpenZeppelin](https://www.comp.xyz/t/capo-price-feed-audit/6631, as well as the LST / LRT implementation [here](https://www.comp.xyz/t/capo-lst-lrt-audit/7118). - -## Proposal actions - -The first action updates wstETH price feed to the CAPO implementation. This sends the encoded 'updateAssetPriceFeed' and 'deployAndUpgradeTo' calls across the bridge to the governance receiver on Base. -`; - - const txn = await deploymentManager.retry(async () => - trace( - await governor.propose(...(await proposal(mainnetActions, description))) - ) - ); - const event = txn.events.find( - (event: { event: string }) => event.event === 'ProposalCreated' - ); - const [proposalId] = event.args; - trace(`Created proposal ${proposalId}.`); - }, - - async enacted(deploymentManager: DeploymentManager): Promise { - return true; - }, - - async verify(deploymentManager: DeploymentManager) { - const { comet, configurator } = await deploymentManager.getContracts(); - - const wstETHIndexInComet = await configurator.getAssetIndex(comet.address, WSTETH_ADDRESS); - - // Check if the price feeds are set correctly. - const wstETHInCometInfo = await comet.getAssetInfoByAddress(WSTETH_ADDRESS); - const wstETHInConfiguratorInfoWETHComet = (await configurator.getConfiguration(comet.address)).assetConfigs[wstETHIndexInComet]; - - expect(wstETHInCometInfo.priceFeed).to.eq(newWstETHPriceFeed); - expect(wstETHInConfiguratorInfoWETHComet.priceFeed).to.eq(newWstETHPriceFeed); - expect(await comet.getPrice(newWstETHPriceFeed)).to.equal(await comet.getPrice(oldWstETHPriceFeed)); - }, -}); diff --git a/deployments/base/usdbc/migrations/1735299714_update_comet_to_support_more_collaterals.ts b/deployments/base/usdbc/migrations/1735299714_update_comet_to_support_more_collaterals.ts deleted file mode 100644 index 39a771da3..000000000 --- a/deployments/base/usdbc/migrations/1735299714_update_comet_to_support_more_collaterals.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { expect } from 'chai'; -import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; -import { migration } from '../../../../plugins/deployment_manager/Migration'; -import { calldata, proposal } from '../../../../src/deploy'; -import { ethers } from 'ethers'; -import { Contract } from 'ethers'; -import { utils } from 'ethers'; - -let newCometExtAddress: string; - -export default migration('1735299714_update_comet_to_support_more_collaterals', { - async prepare(deploymentManager: DeploymentManager) { - const _assetListFactory = await deploymentManager.deploy( - 'assetListFactory', - 'AssetListFactory.sol', - [] - ); - - const cometFactoryWithExtendedAssetList = await deploymentManager.deploy( - 'cometFactoryWithExtendedAssetList', - 'CometFactoryWithExtendedAssetList.sol', - [] - ); - const { - comet - } = await deploymentManager.getContracts(); - - const extensionDelegate = new Contract( - await comet.extensionDelegate(), - [ - 'function name() external view returns (string)', - 'function symbol() external view returns (string)', - ], - await deploymentManager.getSigner() - ); - const name = await extensionDelegate.name(); - const symbol = await extensionDelegate.symbol(); - - const _newCometExt = await deploymentManager.deploy( - 'CometExtAssetList', - 'CometExtAssetList.sol', - [ - { - name32: ethers.utils.formatBytes32String(name), - symbol32: ethers.utils.formatBytes32String(symbol) - }, - _assetListFactory.address - ], - true - ); - return { - cometFactoryWithExtendedAssetList: cometFactoryWithExtendedAssetList.address, - newCometExt: _newCometExt.address - }; - }, - - async enact(deploymentManager: DeploymentManager, govDeploymentManager, { - cometFactoryWithExtendedAssetList, - newCometExt, - }) { - - const trace = deploymentManager.tracer(); - const { - comet, - cometAdmin, - configurator, - bridgeReceiver, - } = await deploymentManager.getContracts(); - - const { - baseL1CrossDomainMessenger, - governor - } = await govDeploymentManager.getContracts(); - - newCometExtAddress = newCometExt; - - const setFactoryCalldata = await calldata( - configurator.populateTransaction.setFactory(comet.address, cometFactoryWithExtendedAssetList) - ); - - const setExtensionDelegateCalldata = await calldata( - configurator.populateTransaction.setExtensionDelegate(comet.address, newCometExt) - ); - - const deployAndUpgradeToCalldata = utils.defaultAbiCoder.encode( - ['address', 'address'], - [configurator.address, comet.address] - ); - - const l2ProposalData = utils.defaultAbiCoder.encode( - ['address[]', 'uint256[]', 'string[]', 'bytes[]'], - [ - [configurator.address, configurator.address, cometAdmin.address], - [0, 0, 0], - [ - 'setFactory(address,address)', - 'setExtensionDelegate(address,address)', - 'deployAndUpgradeTo(address,address)', - ], - [setFactoryCalldata, setExtensionDelegateCalldata, deployAndUpgradeToCalldata], - ] - ); - - const mainnetActions = [ - // Send the proposal to the L2 bridge - { - contract: baseL1CrossDomainMessenger, - signature: 'sendMessage(address,bytes,uint32)', - args: [bridgeReceiver.address, l2ProposalData, 3_000_000] - }, - ]; - - const description = 'DESCRIPTION'; - const txn = await deploymentManager.retry(async () => - trace( - await governor.propose(...(await proposal(mainnetActions, description))) - ) - ); - - const event = txn.events.find( - (event) => event.event === 'ProposalCreated' - ); - const [proposalId] = event.args; - trace(`Created proposal ${proposalId}.`); - }, - - async enacted(): Promise { - return true; - }, - - async verify(deploymentManager: DeploymentManager) { - const { comet } = await deploymentManager.getContracts(); - - const cometNew = new Contract( - comet.address, - [ - 'function assetList() external view returns (address)', - ], - await deploymentManager.getSigner() - ); - - const assetListAddress = await cometNew.assetList(); - - expect(assetListAddress).to.not.be.equal(ethers.constants.AddressZero); - - expect(await comet.extensionDelegate()).to.be.equal(newCometExtAddress); - }, -}); From eadf6f42bd730f3aba5b5e7b560f3876c610f608 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Fri, 22 May 2026 15:45:23 +0300 Subject: [PATCH 52/65] fix: undo delition --- ...pdate_comet_to_support_more_collaterals.ts | 148 ++++++++ .../1761228877_upgrade_to_capo_price_feeds.ts | 319 ------------------ 2 files changed, 148 insertions(+), 319 deletions(-) create mode 100644 deployments/base/usdbc/migrations/1735299714_update_comet_to_support_more_collaterals.ts delete mode 100644 deployments/base/weth/migrations/1761228877_upgrade_to_capo_price_feeds.ts diff --git a/deployments/base/usdbc/migrations/1735299714_update_comet_to_support_more_collaterals.ts b/deployments/base/usdbc/migrations/1735299714_update_comet_to_support_more_collaterals.ts new file mode 100644 index 000000000..39a771da3 --- /dev/null +++ b/deployments/base/usdbc/migrations/1735299714_update_comet_to_support_more_collaterals.ts @@ -0,0 +1,148 @@ +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { calldata, proposal } from '../../../../src/deploy'; +import { ethers } from 'ethers'; +import { Contract } from 'ethers'; +import { utils } from 'ethers'; + +let newCometExtAddress: string; + +export default migration('1735299714_update_comet_to_support_more_collaterals', { + async prepare(deploymentManager: DeploymentManager) { + const _assetListFactory = await deploymentManager.deploy( + 'assetListFactory', + 'AssetListFactory.sol', + [] + ); + + const cometFactoryWithExtendedAssetList = await deploymentManager.deploy( + 'cometFactoryWithExtendedAssetList', + 'CometFactoryWithExtendedAssetList.sol', + [] + ); + const { + comet + } = await deploymentManager.getContracts(); + + const extensionDelegate = new Contract( + await comet.extensionDelegate(), + [ + 'function name() external view returns (string)', + 'function symbol() external view returns (string)', + ], + await deploymentManager.getSigner() + ); + const name = await extensionDelegate.name(); + const symbol = await extensionDelegate.symbol(); + + const _newCometExt = await deploymentManager.deploy( + 'CometExtAssetList', + 'CometExtAssetList.sol', + [ + { + name32: ethers.utils.formatBytes32String(name), + symbol32: ethers.utils.formatBytes32String(symbol) + }, + _assetListFactory.address + ], + true + ); + return { + cometFactoryWithExtendedAssetList: cometFactoryWithExtendedAssetList.address, + newCometExt: _newCometExt.address + }; + }, + + async enact(deploymentManager: DeploymentManager, govDeploymentManager, { + cometFactoryWithExtendedAssetList, + newCometExt, + }) { + + const trace = deploymentManager.tracer(); + const { + comet, + cometAdmin, + configurator, + bridgeReceiver, + } = await deploymentManager.getContracts(); + + const { + baseL1CrossDomainMessenger, + governor + } = await govDeploymentManager.getContracts(); + + newCometExtAddress = newCometExt; + + const setFactoryCalldata = await calldata( + configurator.populateTransaction.setFactory(comet.address, cometFactoryWithExtendedAssetList) + ); + + const setExtensionDelegateCalldata = await calldata( + configurator.populateTransaction.setExtensionDelegate(comet.address, newCometExt) + ); + + const deployAndUpgradeToCalldata = utils.defaultAbiCoder.encode( + ['address', 'address'], + [configurator.address, comet.address] + ); + + const l2ProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [configurator.address, configurator.address, cometAdmin.address], + [0, 0, 0], + [ + 'setFactory(address,address)', + 'setExtensionDelegate(address,address)', + 'deployAndUpgradeTo(address,address)', + ], + [setFactoryCalldata, setExtensionDelegateCalldata, deployAndUpgradeToCalldata], + ] + ); + + const mainnetActions = [ + // Send the proposal to the L2 bridge + { + contract: baseL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [bridgeReceiver.address, l2ProposalData, 3_000_000] + }, + ]; + + const description = 'DESCRIPTION'; + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ) + ); + + const event = txn.events.find( + (event) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + const { comet } = await deploymentManager.getContracts(); + + const cometNew = new Contract( + comet.address, + [ + 'function assetList() external view returns (address)', + ], + await deploymentManager.getSigner() + ); + + const assetListAddress = await cometNew.assetList(); + + expect(assetListAddress).to.not.be.equal(ethers.constants.AddressZero); + + expect(await comet.extensionDelegate()).to.be.equal(newCometExtAddress); + }, +}); diff --git a/deployments/base/weth/migrations/1761228877_upgrade_to_capo_price_feeds.ts b/deployments/base/weth/migrations/1761228877_upgrade_to_capo_price_feeds.ts deleted file mode 100644 index 56cffa4f0..000000000 --- a/deployments/base/weth/migrations/1761228877_upgrade_to_capo_price_feeds.ts +++ /dev/null @@ -1,319 +0,0 @@ -import { expect } from 'chai'; -import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; -import { migration } from '../../../../plugins/deployment_manager/Migration'; -import { calldata, proposal, exp } from '../../../../src/deploy'; -import { utils } from 'ethers'; -import { AggregatorV3Interface } from '../../../../build/types'; - -const WSTETH_ADDRESS = '0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452'; -const WSTETH_STETH_PRICE_FEED_ADDRESS = '0xB88BAc61a4Ca37C43a3725912B1f472c9A5bc061'; - -const EZETH_ADDRESS = '0x2416092f143378750bb29b79ed961ab195cceea5'; -const EZETH_TO_ETH_PRICE_FEED_ADDRESS = '0xC4300B7CF0646F0Fe4C5B2ACFCCC4dCA1346f5d8'; - -const WRSETH_ADDRESS = '0xEDfa23602D0EC14714057867A78d01e94176BEA0'; -const WRSETH_ORACLE = '0xe8dD07CCf5BC4922424140E44Eb970F5950725ef'; - -const WEETH_ADDRESS = '0x04C0599Ae5A44757c0af6F9eC3b93da8976c150A'; -const WEETH_STETH_PRICE_FEED_ADDRESS = '0x35e9D7001819Ea3B39Da906aE6b06A62cfe2c181'; - -const blockToFetch = 36000000; - -let newWstETHToETHPriceFeed: string; -let newEzETHToETHPriceFeed: string; -let newWrsEthToETHPriceFeed: string; -let newWeEthToETHPriceFeed: string; - -let oldWstETHToETHPriceFeed: string; -let oldEzETHToETHPriceFeed: string; -let oldWrsEthToETHPriceFeed: string; -let oldWeEthToETHPriceFeed: string; - -const FEED_DECIMALS = 8; -export default migration('1761228877_upgrade_to_capo_price_feeds', { - async prepare(deploymentManager: DeploymentManager) { - const { timelock } = await deploymentManager.getContracts(); - const blockToFetchTimestamp = (await deploymentManager.hre.ethers.provider.getBlock(blockToFetch))!.timestamp; - const constantPriceFeed = await deploymentManager.fromDep('WETH:priceFeed', 'base', 'weth'); - - //1. wstEth - const rateProviderWstEth = await deploymentManager.existing('wstETH:_rateProvider', WSTETH_STETH_PRICE_FEED_ADDRESS, 'base', 'contracts/capo/contracts/interfaces/AggregatorV3Interface.sol:AggregatorV3Interface') as AggregatorV3Interface; - const [, currentRatioWstEth] = await rateProviderWstEth.latestRoundData({blockTag: blockToFetch}); - - const wstEthCapoPriceFeed = await deploymentManager.deploy( - 'wstETH:priceFeed', - 'capo/contracts/ChainlinkCorrelatedAssetsPriceOracle.sol', - [ - timelock.address, - constantPriceFeed.address, - WSTETH_STETH_PRICE_FEED_ADDRESS, - 'wstETH / ETH CAPO Price Feed', - FEED_DECIMALS, - 3600, - { - snapshotRatio: currentRatioWstEth, - snapshotTimestamp: blockToFetchTimestamp, - maxYearlyRatioGrowthPercent: exp(0.0404, 4) - } - ], - true - ); - - //2. ezEth - const rateProviderEzEth = await deploymentManager.existing('ezETH:_rateProvider', EZETH_TO_ETH_PRICE_FEED_ADDRESS, 'base', 'contracts/capo/contracts/interfaces/AggregatorV3Interface.sol:AggregatorV3Interface') as AggregatorV3Interface; - const [, currentRatioEzEth] = await rateProviderEzEth.latestRoundData({blockTag: blockToFetch}); - const ezEthCapoPriceFeed = await deploymentManager.deploy( - 'ezETH:priceFeed', - 'capo/contracts/ChainlinkCorrelatedAssetsPriceOracle.sol', - [ - timelock.address, - constantPriceFeed.address, - EZETH_TO_ETH_PRICE_FEED_ADDRESS, - 'ezETH / ETH CAPO Price Feed', - FEED_DECIMALS, - 3600, - { - snapshotRatio: currentRatioEzEth, - snapshotTimestamp: blockToFetchTimestamp, - maxYearlyRatioGrowthPercent: exp(0.0707, 4) - } - ], - true - ); - - const rateProviderRsEth = await deploymentManager.existing('rsETH:_rateProvider', WRSETH_ORACLE, 'base', 'contracts/capo/contracts/interfaces/AggregatorV3Interface.sol:AggregatorV3Interface') as AggregatorV3Interface; - const [, currentRatioWrsEth] = await rateProviderRsEth.latestRoundData({blockTag: blockToFetch}); - const rsEthCapoPriceFeed = await deploymentManager.deploy( - 'rsETH:priceFeed', - 'capo/contracts/ChainlinkCorrelatedAssetsPriceOracle.sol', - [ - timelock.address, - constantPriceFeed.address, - WRSETH_ORACLE, - 'rsETH / ETH CAPO Price Feed', - FEED_DECIMALS, - 3600, - { - snapshotRatio: currentRatioWrsEth, - snapshotTimestamp: blockToFetchTimestamp, - maxYearlyRatioGrowthPercent: exp(0.0554, 4) - } - ], - true - ); - - - const rateProviderWeEth = await deploymentManager.existing('weETH:_rateProvider', WEETH_STETH_PRICE_FEED_ADDRESS, 'base', 'contracts/capo/contracts/interfaces/AggregatorV3Interface.sol:AggregatorV3Interface') as AggregatorV3Interface; - const [, currentRatioWeEth] = await rateProviderWeEth.latestRoundData({blockTag: blockToFetch}); - const weEthCapoPriceFeed = await deploymentManager.deploy( - 'weETH:priceFeed', - 'capo/contracts/ChainlinkCorrelatedAssetsPriceOracle.sol', - [ - timelock.address, - constantPriceFeed.address, - WEETH_STETH_PRICE_FEED_ADDRESS, - 'weETH / ETH CAPO Price Feed', - FEED_DECIMALS, - 3600, - { - snapshotRatio: currentRatioWeEth, - snapshotTimestamp: blockToFetchTimestamp, - maxYearlyRatioGrowthPercent: exp(0.0323, 4) - } - ], - true - ); - - return { - wstEthCapoPriceFeedAddress: wstEthCapoPriceFeed.address, - ezEthCapoPriceFeedAddress: ezEthCapoPriceFeed.address, - rsEthCapoPriceFeedAddress: rsEthCapoPriceFeed.address, - weEthCapoPriceFeedAddress: weEthCapoPriceFeed.address - }; - }, - - async enact(deploymentManager: DeploymentManager, govDeploymentManager, { - wstEthCapoPriceFeedAddress, - ezEthCapoPriceFeedAddress, - rsEthCapoPriceFeedAddress, - weEthCapoPriceFeedAddress - }) { - - newWstETHToETHPriceFeed = wstEthCapoPriceFeedAddress; - newEzETHToETHPriceFeed = ezEthCapoPriceFeedAddress; - newWrsEthToETHPriceFeed = rsEthCapoPriceFeedAddress; - newWeEthToETHPriceFeed = weEthCapoPriceFeedAddress; - - const trace = deploymentManager.tracer(); - - const { - configurator, - comet, - bridgeReceiver, - cometAdmin - } = await deploymentManager.getContracts(); - - const { - governor, - baseL1CrossDomainMessenger - } = await govDeploymentManager.getContracts(); - - const updateEzEthPriceFeedCalldata = await calldata( - configurator.populateTransaction.updateAssetPriceFeed( - comet.address, - EZETH_ADDRESS, - ezEthCapoPriceFeedAddress - ) - ); - - const updateWstEthPriceFeedCalldata = await calldata( - configurator.populateTransaction.updateAssetPriceFeed( - comet.address, - WSTETH_ADDRESS, - wstEthCapoPriceFeedAddress - ) - ); - - const updateRsEthPriceFeedCalldata = await calldata( - configurator.populateTransaction.updateAssetPriceFeed( - comet.address, - WRSETH_ADDRESS, - rsEthCapoPriceFeedAddress - ) - ); - - const updateWeEthPriceFeedCalldata = await calldata( - configurator.populateTransaction.updateAssetPriceFeed( - comet.address, - WEETH_ADDRESS, - weEthCapoPriceFeedAddress - ) - ); - - const deployAndUpgradeToCalldata = utils.defaultAbiCoder.encode( - ['address', 'address'], - [configurator.address, comet.address] - ); - - const l2ProposalData = utils.defaultAbiCoder.encode( - ['address[]', 'uint256[]', 'string[]', 'bytes[]'], - [ - [ - configurator.address, - configurator.address, - configurator.address, - configurator.address, - cometAdmin.address - ], - [0, 0, 0, 0, 0], - [ - 'updateAssetPriceFeed(address,address,address)', - 'updateAssetPriceFeed(address,address,address)', - 'updateAssetPriceFeed(address,address,address)', - 'updateAssetPriceFeed(address,address,address)', - 'deployAndUpgradeTo(address,address)' - ], - [ - updateWstEthPriceFeedCalldata, - updateEzEthPriceFeedCalldata, - updateRsEthPriceFeedCalldata, - updateWeEthPriceFeedCalldata, - deployAndUpgradeToCalldata - ], - ] - ); - - [,, oldWstETHToETHPriceFeed] = await comet.getAssetInfoByAddress(WSTETH_ADDRESS); - [,, oldEzETHToETHPriceFeed] = await comet.getAssetInfoByAddress(EZETH_ADDRESS); - [,, oldWrsEthToETHPriceFeed] = await comet.getAssetInfoByAddress(WRSETH_ADDRESS); - [,, oldWeEthToETHPriceFeed] = await comet.getAssetInfoByAddress(WEETH_ADDRESS); - - const mainnetActions = [ - { - contract: baseL1CrossDomainMessenger, - signature: 'sendMessage(address,bytes,uint32)', - args: [ - bridgeReceiver.address, - l2ProposalData, - 3_000_000 - ] - }, - ]; - - const description = `# Update price feeds in cWETHv3 on Base with CAPO implementation. - -## Proposal summary - -This proposal updates existing price feeds for wstETH, ezETH, rsETH, and weETH on the WETH market on Base. - -### CAPO summary - -CAPO is a price oracle adapter designed to support assets that grow gradually relative to a base asset - such as liquid staking tokens that accumulate yield over time. It provides a mechanism to track this expected growth while protecting downstream protocol from sudden or manipulated price spikes. wstETH, ezETH, rsETH, and weETH price feeds are updated to their CAPO implementations. - -Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1040) and [forum discussion for CAPO](https://www.comp.xyz/t/woof-correlated-assets-price-oracle-capo/6245). - -### CAPO audit - -CAPO has been audited by [OpenZeppelin](https://www.comp.xyz/t/capo-price-feed-audit/6631, as well as the LST / LRT implementation [here](https://www.comp.xyz/t/capo-lst-lrt-audit/7118). - -## Proposal actions - -The first action updates wstETH, ezETH, rsETH, and weETH price feeds to the CAPO implementation. This sends the encoded 'updateAssetPriceFeed' and 'deployAndUpgradeTo' calls across the bridge to the governance receiver on Base. -`; - const txn = await govDeploymentManager.retry(async () => - trace( - await governor.propose(...(await proposal(mainnetActions, description))) - ) - ); - - const event = txn.events.find( - (event: { event: string }) => event.event === 'ProposalCreated' - ); - const [proposalId] = event.args; - trace(`Created proposal ${proposalId}.`); - }, - - async enacted(deploymentManager: DeploymentManager): Promise { - return true; - }, - - async verify(deploymentManager: DeploymentManager) { - const { comet, configurator } = await deploymentManager.getContracts(); - - // 1. wstETH - const wstETHIndexInComet = await configurator.getAssetIndex(comet.address, WSTETH_ADDRESS); - const wstETHInCometInfo = await comet.getAssetInfoByAddress(WSTETH_ADDRESS); - const wstETHInConfiguratorInfoWETHComet = (await configurator.getConfiguration(comet.address)).assetConfigs[wstETHIndexInComet]; - - expect(wstETHInCometInfo.priceFeed).to.eq(newWstETHToETHPriceFeed); - expect(wstETHInConfiguratorInfoWETHComet.priceFeed).to.eq(newWstETHToETHPriceFeed); - expect(await comet.getPrice(newWstETHToETHPriceFeed)).to.be.closeTo(await comet.getPrice(oldWstETHToETHPriceFeed), 1e6); - - // 2. ezETH - const ezETHIndexInComet = await configurator.getAssetIndex(comet.address, EZETH_ADDRESS); - const ezETHInCometInfo = await comet.getAssetInfoByAddress(EZETH_ADDRESS); - const ezETHInConfiguratorInfoWETHComet = (await configurator.getConfiguration(comet.address)).assetConfigs[ezETHIndexInComet]; - - expect(ezETHInCometInfo.priceFeed).to.eq(newEzETHToETHPriceFeed); - expect(ezETHInConfiguratorInfoWETHComet.priceFeed).to.eq(newEzETHToETHPriceFeed); - expect(await comet.getPrice(newEzETHToETHPriceFeed)).to.equal(await comet.getPrice(oldEzETHToETHPriceFeed)); - - // 3. wrsETH - const wrsETHIndexInComet = await configurator.getAssetIndex(comet.address, WRSETH_ADDRESS); - const wrsETHInCometInfo = await comet.getAssetInfoByAddress(WRSETH_ADDRESS); - const wrsETHInConfiguratorInfoWETHComet = (await configurator.getConfiguration(comet.address)).assetConfigs[wrsETHIndexInComet]; - - expect(wrsETHInCometInfo.priceFeed).to.eq(newWrsEthToETHPriceFeed); - expect(wrsETHInConfiguratorInfoWETHComet.priceFeed).to.eq(newWrsEthToETHPriceFeed); - expect(await comet.getPrice(newWrsEthToETHPriceFeed)).to.equal(await comet.getPrice(oldWrsEthToETHPriceFeed)); - - // 4. weETH - const weETHIndexInComet = await configurator.getAssetIndex(comet.address, WEETH_ADDRESS); - const weETHInCometInfo = await comet.getAssetInfoByAddress(WEETH_ADDRESS); - const weETHInConfiguratorInfoWETHComet = (await configurator.getConfiguration(comet.address)).assetConfigs[weETHIndexInComet]; - - expect(weETHInCometInfo.priceFeed).to.eq(newWeEthToETHPriceFeed); - expect(weETHInConfiguratorInfoWETHComet.priceFeed).to.eq(newWeEthToETHPriceFeed); - expect(await comet.getPrice(newWeEthToETHPriceFeed)).to.equal(await comet.getPrice(oldWeEthToETHPriceFeed)); - }, -}); From 8bea7de45a6aa739e21b17fd375891f27c8a34c1 Mon Sep 17 00:00:00 2001 From: MishaShWoof Date: Mon, 1 Jun 2026 13:30:35 +0300 Subject: [PATCH 53/65] Next Develop Update (#433) * feat: simulation for proposal, that target multiple l2 chains * fix: clean up * feat: tenderly simulations for multiple messages for one network * fix: seacrest and tenderly simulation fix * multiple migrations and some fixes to l2 -> L1 simulation * fix: speed up scenario run * fix: scroll fix and a bunch of new whales * fix: update forge and scenario config * Curent Dev (#1127) Multiple previously passed migrations, along with various fixes and improvements. --- .github/workflows/deploy-market.yaml | 4 +- .github/workflows/enact-migration.yaml | 4 +- .github/workflows/prepare-migration.yaml | 4 +- .github/workflows/run-forge-tests.yaml | 2 +- .../1778758319_update_supply_caps_on_l2.ts | 479 +++++++++ .../1778758319_update_supply_caps_on_l2.ts | 212 ++++ .../1778758319_update_supply_caps_on_l2.ts | 148 +++ .../1775661752_withdraw_reserves.ts | 908 ++++++++++++++++++ .../1776768296_update_curve_params_on_l2.ts | 483 ++++++++++ ...40217_update_rseth_pricefeeds_across_l2.ts | 441 +++++++++ .../1778758319_update_supply_caps_on_l2.ts | 861 +++++++++++++++++ .../1779114960_update_supply_caps_on_l2.ts | 580 +++++++++++ .../1778758319_update_supply_caps_on_l2.ts | 147 +++ .../1779114960_update_supply_caps_on_l2.ts | 251 +++++ .../1779114960_update_supply_caps_on_l2.ts | 203 ++++ deployments/relations.ts | 11 +- .../1779114960_update_supply_caps_on_l2.ts | 205 ++++ hardhat.config.ts | 12 +- .../deployment_manager/DeploymentManager.ts | 15 + plugins/deployment_manager/Import.ts | 2 +- plugins/import/blockscout.ts | 5 +- plugins/scenario/utils/hreForBase.ts | 22 +- scenario/constraints/ProposalConstraint.ts | 22 +- scenario/utils/index.ts | 182 ++-- scenario/utils/isBridgeProposal.ts | 271 +++--- scenario/utils/relayArbitrumMessage.ts | 203 +++- scenario/utils/relayBaseMessage.ts | 121 ++- scenario/utils/relayLineaMessage.ts | 9 +- scenario/utils/relayMantleMessage.ts | 5 +- scenario/utils/relayMessage.ts | 28 +- scenario/utils/relayOptimismMessage.ts | 180 +++- scenario/utils/relayScrollMessage.ts | 4 +- scenario/utils/relayUnichainMessage.ts | 25 +- scenario/utils/scenarioHelper.ts | 13 +- src/deploy/index.ts | 24 + tasks/deployment_manager/task.ts | 4 +- 36 files changed, 5765 insertions(+), 325 deletions(-) create mode 100644 deployments/arbitrum/usdc/migrations/1778758319_update_supply_caps_on_l2.ts create mode 100644 deployments/base/usdc/migrations/1778758319_update_supply_caps_on_l2.ts create mode 100644 deployments/linea/weth/migrations/1778758319_update_supply_caps_on_l2.ts create mode 100644 deployments/mainnet/usdc/migrations/1775661752_withdraw_reserves.ts create mode 100644 deployments/mainnet/usdc/migrations/1776768296_update_curve_params_on_l2.ts create mode 100644 deployments/mainnet/usdc/migrations/1776940217_update_rseth_pricefeeds_across_l2.ts create mode 100644 deployments/mainnet/usdc/migrations/1778758319_update_supply_caps_on_l2.ts create mode 100644 deployments/mainnet/usdc/migrations/1779114960_update_supply_caps_on_l2.ts create mode 100644 deployments/mantle/usde/migrations/1778758319_update_supply_caps_on_l2.ts create mode 100644 deployments/optimism/usdc/migrations/1779114960_update_supply_caps_on_l2.ts create mode 100644 deployments/polygon/usdc/migrations/1779114960_update_supply_caps_on_l2.ts create mode 100644 deployments/unichain/usdc/migrations/1779114960_update_supply_caps_on_l2.ts diff --git a/.github/workflows/deploy-market.yaml b/.github/workflows/deploy-market.yaml index c2066d7ec..ccf04b85e 100644 --- a/.github/workflows/deploy-market.yaml +++ b/.github/workflows/deploy-market.yaml @@ -57,7 +57,7 @@ jobs: LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} steps: - name: Seacrest - uses: hayesgm/seacrest@af229b0a00b73cb6fa9940a836a62fa3b918fd77 + uses: hayesgm/seacrest@1578d5b4cf165e97e11d3debf039db09a497211f with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" @@ -66,7 +66,7 @@ jobs: if: github.event.inputs.eth_pk == '' - name: Seacrest (governance network) - uses: hayesgm/seacrest@af229b0a00b73cb6fa9940a836a62fa3b918fd77 + uses: hayesgm/seacrest@1578d5b4cf165e97e11d3debf039db09a497211f with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ vars.GOV_NETWORK }}" diff --git a/.github/workflows/enact-migration.yaml b/.github/workflows/enact-migration.yaml index 73b48a0cb..b521a5289 100644 --- a/.github/workflows/enact-migration.yaml +++ b/.github/workflows/enact-migration.yaml @@ -101,7 +101,7 @@ jobs: echo "TENDERLY_ACCESS_KEY=$TENDERLY_ACCESS_KEY" >> "$GITHUB_ENV" - name: Seacrest - uses: hayesgm/seacrest@af229b0a00b73cb6fa9940a836a62fa3b918fd77 + uses: hayesgm/seacrest@1578d5b4cf165e97e11d3debf039db09a497211f with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" @@ -110,7 +110,7 @@ jobs: if: github.event.inputs.eth_pk == '' - name: Seacrest (governance network) - uses: hayesgm/seacrest@af229b0a00b73cb6fa9940a836a62fa3b918fd77 + uses: hayesgm/seacrest@1578d5b4cf165e97e11d3debf039db09a497211f with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ vars.GOV_NETWORK }}" diff --git a/.github/workflows/prepare-migration.yaml b/.github/workflows/prepare-migration.yaml index 27392ffcc..2cac15e4c 100644 --- a/.github/workflows/prepare-migration.yaml +++ b/.github/workflows/prepare-migration.yaml @@ -71,7 +71,7 @@ jobs: echo "No governance network for selected network" ;; esac - name: Seacrest - uses: hayesgm/seacrest@af229b0a00b73cb6fa9940a836a62fa3b918fd77 + uses: hayesgm/seacrest@1578d5b4cf165e97e11d3debf039db09a497211f with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" @@ -80,7 +80,7 @@ jobs: if: github.event.inputs.eth_pk == '' - name: Seacrest (governance network) - uses: hayesgm/seacrest@af229b0a00b73cb6fa9940a836a62fa3b918fd77 + uses: hayesgm/seacrest@1578d5b4cf165e97e11d3debf039db09a497211f with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ vars.GOV_NETWORK }}" diff --git a/.github/workflows/run-forge-tests.yaml b/.github/workflows/run-forge-tests.yaml index 1d1c10283..050840763 100644 --- a/.github/workflows/run-forge-tests.yaml +++ b/.github/workflows/run-forge-tests.yaml @@ -13,7 +13,7 @@ jobs: submodules: recursive - name: Install Foundry - uses: onbjerg/foundry-toolchain@v1 + uses: foundry-rs/foundry-toolchain@v1 with: version: nightly diff --git a/deployments/arbitrum/usdc/migrations/1778758319_update_supply_caps_on_l2.ts b/deployments/arbitrum/usdc/migrations/1778758319_update_supply_caps_on_l2.ts new file mode 100644 index 000000000..611a949c1 --- /dev/null +++ b/deployments/arbitrum/usdc/migrations/1778758319_update_supply_caps_on_l2.ts @@ -0,0 +1,479 @@ +import { expect } from 'chai'; +import { Contract, utils } from 'ethers'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { exp, proposal } from '../../../../src/deploy'; +import { applyL1ToL2Alias, estimateL2Transaction } from '../../../../scenario/utils/arbitrumUtils'; + +/* +// Arbitrum + +Arbitrum USDC Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +tETH 50 0 0.26% 0 Rule 1 +tBTC 40 1 3.23% 0 Rule 1 (see note) +ezETH 1,400 78 5.59% 102 Rule 2 (~31% buffer) +GMX 120,000 1,997 1.66% 2,596 Rule 2 (~30% buffer) +ARB 16,000,000 1,497,565 9.36% 1,946,834 Rule 2 (~30% buffer) + +Arbitrum USDC.e Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +GMX 25,000 3 0.01% 0 Rule 1 +ARB 2,000,000 22,962 1.15% 29,851 Rule 2 (~30% buffer) + +Arbitrum USDT Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +tETH 25 0 0.01% 0 Rule 1 +tBTC 80 2 2.68% 3 Rule 2 (integer-rounded buffer) +GMX 50,000 2,099 4.20% 2,729 Rule 2 (~30% buffer) +ARB 7,500,000 349,311 4.66% 454,105 Rule 2 (~30% buffer) + +Arbitrum WETH Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +tETH 25 0 0.61% 0 Rule 1 +rETH 3,750 5 0.14% 0 Rule 1 +weETH 24,000 585 2.44% 760 Rule 2 (~30% buffer) +ezETH 12,000 447 3.73% 582 Rule 2 (~30% buffer) + +*/ + +const cometConfig = { + Arbitrum: { + USDC: { + address: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf', + }, + USDCe: { + address: '0xA5EDBDD9646f8dFF606d7448e414884C7d905dCA', + }, + USDT: { + address: '0xd98Be00b5D27fc98112BdE293e487f8D4cA57d07', + }, + WETH: { + address: '0x6f7D514bbD4aFf3BcD1140B7344b32f063dEe486', + }, + }, +}; + +const supplyCapConfig = { + Arbitrum: { + USDC: { + tETH: { + newCap: 0, + decimals: 18, + }, + tBTC: { + newCap: 0, + decimals: 18, + }, + ezETH: { + newCap: 102, + decimals: 18, + }, + GMX: { + newCap: 2_596, + decimals: 18, + }, + ARB: { + newCap: 1_946_834, + decimals: 18, + }, + }, + USDCe: { + GMX: { + newCap: 0, + decimals: 18, + }, + ARB: { + newCap: 29_851, + decimals: 18, + }, + }, + USDT: { + tETH: { + newCap: 0, + decimals: 18, + }, + tBTC: { + newCap: 3, + decimals: 18, + }, + GMX: { + newCap: 2_729, + decimals: 18, + }, + ARB: { + newCap: 454_105, + decimals: 18, + }, + }, + WETH: { + tETH: { + newCap: 0, + decimals: 18, + }, + rETH: { + newCap: 0, + decimals: 18, + }, + weETH: { + newCap: 760, + decimals: 18, + }, + ezETH: { + newCap: 582, + decimals: 18, + }, + }, + }, +}; + + +export default migration('1778758319_update_supply_caps_on_l2', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager, govDeploymentManager) { + + const trace = deploymentManager.tracer(); + + const { + timelock, + governor, + arbitrumInbox, + } = await govDeploymentManager.getContracts(); + + // Arbitrum + const arbitrumDm = await govDeploymentManager.addBridgedDeploymentManager('arbitrum', 'usdc', deploymentManager.hre); + const { + bridgeReceiver: arbitrumBridgeReceiver, + configurator: arbitrumConfigurator, + cometAdmin: arbitrumCometAdmin, + tETH: arbitrumTETH, + tBTC: arbitrumTBTC, + ezETH: arbitrumEZETH, + GMX: arbitrumGMX, + ARB: arbitrumARB, + timelock: arbitrumTimelock, + } = await arbitrumDm.getContracts(); + + const arbitrumUsdcUpdateTETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDC.address, arbitrumTETH.address, exp(supplyCapConfig.Arbitrum.USDC.tETH.newCap, supplyCapConfig.Arbitrum.USDC.tETH.decimals)]); + const arbitrumUsdcUpdateTBTCSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDC.address, arbitrumTBTC.address, exp(supplyCapConfig.Arbitrum.USDC.tBTC.newCap, supplyCapConfig.Arbitrum.USDC.tBTC.decimals)]); + const arbitrumUsdcUpdateEZETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDC.address, arbitrumEZETH.address, exp(supplyCapConfig.Arbitrum.USDC.ezETH.newCap, supplyCapConfig.Arbitrum.USDC.ezETH.decimals)]); + const arbitrumUsdcUpdateGMXSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDC.address, arbitrumGMX.address, exp(supplyCapConfig.Arbitrum.USDC.GMX.newCap, supplyCapConfig.Arbitrum.USDC.GMX.decimals)]); + const arbitrumUsdcUpdateARBSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDC.address, arbitrumARB.address, exp(supplyCapConfig.Arbitrum.USDC.ARB.newCap, supplyCapConfig.Arbitrum.USDC.ARB.decimals)]); + const arbitrumUsdcDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [arbitrumConfigurator.address, cometConfig.Arbitrum.USDC.address]); + + const arbitrumUsdceUpdateGMXSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDCe.address, arbitrumGMX.address, exp(supplyCapConfig.Arbitrum.USDCe.GMX.newCap, supplyCapConfig.Arbitrum.USDCe.GMX.decimals)]); + const arbitrumUsdceUpdateARBSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDCe.address, arbitrumARB.address, exp(supplyCapConfig.Arbitrum.USDCe.ARB.newCap, supplyCapConfig.Arbitrum.USDCe.ARB.decimals)]); + const arbitrumUsdceDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [arbitrumConfigurator.address, cometConfig.Arbitrum.USDCe.address]); + + const arbitrumProposalData1 = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + // USDC Comet + arbitrumConfigurator.address, // tETH + arbitrumConfigurator.address, // tBTC + arbitrumConfigurator.address, // ezETH + arbitrumConfigurator.address, // GMX + arbitrumConfigurator.address, // ARB + arbitrumCometAdmin.address, + // USDC.e Comet + arbitrumConfigurator.address, // GMX + arbitrumConfigurator.address, // ARB + arbitrumCometAdmin.address, + ], + [ + // USDC Comet + 0, // tETH + 0, // tBTC + 0, // ezETH + 0, // GMX + 0, // ARB + 0, + // USDC.e Comet + 0, // GMX + 0, // ARB + 0, + ], + [ + // USDC Comet + 'updateAssetSupplyCap(address,address,uint128)', // tETH + 'updateAssetSupplyCap(address,address,uint128)', // tBTC + 'updateAssetSupplyCap(address,address,uint128)', // ezETH + 'updateAssetSupplyCap(address,address,uint128)', // GMX + 'updateAssetSupplyCap(address,address,uint128)', // ARB + 'deployAndUpgradeTo(address,address)', + // USDC.e Comet + 'updateAssetSupplyCap(address,address,uint128)', // GMX + 'updateAssetSupplyCap(address,address,uint128)', // ARB + 'deployAndUpgradeTo(address,address)', + ], + [ + // USDC Comet + arbitrumUsdcUpdateTETHSupplyCapCalldata, + arbitrumUsdcUpdateTBTCSupplyCapCalldata, + arbitrumUsdcUpdateEZETHSupplyCapCalldata, + arbitrumUsdcUpdateGMXSupplyCapCalldata, + arbitrumUsdcUpdateARBSupplyCapCalldata, + arbitrumUsdcDeployAndUpgradeToCalldata, + // USDC.e Comet + arbitrumUsdceUpdateGMXSupplyCapCalldata, + arbitrumUsdceUpdateARBSupplyCapCalldata, + arbitrumUsdceDeployAndUpgradeToCalldata, + ], + ] + ); + const createRetryableTicketGasParams1 = await estimateL2Transaction( + { + from: applyL1ToL2Alias(timelock.address), + to: arbitrumBridgeReceiver.address, + data: arbitrumProposalData1 + }, + arbitrumDm + ); + + const arbitrumUsdtUpdateTETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDT.address, arbitrumTETH.address, exp(supplyCapConfig.Arbitrum.USDT.tETH.newCap, supplyCapConfig.Arbitrum.USDT.tETH.decimals)]); + const arbitrumUsdtUpdateTBTCSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDT.address, arbitrumTBTC.address, exp(supplyCapConfig.Arbitrum.USDT.tBTC.newCap, supplyCapConfig.Arbitrum.USDT.tBTC.decimals)]); + const arbitrumUsdtUpdateGMXSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDT.address, arbitrumGMX.address, exp(supplyCapConfig.Arbitrum.USDT.GMX.newCap, supplyCapConfig.Arbitrum.USDT.GMX.decimals)]); + const arbitrumUsdtUpdateARBSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDT.address, arbitrumARB.address, exp(supplyCapConfig.Arbitrum.USDT.ARB.newCap, supplyCapConfig.Arbitrum.USDT.ARB.decimals)]); + const arbitrumUsdtDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [arbitrumConfigurator.address, cometConfig.Arbitrum.USDT.address]); + + const arbitrumDmWeth = await govDeploymentManager.addBridgedDeploymentManager('arbitrum', 'weth', deploymentManager.hre); + const { + rETH: arbitrumRETH, + weETH: arbitrumWeETH, + ezETH: arbitrumEzETH, + } = await arbitrumDmWeth.getContracts(); + + const arbitrumWethUpdateTETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.WETH.address, arbitrumTETH.address, exp(supplyCapConfig.Arbitrum.WETH.tETH.newCap, supplyCapConfig.Arbitrum.WETH.tETH.decimals)]); + const arbitrumWethUpdateRETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.WETH.address, arbitrumRETH.address, exp(supplyCapConfig.Arbitrum.WETH.rETH.newCap, supplyCapConfig.Arbitrum.WETH.rETH.decimals)]); + const arbitrumWethUpdateWeETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.WETH.address, arbitrumWeETH.address, exp(supplyCapConfig.Arbitrum.WETH.weETH.newCap, supplyCapConfig.Arbitrum.WETH.weETH.decimals)]); + const arbitrumWethUpdateEzETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.WETH.address, arbitrumEzETH.address, exp(supplyCapConfig.Arbitrum.WETH.ezETH.newCap, supplyCapConfig.Arbitrum.WETH.ezETH.decimals)]); + const arbitrumWethDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [arbitrumConfigurator.address, cometConfig.Arbitrum.WETH.address]); + + const arbitrumProposalData2 = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + // USDT Comet + arbitrumConfigurator.address, // tETH + arbitrumConfigurator.address, // tBTC + arbitrumConfigurator.address, // GMX + arbitrumConfigurator.address, // ARB + arbitrumCometAdmin.address, + // WETH Comet + arbitrumConfigurator.address, // tETH + arbitrumConfigurator.address, // rETH + arbitrumConfigurator.address, // weETH + arbitrumConfigurator.address, // ezETH + arbitrumCometAdmin.address, + ], + [ + // USDT Comet + 0, // tETH + 0, // tBTC + 0, // GMX + 0, // ARB + 0, + // WETH Comet + 0, // tETH + 0, // rETH + 0, // weETH + 0, // ezETH + 0, + ], + [ + // USDT Comet + 'updateAssetSupplyCap(address,address,uint128)', // tETH + 'updateAssetSupplyCap(address,address,uint128)', // tBTC + 'updateAssetSupplyCap(address,address,uint128)', // GMX + 'updateAssetSupplyCap(address,address,uint128)', // ARB + 'deployAndUpgradeTo(address,address)', + // WETH Comet + 'updateAssetSupplyCap(address,address,uint128)', // tETH + 'updateAssetSupplyCap(address,address,uint128)', // rETH + 'updateAssetSupplyCap(address,address,uint128)', // weETH + 'updateAssetSupplyCap(address,address,uint128)', // ezETH + 'deployAndUpgradeTo(address,address)', + ], + [ + // USDT Comet + arbitrumUsdtUpdateTETHSupplyCapCalldata, + arbitrumUsdtUpdateTBTCSupplyCapCalldata, + arbitrumUsdtUpdateGMXSupplyCapCalldata, + arbitrumUsdtUpdateARBSupplyCapCalldata, + arbitrumUsdtDeployAndUpgradeToCalldata, + // WETH Comet + arbitrumWethUpdateTETHSupplyCapCalldata, + arbitrumWethUpdateRETHSupplyCapCalldata, + arbitrumWethUpdateWeETHSupplyCapCalldata, + arbitrumWethUpdateEzETHSupplyCapCalldata, + arbitrumWethDeployAndUpgradeToCalldata, + ] + ] + ); + + const createRetryableTicketGasParams2 = await estimateL2Transaction( + { + from: applyL1ToL2Alias(timelock.address), + to: arbitrumBridgeReceiver.address, + data: arbitrumProposalData2 + }, + arbitrumDm + ); + + const mainnetActions = [ + // 1. Arbitrum proposal USDC + USDC.e + { + contract: arbitrumInbox, + signature: 'createRetryableTicket(address,uint256,uint256,address,address,uint256,uint256,bytes)', + args: [ + arbitrumBridgeReceiver.address, // address to, + 0, // uint256 l2CallValue, + createRetryableTicketGasParams1.maxSubmissionCost, // uint256 maxSubmissionCost, + arbitrumTimelock.address, // address excessFeeRefundAddress, + arbitrumTimelock.address, // address callValueRefundAddress, + createRetryableTicketGasParams1.gasLimit, // uint256 gasLimit, + createRetryableTicketGasParams1.maxFeePerGas*2, // uint256 maxFeePerGas, + arbitrumProposalData1, // bytes calldata data + ], + value: createRetryableTicketGasParams1.deposit.mul(2), + }, + // 2. Arbitrum proposal USDT + WETH + { + contract: arbitrumInbox, + signature: 'createRetryableTicket(address,uint256,uint256,address,address,uint256,uint256,bytes)', + args: [ + arbitrumBridgeReceiver.address, // address to, + 0, // uint256 l2CallValue, + createRetryableTicketGasParams2.maxSubmissionCost, // uint256 maxSubmissionCost, + arbitrumTimelock.address, // address excessFeeRefundAddress, + arbitrumTimelock.address, // address callValueRefundAddress, + createRetryableTicketGasParams2.gasLimit, // uint256 gasLimit, + createRetryableTicketGasParams2.maxFeePerGas*2, // uint256 maxFeePerGas, + arbitrumProposalData2, // bytes calldata data + ], + value: createRetryableTicketGasParams2.deposit.mul(2), + }, + ]; + + const description = `DESCRIPTION`; + + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 600_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager, govDeploymentManager) { + // Arbitrum + const { + tETH: arbitrumTETH, + tBTC: arbitrumTBTC, + ezETH: arbitrumEZETH, + GMX: arbitrumGMX, + ARB: arbitrumARB, + } = await deploymentManager.getContracts(); + + // USDC Comet + const arbitrumUsdcComet = new Contract( + cometConfig.Arbitrum.USDC.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await deploymentManager.getSigner() + ); + + const tETHAssetInfoUsdc = await arbitrumUsdcComet.getAssetInfoByAddress(arbitrumTETH.address); + const tBTCAssetInfoUsdc = await arbitrumUsdcComet.getAssetInfoByAddress(arbitrumTBTC.address); + const ezETHAssetInfoUsdc = await arbitrumUsdcComet.getAssetInfoByAddress(arbitrumEZETH.address); + const GMXAssetInfoUsdc = await arbitrumUsdcComet.getAssetInfoByAddress(arbitrumGMX.address); + const ARBAssetInfoUsdc = await arbitrumUsdcComet.getAssetInfoByAddress(arbitrumARB.address); + + expect(tETHAssetInfoUsdc.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDC.tETH.decimals)); + expect(tBTCAssetInfoUsdc.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDC.tBTC.decimals)); + expect(ezETHAssetInfoUsdc.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDC.ezETH.decimals)); + expect(GMXAssetInfoUsdc.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDC.GMX.decimals)); + expect(ARBAssetInfoUsdc.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDC.ARB.decimals)); + + expect(tETHAssetInfoUsdc.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDC.tETH.newCap, supplyCapConfig.Arbitrum.USDC.tETH.decimals)); + expect(tBTCAssetInfoUsdc.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDC.tBTC.newCap, supplyCapConfig.Arbitrum.USDC.tBTC.decimals)); + expect(ezETHAssetInfoUsdc.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDC.ezETH.newCap, supplyCapConfig.Arbitrum.USDC.ezETH.decimals)); + expect(GMXAssetInfoUsdc.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDC.GMX.newCap, supplyCapConfig.Arbitrum.USDC.GMX.decimals)); + expect(ARBAssetInfoUsdc.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDC.ARB.newCap, supplyCapConfig.Arbitrum.USDC.ARB.decimals)); + + // USDC.e Comet + const arbitrumUsdceComet = new Contract( + cometConfig.Arbitrum.USDCe.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await deploymentManager.getSigner() + ); + + const GMXAssetInfoUsdce = await arbitrumUsdceComet.getAssetInfoByAddress(arbitrumGMX.address); + const ARBAssetInfoUsdce = await arbitrumUsdceComet.getAssetInfoByAddress(arbitrumARB.address); + + expect(GMXAssetInfoUsdce.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDCe.GMX.decimals)); + expect(ARBAssetInfoUsdce.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDCe.ARB.decimals)); + + expect(GMXAssetInfoUsdce.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDCe.GMX.newCap, supplyCapConfig.Arbitrum.USDCe.GMX.decimals)); + expect(ARBAssetInfoUsdce.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDCe.ARB.newCap, supplyCapConfig.Arbitrum.USDCe.ARB.decimals)); + + const arbitrumUsdtComet = new Contract( + cometConfig.Arbitrum.USDT.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await deploymentManager.getSigner() + ); + + const tETHAssetInfoUsdt = await arbitrumUsdtComet.getAssetInfoByAddress(arbitrumTETH.address); + const tBTCAssetInfoUsdt = await arbitrumUsdtComet.getAssetInfoByAddress(arbitrumTBTC.address); + const GMXAssetInfoUsdt = await arbitrumUsdtComet.getAssetInfoByAddress(arbitrumGMX.address); + const ARBAssetInfoUsdt = await arbitrumUsdtComet.getAssetInfoByAddress(arbitrumARB.address); + + expect(tETHAssetInfoUsdt.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDT.tETH.decimals)); + expect(tBTCAssetInfoUsdt.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDT.tBTC.decimals)); + expect(GMXAssetInfoUsdt.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDT.GMX.decimals)); + expect(ARBAssetInfoUsdt.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDT.ARB.decimals)); + expect(tETHAssetInfoUsdt.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDT.tETH.newCap, supplyCapConfig.Arbitrum.USDT.tETH.decimals)); + expect(tBTCAssetInfoUsdt.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDT.tBTC.newCap, supplyCapConfig.Arbitrum.USDT.tBTC.decimals)); + expect(GMXAssetInfoUsdt.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDT.GMX.newCap, supplyCapConfig.Arbitrum.USDT.GMX.decimals)); + expect(ARBAssetInfoUsdt.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDT.ARB.newCap, supplyCapConfig.Arbitrum.USDT.ARB.decimals)); + + const arbitrumDmWeth = govDeploymentManager.bridgedDeploymentManagers.get('arbitrum:weth') as DeploymentManager; + const { + rETH: arbitrumRETH, + weETH: arbitrumWeETH, + ezETH: arbitrumEzETH, + } = await arbitrumDmWeth.getContracts(); + const arbitrumWethComet = new Contract( + cometConfig.Arbitrum.WETH.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await arbitrumDmWeth.getSigner() + ); + + const tETHAssetInfoWeth = await arbitrumWethComet.getAssetInfoByAddress(arbitrumTETH.address); + const rETHAssetInfoWeth = await arbitrumWethComet.getAssetInfoByAddress(arbitrumRETH.address); + const weETHAssetInfoWeth = await arbitrumWethComet.getAssetInfoByAddress(arbitrumWeETH.address); + const ezETHAssetInfoWeth = await arbitrumWethComet.getAssetInfoByAddress(arbitrumEzETH.address); + + expect(tETHAssetInfoWeth.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.WETH.tETH.decimals)); + expect(rETHAssetInfoWeth.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.WETH.rETH.decimals)); + expect(weETHAssetInfoWeth.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.WETH.weETH.decimals)); + expect(ezETHAssetInfoWeth.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.WETH.ezETH.decimals)); + + expect(tETHAssetInfoWeth.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.WETH.tETH.newCap, supplyCapConfig.Arbitrum.WETH.tETH.decimals)); + expect(rETHAssetInfoWeth.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.WETH.rETH.newCap, supplyCapConfig.Arbitrum.WETH.rETH.decimals)); + expect(weETHAssetInfoWeth.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.WETH.weETH.newCap, supplyCapConfig.Arbitrum.WETH.weETH.decimals)); + expect(ezETHAssetInfoWeth.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.WETH.ezETH.newCap, supplyCapConfig.Arbitrum.WETH.ezETH.decimals)); + }, +}); diff --git a/deployments/base/usdc/migrations/1778758319_update_supply_caps_on_l2.ts b/deployments/base/usdc/migrations/1778758319_update_supply_caps_on_l2.ts new file mode 100644 index 000000000..802f376db --- /dev/null +++ b/deployments/base/usdc/migrations/1778758319_update_supply_caps_on_l2.ts @@ -0,0 +1,212 @@ +import { expect } from 'chai'; +import { Contract, utils } from 'ethers'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { exp, proposal } from '../../../../src/deploy'; + +/* +// Base + +Base USDC Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +tBTC 75 15 20.06% 20 Rule 2 (~33% buffer) + +Base WETH Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +wsuperOETHb 2,000 676 33.81% 811 Rule 2 (~20% buffer) +weETH 7,500 363 4.84% 472 Rule 2 (~30% buffer) +ezETH 1,000 182 18.23% 237 Rule 2 (~30% buffer) + +*/ + +const cometConfig = { + Base: { + USDC: { + address: '0xb125E6687d4313864e53df431d5425969c15Eb2F', + }, + WETH: { + address: '0x46e6b214b524310239732D51387075E0e70970bf', + }, + }, +}; + +const supplyCapConfig = { + Base: { + USDC: { + tBTC: { + newCap: 20, + decimals: 18, + }, + }, + WETH: { + wsuperOETHb: { + newCap: 811, + decimals: 18, + }, + weETH: { + newCap: 472, + decimals: 18, + }, + ezETH: { + newCap: 237, + decimals: 18, + }, + }, + }, +}; + + +export default migration('1778758319_update_supply_caps_on_l2', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager, govDeploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const { + governor, + baseL1CrossDomainMessenger, + } = await govDeploymentManager.getContracts(); + + // Base + const { + bridgeReceiver : baseBridgeReceiver, + configurator: baseConfigurator, + cometAdmin: baseCometAdmin, + tBTC: baseTBTC, + } = await deploymentManager.getContracts(); + + const baseUsdcUpdateTBTCSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Base.USDC.address, baseTBTC.address, exp(supplyCapConfig.Base.USDC.tBTC.newCap, supplyCapConfig.Base.USDC.tBTC.decimals)]); + const baseUsdcDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [baseConfigurator.address, cometConfig.Base.USDC.address]); + + const baseDmWeth = await govDeploymentManager.addBridgedDeploymentManager('base', 'weth', deploymentManager.hre); + const { + wsuperOETHb: baseSuperOETHb, + weETH: baseWeETH, + ezETH: baseEzETH, + } = await baseDmWeth.getContracts(); + + const baseWethUpdateSuperOETHbSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Base.WETH.address, baseSuperOETHb.address, exp(supplyCapConfig.Base.WETH.wsuperOETHb.newCap, supplyCapConfig.Base.WETH.wsuperOETHb.decimals)]); + const baseWethUpdateWeETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Base.WETH.address, baseWeETH.address, exp(supplyCapConfig.Base.WETH.weETH.newCap, supplyCapConfig.Base.WETH.weETH.decimals)]); + const baseWethUpdateEzETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Base.WETH.address, baseEzETH.address, exp(supplyCapConfig.Base.WETH.ezETH.newCap, supplyCapConfig.Base.WETH.ezETH.decimals)]); + const baseWethDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [baseConfigurator.address, cometConfig.Base.WETH.address]); + + const baseProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + // USDC Comet + baseConfigurator.address, // tBTC + baseCometAdmin.address, + // WETH Comet + baseConfigurator.address, // wsuperOETHb + baseConfigurator.address, // weETH + baseConfigurator.address, // ezETH + baseCometAdmin.address, + ], + [ + // USDC Comet + 0, // tBTC + 0, + // WETH Comet + 0, // wsuperOETHb + 0, // weETH + 0, // ezETH + 0, + ], + [ + // USDC Comet + 'updateAssetSupplyCap(address,address,uint128)', // tBTC + 'deployAndUpgradeTo(address,address)', + // WETH Comet + 'updateAssetSupplyCap(address,address,uint128)', // wsuperOETHb + 'updateAssetSupplyCap(address,address,uint128)', // weETH + 'updateAssetSupplyCap(address,address,uint128)', // ezETH + 'deployAndUpgradeTo(address,address)', + ], + [ + // USDC Comet + baseUsdcUpdateTBTCSupplyCapCalldata, + baseUsdcDeployAndUpgradeToCalldata, + // WETH Comet + baseWethUpdateSuperOETHbSupplyCapCalldata, + baseWethUpdateWeETHSupplyCapCalldata, + baseWethUpdateEzETHSupplyCapCalldata, + baseWethDeployAndUpgradeToCalldata, + ], + ] + ); + + const mainnetActions = [ + // 1. Base proposal + { + contract: baseL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [baseBridgeReceiver.address, baseProposalData, 3_000_000] + }, + ]; + + const description = `DESCRIPTION`; + + const txn = await govDeploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 600_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager, govDeploymentManager) { + // Base + const { + tBTC: baseTBTC, + } = await deploymentManager.getContracts(); + + const baseUsdcComet = new Contract( + cometConfig.Base.USDC.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await deploymentManager.getSigner() + ); + + const tBTCAssetInfoBaseUsdc = await baseUsdcComet.getAssetInfoByAddress(baseTBTC.address); + + expect(tBTCAssetInfoBaseUsdc.scale).to.equal(exp(1, supplyCapConfig.Base.USDC.tBTC.decimals)); + expect(tBTCAssetInfoBaseUsdc.supplyCap).to.equal(exp(supplyCapConfig.Base.USDC.tBTC.newCap, supplyCapConfig.Base.USDC.tBTC.decimals)); + + const baseDmWeth = govDeploymentManager.bridgedDeploymentManagers.get('base:weth') as DeploymentManager; + const { + wsuperOETHb: baseSuperOETHb, + weETH: baseWeETH, + ezETH: baseEzETH, + } = await baseDmWeth.getContracts(); + + const baseWethComet = new Contract( + cometConfig.Base.WETH.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await baseDmWeth.getSigner() + ); + + const superOETHbAssetInfoBaseWeth = await baseWethComet.getAssetInfoByAddress(baseSuperOETHb.address); + const weETHAssetInfoBaseWeth = await baseWethComet.getAssetInfoByAddress(baseWeETH.address); + const ezETHAssetInfoBaseWeth = await baseWethComet.getAssetInfoByAddress(baseEzETH.address); + + expect(superOETHbAssetInfoBaseWeth.scale).to.equal(exp(1, supplyCapConfig.Base.WETH.wsuperOETHb.decimals)); + expect(weETHAssetInfoBaseWeth.scale).to.equal(exp(1, supplyCapConfig.Base.WETH.weETH.decimals)); + expect(ezETHAssetInfoBaseWeth.scale).to.equal(exp(1, supplyCapConfig.Base.WETH.ezETH.decimals)); + + expect(superOETHbAssetInfoBaseWeth.supplyCap).to.equal(exp(supplyCapConfig.Base.WETH.wsuperOETHb.newCap, supplyCapConfig.Base.WETH.wsuperOETHb.decimals)); + expect(weETHAssetInfoBaseWeth.supplyCap).to.equal(exp(supplyCapConfig.Base.WETH.weETH.newCap, supplyCapConfig.Base.WETH.weETH.decimals)); + expect(ezETHAssetInfoBaseWeth.supplyCap).to.equal(exp(supplyCapConfig.Base.WETH.ezETH.newCap, supplyCapConfig.Base.WETH.ezETH.decimals)); + }, +}); diff --git a/deployments/linea/weth/migrations/1778758319_update_supply_caps_on_l2.ts b/deployments/linea/weth/migrations/1778758319_update_supply_caps_on_l2.ts new file mode 100644 index 000000000..2f130915b --- /dev/null +++ b/deployments/linea/weth/migrations/1778758319_update_supply_caps_on_l2.ts @@ -0,0 +1,148 @@ +import { expect } from 'chai'; +import { Contract, utils } from 'ethers'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { exp, proposal } from '../../../../src/deploy'; + +/* +// Linea + +Linea WETH Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +ezETH 4,830 8 0.16% 0 Rule 1 +weETH 3,550 93 2.63% 121 Rule 2 (~30% buffer) + +*/ + +const cometConfig = { + Linea: { + WETH: { + address: '0x60F2058379716A64a7A5d29219397e79bC552194', + }, + }, +}; + +const supplyCapConfig = { + Linea: { + WETH: { + ezETH: { + newCap: 0, + decimals: 18, + }, + weETH: { + newCap: 121, + decimals: 18, + }, + }, + }, +}; + + +export default migration('1778758319_update_supply_caps_on_l2', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager, govDeploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const { + governor, + lineaMessageService, + } = await govDeploymentManager.getContracts(); + + // Linea + const { + bridgeReceiver: lineaBridgeReceiver, + configurator: lineaConfigurator, + cometAdmin: lineaCometAdmin, + ezETH: lineaEzETH, + weETH: lineaWeETH, + } = await deploymentManager.getContracts(); + + const lineaWethUpdateEZETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Linea.WETH.address, lineaEzETH.address, exp(supplyCapConfig.Linea.WETH.ezETH.newCap, supplyCapConfig.Linea.WETH.ezETH.decimals)]); + const lineaWethUpdateWeETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Linea.WETH.address, lineaWeETH.address, exp(supplyCapConfig.Linea.WETH.weETH.newCap, supplyCapConfig.Linea.WETH.weETH.decimals)]); + const lineaDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [lineaConfigurator.address, cometConfig.Linea.WETH.address]); + + const lineaProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + // WETH Comet + lineaConfigurator.address, + lineaConfigurator.address, + lineaCometAdmin.address, + ], + [ + // WETH Comet + 0, + 0, + 0 + ], + [ + // WETH Comet + 'updateAssetSupplyCap(address,address,uint128)', + 'updateAssetSupplyCap(address,address,uint128)', + 'deployAndUpgradeTo(address,address)', + ], + [ + // WETH Comet + lineaWethUpdateEZETHSupplyCapCalldata, + lineaWethUpdateWeETHSupplyCapCalldata, + lineaDeployAndUpgradeToCalldata + ], + ] + ); + + const mainnetActions = [ + // 1. Linea proposal + { + contract: lineaMessageService, + signature: 'sendMessage(address,uint256,bytes)', + args: [lineaBridgeReceiver.address, 0, lineaProposalData], + }, + ]; + + const description = `DESCRIPTION`; + + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 600_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + // Linea + const { + ezETH: lineaEzETH, + weETH: lineaWeETH, + } = await deploymentManager.getContracts(); + + const lineaWethComet = new Contract( + cometConfig.Linea.WETH.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await deploymentManager.getSigner() + ); + + const ezETHAssetInfoLineaWeth = await lineaWethComet.getAssetInfoByAddress(lineaEzETH.address); + const weETHAssetInfoLineaWeth = await lineaWethComet.getAssetInfoByAddress(lineaWeETH.address); + + expect(ezETHAssetInfoLineaWeth.scale).to.equal(exp(1, supplyCapConfig.Linea.WETH.ezETH.decimals)); + expect(weETHAssetInfoLineaWeth.scale).to.equal(exp(1, supplyCapConfig.Linea.WETH.weETH.decimals)); + + expect(ezETHAssetInfoLineaWeth.supplyCap).to.equal(exp(supplyCapConfig.Linea.WETH.ezETH.newCap, supplyCapConfig.Linea.WETH.ezETH.decimals)); + expect(weETHAssetInfoLineaWeth.supplyCap).to.equal(exp(supplyCapConfig.Linea.WETH.weETH.newCap, supplyCapConfig.Linea.WETH.weETH.decimals)); + }, +}); diff --git a/deployments/mainnet/usdc/migrations/1775661752_withdraw_reserves.ts b/deployments/mainnet/usdc/migrations/1775661752_withdraw_reserves.ts new file mode 100644 index 000000000..ddc047bd8 --- /dev/null +++ b/deployments/mainnet/usdc/migrations/1775661752_withdraw_reserves.ts @@ -0,0 +1,908 @@ +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { exp, proposal } from '../../../../src/deploy'; +import { utils, Contract, BigNumber } from 'ethers'; +import { applyL1ToL2Alias, estimateL2Transaction } from '../../../../scenario/utils/arbitrumUtils'; +import { forkedHreForBase } from '../../../../plugins/scenario/utils/hreForBase'; + +const withdrawConfigV2 = { + cWBTC2: { + address: '0xccF4429DB6322D5C611ee964527D42E5d685DD6a', + asset: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', + amount: 139, + decimals: 8, + }, + cUSDC: { + address: '0x39AA39c021dfbaE8faC545936693aC917d5E7563', + asset: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + amount: 5_772_174, + decimals: 6, + }, + cETH: { + address: '0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5', + asset: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + amount: 813, + decimals: 18, + }, + cUSDT: { + address: '0xf650C3d88D12dB855b8bf7D11Be6C55A4e07dCC9', + asset: '0xdAC17F958D2ee523a2206206994597C13D831ec7', + amount: 1_233_614, + decimals: 6, + }, + cBAT: { + address: '0x6C8c6b02E7b2BE14d4fA6022Dfd6d75921D90E4E', + asset: '0x0d8775f648430679a709e98d2b0cb6250d2887ef', + amount: 2_475_186, + decimals: 18, + }, + cUNI: { + address: '0x35A18000230DA775CAc24873d00Ff85BccdeD550', + asset: '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984', + amount: 66_056, + decimals: 18, + }, + cTUSD: { + address: '0x12392F67bdf24faE0AF363c24aC620a2f67DAd86', + asset: '0x0000000000085d4780b73119b644ae5ecd22b376', + amount: 168_050, + decimals: 18, + }, + cLINK: { + address: '0xFAce851a4921ce59e912d19329929CE6da6EB0c7', + asset: '0x514910771af9ca656af840dff83e8264ecf986ca', + amount: 7_874, + decimals: 18, + }, + cAAVE: { + address: '0xe65cdB6479BaC1e22340E4E755fAE7E509EcD06c', + asset: '0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9', + amount: 265, + decimals: 18, + }, + cCOMP: { + address: '0x70e36f6BF80a52b3B46b3aF8e106CC0ed743E8e4', + asset: '0xc00e94cb662c3520282e6f5717214004a7f26888', + amount: 664, + decimals: 18, + }, +}; + +const withdrawConfigV3 = { + mainnet: { + cUSDCv3: { + address: '0xc3d688B66703497DAA19211EEdff47f25384cdc3', + amount: 5_983_604, + decimals: 6, + } + }, + optimism: { + cUSDCv3: { + address: '0x2e44e174f7D53F0212823acC11C01A11d58c5bCB', + assetL1: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', + assetL2: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85', + amount: 258_077, + decimals: 6, + }, + cUSDTv3: { + address: '0x995E394b8B2437aC8Ce61Ee0bC610D617962B214', + assetL1: '0xdAC17F958D2ee523a2206206994597C13D831ec7', + assetL2: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58', + amount: 10_242, + decimals: 6, + }, + }, + base: { + cUSDbCv3: { + address: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf', + assetL1: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', + assetL2: '0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA', + amount: 120_512, + decimals: 6, + }, + }, + arbitrum: { + cUSDCv3: { + address: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf', + assetL1: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + assetL2: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831', + amount: 43_556, + decimals: 6, + }, + cUSDCev3: { + address: '0xA5EDBDD9646f8dFF606d7448e414884C7d905dCA', + assetL1: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + assetL2: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', + amount: 257_235, + decimals: 6, + }, + cWETHv3: { + address: '0x6f7D514bbD4aFf3BcD1140B7344b32f063dEe486', + assetL1: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + assetL2: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', + amount: 34.76, + decimals: 18, + }, + } +}; + +const recipient = '0xDcB34b56842F853A69E86De5A0c22c49d97C130C'; +const newVaultOwner = '0xefeD08b791423C7D7937507Cf840E86a7ddC11c1'; + +const OPTIMISM_BRIDGE_RECEIVER = '0xC3a73A70d1577CD5B02da0bA91C0Afc8fA434DAF'; +const OPTIMISM_TIMELOCK = '0xd98Be00b5D27fc98112BdE293e487f8D4cA57d07'; +const OPTIMISM_STANDARD_BRIDGE = '0x4200000000000000000000000000000000000010'; +const OPTIMISM_CCTP_TOKEN_MESSENGER = '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d'; + +const BASE_BRIDGE_RECEIVER = '0x18281dfC4d00905DA1aaA6731414EABa843c468A'; +const BASE_TIMELOCK = '0xCC3E7c85Bb0EE4f09380e041fee95a0caeDD4a02'; +const BASE_STANDARD_BRIDGE = '0x4200000000000000000000000000000000000010'; + +const ARBITRUM_USDCE_GATEWAY = '0x096760F208390250649E3e8763348E783AEF5562'; +const ARBITRUM_WETH_GATEWAY = '0x6c411aD3E74De3E7Bd422b94A27770f5B86C623B'; +const ARBITRUM_BRIDGE_RECEIVER = '0x42480C37B249e33aABaf4c22B20235656bd38068'; +const ARBITRUM_TIMELOCK = '0x3fB4d38ea7EC20D91917c09591490Eeda38Cf88A'; +const ARBITRUM_CCTP_TOKEN_MESSENGER = '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d'; + +const AERA_VAULT = '0x8624f61Cc6e5A86790e173712AfDd480fa8b73Ba'; +const AVANTGARDE_VAULT = '0xeB6332bbB14b1488eFb3A395B8EBF6a6904C4241'; + +let balancesBefore: Record = {}; + +async function getErc20FromAddress(dm: DeploymentManager, address: string, ): Promise { + return new Contract(address, ['function balanceOf(address) view returns (uint256)'], await dm.getSigner()); +} + +export default migration('1775661752_withdraw_reserves', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager) { + const trace = deploymentManager.tracer(); + + const { + timelock, + governor, + opL1CrossDomainMessenger, + baseL1CrossDomainMessenger, + arbitrumInbox + } = await deploymentManager.getContracts(); + + // Optimism + const opHre = await forkedHreForBase({ name: 'optimism-usdc', network: 'optimism', deployment: 'usdc' }); + await deploymentManager.addBridgedDeploymentManager('optimism', 'usdc', opHre); + const withdrawUsdcOptimismCalldata = utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [OPTIMISM_TIMELOCK, exp(withdrawConfigV3.optimism.cUSDCv3.amount, withdrawConfigV3.optimism.cUSDCv3.decimals)] + ); + + const approveUsdcOptimismCalldata = utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [OPTIMISM_CCTP_TOKEN_MESSENGER, exp(withdrawConfigV3.optimism.cUSDCv3.amount, withdrawConfigV3.optimism.cUSDCv3.decimals)] + ); + + const depositForBurnUsdcOptimismCalldata = utils.defaultAbiCoder.encode( + ['uint256', 'uint32', 'bytes32', 'address', 'bytes32', 'uint256', 'uint32'], + [ + exp(withdrawConfigV3.optimism.cUSDCv3.amount, withdrawConfigV3.optimism.cUSDCv3.decimals), // amount + 0, // destinationDomain (Ethereum Mainnet) + utils.hexZeroPad(recipient, 32), // mintRecipient + withdrawConfigV3.optimism.cUSDCv3.assetL2, // burnToken + utils.hexZeroPad('0x', 32), // destinationCaller + exp(10, 6), // maxFee + 1000 // minFinalityThreshold + ] + ); + + const withdrawUsdtOptimismCalldata = utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [OPTIMISM_TIMELOCK, exp(withdrawConfigV3.optimism.cUSDTv3.amount, withdrawConfigV3.optimism.cUSDTv3.decimals)] + ); + + const approveUsdtOptimismCalldata = utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [OPTIMISM_STANDARD_BRIDGE, exp(withdrawConfigV3.optimism.cUSDTv3.amount, withdrawConfigV3.optimism.cUSDTv3.decimals)] + ); + + const bridgeERC20ToUsdtOptimismCalldata = utils.defaultAbiCoder.encode( + ['address', 'address', 'address', 'uint256', 'uint32', 'bytes'], + [ + withdrawConfigV3.optimism.cUSDTv3.assetL2, // _localToken + withdrawConfigV3.optimism.cUSDTv3.assetL1, // _remoteToken + recipient, // _to + exp(withdrawConfigV3.optimism.cUSDTv3.amount, withdrawConfigV3.optimism.cUSDTv3.decimals), // _amount + 200000, // _minGasLimit + '0x', // _data + ] + ); + + const optimismProposalData1 = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + withdrawConfigV3.optimism.cUSDTv3.address, + withdrawConfigV3.optimism.cUSDTv3.assetL2, + OPTIMISM_STANDARD_BRIDGE, + ], + [ + 0, 0, 0, + ], + [ + 'withdrawReserves(address,uint256)', + 'approve(address,uint256)', + 'bridgeERC20To(address,address,address,uint256,uint32,bytes)' + ], + [ + withdrawUsdtOptimismCalldata, + approveUsdtOptimismCalldata, + bridgeERC20ToUsdtOptimismCalldata, + ] + ] + ); + + const optimismProposalData2 = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + withdrawConfigV3.optimism.cUSDCv3.address, + withdrawConfigV3.optimism.cUSDCv3.assetL2, + OPTIMISM_CCTP_TOKEN_MESSENGER, + ], + [ + 0, 0, 0, + ], + [ + 'withdrawReserves(address,uint256)', + 'approve(address,uint256)', + 'depositForBurn(uint256,uint32,bytes32,address,bytes32,uint256,uint32)', + ], + [ + withdrawUsdcOptimismCalldata, + approveUsdcOptimismCalldata, + depositForBurnUsdcOptimismCalldata, + ] + ] + ); + // Base + const baseHre = await forkedHreForBase({ name: 'base-usdbc', network: 'base', deployment: 'usdbc' }); + await deploymentManager.addBridgedDeploymentManager('base', 'usdbc', baseHre); + const withdrawUsdbcBaseCalldata = utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [BASE_TIMELOCK, exp(withdrawConfigV3.base.cUSDbCv3.amount, withdrawConfigV3.base.cUSDbCv3.decimals)] + ); + + const approveUsdbcBaseCalldata = utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [BASE_STANDARD_BRIDGE, exp(withdrawConfigV3.base.cUSDbCv3.amount, withdrawConfigV3.base.cUSDbCv3.decimals)] + ); + + const bridgeERC20ToUsdbcBaseCalldata = utils.defaultAbiCoder.encode( + ['address', 'address', 'address', 'uint256', 'uint32', 'bytes'], + [ + withdrawConfigV3.base.cUSDbCv3.assetL2, // _localToken + withdrawConfigV3.base.cUSDbCv3.assetL1, // _remoteToken + recipient, // _to + exp(withdrawConfigV3.base.cUSDbCv3.amount, withdrawConfigV3.base.cUSDbCv3.decimals), // _amount + 200000, // _minGasLimit + '0x', // _data + ] + ); + + const baseProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + withdrawConfigV3.base.cUSDbCv3.address, + withdrawConfigV3.base.cUSDbCv3.assetL2, + BASE_STANDARD_BRIDGE, + ], + [ + 0, 0, 0, + ], + [ + 'withdrawReserves(address,uint256)', + 'approve(address,uint256)', + 'bridgeERC20To(address,address,address,uint256,uint32,bytes)' + ], + [ + withdrawUsdbcBaseCalldata, + approveUsdbcBaseCalldata, + bridgeERC20ToUsdbcBaseCalldata, + ] + ] + ); + + // Arbitrum + const arbitrumHre = await forkedHreForBase({ name: 'arbitrum-usdc', network: 'arbitrum', deployment: 'usdc' }); + const arbitrumDm = await deploymentManager.addBridgedDeploymentManager('arbitrum', 'usdc', arbitrumHre); + const withdrawUsdcArbitrumCalldata = utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [ARBITRUM_TIMELOCK, exp(withdrawConfigV3.arbitrum.cUSDCv3.amount, withdrawConfigV3.arbitrum.cUSDCv3.decimals)] + ); + + const withdrawUsdceArbitrumCalldata = utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [ARBITRUM_TIMELOCK, exp(withdrawConfigV3.arbitrum.cUSDCev3.amount, withdrawConfigV3.arbitrum.cUSDCev3.decimals)] + ); + + const withdrawEthArbitrumCalldata = utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [ARBITRUM_TIMELOCK, exp(withdrawConfigV3.arbitrum.cWETHv3.amount, withdrawConfigV3.arbitrum.cWETHv3.decimals)] + ); + + const approveUsdcArbitrumCalldata = utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [ARBITRUM_CCTP_TOKEN_MESSENGER, exp(withdrawConfigV3.arbitrum.cUSDCv3.amount, withdrawConfigV3.arbitrum.cUSDCv3.decimals)] + ); + + const depositForBurnUsdcArbitrumCalldata = utils.defaultAbiCoder.encode( + ['uint256', 'uint32', 'bytes32', 'address', 'bytes32', 'uint256', 'uint32'], + [ + exp(withdrawConfigV3.arbitrum.cUSDCv3.amount, withdrawConfigV3.arbitrum.cUSDCv3.decimals), // amount + 0, // destinationDomain (Ethereum Mainnet) + utils.hexZeroPad(recipient, 32), // mintRecipient + withdrawConfigV3.arbitrum.cUSDCv3.assetL2, // burnToken + utils.hexZeroPad('0x', 32), // destinationCaller + exp(10, 6), // maxFee + 1000 // minFinalityThreshold + ] + ); + + const approveUsdceArbitrumCalldata = utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [ARBITRUM_USDCE_GATEWAY, exp(withdrawConfigV3.arbitrum.cUSDCev3.amount, withdrawConfigV3.arbitrum.cUSDCev3.decimals)] + ); + + const outboundTransferUsdceArbitrumCalldata = utils.defaultAbiCoder.encode( + ['address', 'address', 'uint256', 'bytes'], + [ + withdrawConfigV3.arbitrum.cUSDCev3.assetL1, // l1Token + recipient, // to + exp(withdrawConfigV3.arbitrum.cUSDCev3.amount, withdrawConfigV3.arbitrum.cUSDCev3.decimals), // amount + '0x' // data + ] + ); + + const approveWethArbitrumCalldata = utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [ARBITRUM_WETH_GATEWAY, exp(withdrawConfigV3.arbitrum.cWETHv3.amount, withdrawConfigV3.arbitrum.cWETHv3.decimals)] + ); + + const outboundTransferWethArbitrumCalldata = utils.defaultAbiCoder.encode( + ['address', 'address', 'uint256', 'bytes'], + [ + withdrawConfigV3.arbitrum.cWETHv3.assetL1, // l1Token + recipient, // to + exp(withdrawConfigV3.arbitrum.cWETHv3.amount, withdrawConfigV3.arbitrum.cWETHv3.decimals), // amount + '0x' // data + ] + ); + + const arbitrumProposalData1 = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + withdrawConfigV3.arbitrum.cUSDCv3.address, + withdrawConfigV3.arbitrum.cUSDCv3.assetL2, + ARBITRUM_CCTP_TOKEN_MESSENGER, + ], + [ + 0, 0, 0, + ], + [ + 'withdrawReserves(address,uint256)', + 'approve(address,uint256)', + 'depositForBurn(uint256,uint32,bytes32,address,bytes32,uint256,uint32)', + ], + [ + withdrawUsdcArbitrumCalldata, + approveUsdcArbitrumCalldata, + depositForBurnUsdcArbitrumCalldata, + ] + ] + ); + + const arbitrumProposalData2 = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + withdrawConfigV3.arbitrum.cUSDCev3.address, + withdrawConfigV3.arbitrum.cUSDCev3.assetL2, + ARBITRUM_USDCE_GATEWAY, + ], + [ + 0, 0, 0, + ], + [ + 'withdrawReserves(address,uint256)', + 'approve(address,uint256)', + 'outboundTransfer(address,address,uint256,bytes)', + ], + [ + withdrawUsdceArbitrumCalldata, + approveUsdceArbitrumCalldata, + outboundTransferUsdceArbitrumCalldata, + ] + ] + ); + + const arbitrumProposalData3 = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + withdrawConfigV3.arbitrum.cWETHv3.address, + withdrawConfigV3.arbitrum.cWETHv3.assetL2, + ARBITRUM_WETH_GATEWAY + ], + [ + 0, 0, 0, + ], + [ + 'withdrawReserves(address,uint256)', + 'approve(address,uint256)', + 'outboundTransfer(address,address,uint256,bytes)', + ], + [ + withdrawEthArbitrumCalldata, + approveWethArbitrumCalldata, + outboundTransferWethArbitrumCalldata + ] + ] + ); + + const createRetryableTicketGasParams1 = await estimateL2Transaction( + { + from: applyL1ToL2Alias(timelock.address), + to: ARBITRUM_BRIDGE_RECEIVER, + data: arbitrumProposalData1 + }, + arbitrumDm + ); + + const createRetryableTicketGasParams2 = await estimateL2Transaction( + { + from: applyL1ToL2Alias(timelock.address), + to: ARBITRUM_BRIDGE_RECEIVER, + data: arbitrumProposalData2 + }, + arbitrumDm + ); + + const createRetryableTicketGasParams3 = await estimateL2Transaction( + { + from: applyL1ToL2Alias(timelock.address), + to: ARBITRUM_BRIDGE_RECEIVER, + data: arbitrumProposalData3 + }, + arbitrumDm + ); + + const refundAddress = ARBITRUM_TIMELOCK; + + // Vaults + const transferOwnershipCalldata = utils.defaultAbiCoder.encode( + ['address'], + [newVaultOwner] + ); + + const avantgardeVault = new Contract( + AVANTGARDE_VAULT, [ + 'function execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes) external', + 'function swapOwner(address,address,address) external' + ], + await deploymentManager.getSigner() + ); + const swapOwnerCalldata = avantgardeVault.interface.encodeFunctionData( + 'swapOwner', + // [address(0x1), timelock.address, recipient] + [utils.getAddress(utils.hexZeroPad('0x01', 20)), timelock.address, newVaultOwner] + ); + + const mainnetActions = [ + // 1. Withdraw reserves from cWBTCv2 + { + target: withdrawConfigV2.cWBTC2.address, + signature: '_reduceReserves(uint256)', + calldata: utils.defaultAbiCoder.encode( + ['uint256'], + [exp(withdrawConfigV2.cWBTC2.amount, withdrawConfigV2.cWBTC2.decimals)] + + ), + }, + // 2. Transfer withdrawn BTC to recipient + { + target: withdrawConfigV2.cWBTC2.asset, + signature: 'transfer(address,uint256)', + calldata: utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [recipient, exp(withdrawConfigV2.cWBTC2.amount, withdrawConfigV2.cWBTC2.decimals)] + ), + }, + // 3. Withdraw reserves from cUSDCv2 + { + target: withdrawConfigV2.cUSDC.address, + signature: '_reduceReserves(uint256)', + calldata: utils.defaultAbiCoder.encode( + ['uint256'], + [exp(withdrawConfigV2.cUSDC.amount, withdrawConfigV2.cUSDC.decimals)] + ), + }, + // 4. Transfer withdrawn USDC to recipient + { + target: withdrawConfigV2.cUSDC.asset, + signature: 'transfer(address,uint256)', + calldata: utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [recipient, exp(withdrawConfigV2.cUSDC.amount, withdrawConfigV2.cUSDC.decimals)] + ), + }, + // 5. Withdraw reserves from cETHv2 + { + target: withdrawConfigV2.cETH.address, + signature: '_reduceReserves(uint256)', + calldata: utils.defaultAbiCoder.encode( + ['uint256'], + [exp(withdrawConfigV2.cETH.amount, withdrawConfigV2.cETH.decimals)] + ), + }, + // 6. Transfer withdrawn ETH to recipient + { + target: recipient, + signature: '', + value: exp(withdrawConfigV2.cETH.amount, withdrawConfigV2.cETH.decimals), + calldata: '0x', + }, + // 7. Withdraw reserves from cUSDTv2 + { + target: withdrawConfigV2.cUSDT.address, + signature: '_reduceReserves(uint256)', + calldata: utils.defaultAbiCoder.encode( + ['uint256'], + [exp(withdrawConfigV2.cUSDT.amount, withdrawConfigV2.cUSDT.decimals)] + ), + }, + // 8. Transfer withdrawn USDT to recipient + { + target: withdrawConfigV2.cUSDT.asset, + signature: 'transfer(address,uint256)', + calldata: utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [recipient, exp(withdrawConfigV2.cUSDT.amount, withdrawConfigV2.cUSDT.decimals)] + ), + }, + // 9. Withdraw reserves from cBATv2 + { + target: withdrawConfigV2.cBAT.address, + signature: '_reduceReserves(uint256)', + calldata: utils.defaultAbiCoder.encode( + ['uint256'], + [exp(withdrawConfigV2.cBAT.amount, withdrawConfigV2.cBAT.decimals)] + ), + }, + // 10. Transfer withdrawn BAT to recipient + { + target: withdrawConfigV2.cBAT.asset, + signature: 'transfer(address,uint256)', + calldata: utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [recipient, exp(withdrawConfigV2.cBAT.amount, withdrawConfigV2.cBAT.decimals)] + ), + }, + // 11. Withdraw reserves from cUNIv2 + { + target: withdrawConfigV2.cUNI.address, + signature: '_reduceReserves(uint256)', + calldata: utils.defaultAbiCoder.encode( + ['uint256'], + [exp(withdrawConfigV2.cUNI.amount, withdrawConfigV2.cUNI.decimals)] + ), + }, + // 12. Transfer withdrawn UNI to recipient + { + target: withdrawConfigV2.cUNI.asset, + signature: 'transfer(address,uint256)', + calldata: utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [recipient, exp(withdrawConfigV2.cUNI.amount, withdrawConfigV2.cUNI.decimals)] + ), + }, + // 13. Withdraw reserves from cTUSDv2 + { + target: withdrawConfigV2.cTUSD.address, + signature: '_reduceReserves(uint256)', + calldata: utils.defaultAbiCoder.encode( + ['uint256'], + [exp(withdrawConfigV2.cTUSD.amount, withdrawConfigV2.cTUSD.decimals)] + ), + }, + // 14. Transfer withdrawn TUSD to recipient + { + target: withdrawConfigV2.cTUSD.asset, + signature: 'transfer(address,uint256)', + calldata: utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [recipient, exp(withdrawConfigV2.cTUSD.amount, withdrawConfigV2.cTUSD.decimals)] + ), + }, + // 15. Withdraw reserves from cLINKv2 + { + target: withdrawConfigV2.cLINK.address, + signature: '_reduceReserves(uint256)', + calldata: utils.defaultAbiCoder.encode( + ['uint256'], + [exp(withdrawConfigV2.cLINK.amount, withdrawConfigV2.cLINK.decimals)] + ), + }, + // 16. Transfer withdrawn LINK to recipient + { + target: withdrawConfigV2.cLINK.asset, + signature: 'transfer(address,uint256)', + calldata: utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [recipient, exp(withdrawConfigV2.cLINK.amount, withdrawConfigV2.cLINK.decimals)] + ), + }, + // 17. Withdraw reserves from cAAVEv2 + { + target: withdrawConfigV2.cAAVE.address, + signature: '_reduceReserves(uint256)', + calldata: utils.defaultAbiCoder.encode( + ['uint256'], + [exp(withdrawConfigV2.cAAVE.amount, withdrawConfigV2.cAAVE.decimals)] + ), + }, + // 18. Transfer withdrawn AAVE to recipient + { + target: withdrawConfigV2.cAAVE.asset, + signature: 'transfer(address,uint256)', + calldata: utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [recipient, exp(withdrawConfigV2.cAAVE.amount, withdrawConfigV2.cAAVE.decimals)] + ), + }, + // 19. Withdraw reserves from cCOMPv2 + { + target: withdrawConfigV2.cCOMP.address, + signature: '_reduceReserves(uint256)', + calldata: utils.defaultAbiCoder.encode( + ['uint256'], + [exp(withdrawConfigV2.cCOMP.amount, withdrawConfigV2.cCOMP.decimals)] + ), + }, + // 20. Transfer withdrawn COMP to recipient + { + target: withdrawConfigV2.cCOMP.asset, + signature: 'transfer(address,uint256)', + calldata: utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [recipient, exp(withdrawConfigV2.cCOMP.amount, withdrawConfigV2.cCOMP.decimals)] + ), + }, + // 21. Withdraw reserves from cUSDCv3 + { + target: withdrawConfigV3.mainnet.cUSDCv3.address, + signature: 'withdrawReserves(address,uint256)', + calldata: utils.defaultAbiCoder.encode( + ['address', 'uint256'], + [recipient, exp(withdrawConfigV3.mainnet.cUSDCv3.amount, withdrawConfigV3.mainnet.cUSDCv3.decimals)] + ), + }, + // 22. Send message to Optimism to trigger USDT withdrawal and bridging it back to Mainnet + { + contract: opL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [OPTIMISM_BRIDGE_RECEIVER, optimismProposalData1, 2_500_000], + }, + // 23. Send message to Optimism to trigger USDC withdrawal and bridging it back to Mainnet + { + contract: opL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [OPTIMISM_BRIDGE_RECEIVER, optimismProposalData2, 2_500_000], + }, + // 24. Send message to Base to trigger USDbC withdrawal and bridging it back to Mainnet + { + contract: baseL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [BASE_BRIDGE_RECEIVER, baseProposalData, 3_000_000] + }, + // 25. Send message to Arbitrum to trigger USDC withdrawal and bridging it back to Mainnet + { + contract: arbitrumInbox, + signature: 'createRetryableTicket(address,uint256,uint256,address,address,uint256,uint256,bytes)', + args: [ + ARBITRUM_BRIDGE_RECEIVER, // address to, + 0, // uint256 l2CallValue, + createRetryableTicketGasParams1.maxSubmissionCost, // uint256 maxSubmissionCost, + refundAddress, // address excessFeeRefundAddress, + refundAddress, // address callValueRefundAddress, + createRetryableTicketGasParams1.gasLimit, // uint256 gasLimit, + createRetryableTicketGasParams1.maxFeePerGas*2, // uint256 maxFeePerGas, + arbitrumProposalData1, // bytes calldata data + ], + value: createRetryableTicketGasParams1.deposit.mul(2), + }, + // 26. Send message to Arbitrum to trigger USDC.e withdrawal and bridging it back to Mainnet + { + contract: arbitrumInbox, + signature: 'createRetryableTicket(address,uint256,uint256,address,address,uint256,uint256,bytes)', + args: [ + ARBITRUM_BRIDGE_RECEIVER, // address to, + 0, // uint256 l2CallValue, + createRetryableTicketGasParams2.maxSubmissionCost, // uint256 maxSubmissionCost, + refundAddress, // address excessFeeRefundAddress, + refundAddress, // address callValueRefundAddress, + createRetryableTicketGasParams2.gasLimit, // uint256 gasLimit, + createRetryableTicketGasParams2.maxFeePerGas*2, // uint256 maxFeePerGas, + arbitrumProposalData2, // bytes calldata data + ], + value: createRetryableTicketGasParams2.deposit.mul(2), + }, + // 27. Send message to Arbitrum to trigger WETH withdrawal and bridging it back to Mainnet + { + contract: arbitrumInbox, + signature: 'createRetryableTicket(address,uint256,uint256,address,address,uint256,uint256,bytes)', + args: [ + ARBITRUM_BRIDGE_RECEIVER, // address to, + 0, // uint256 l2CallValue, + createRetryableTicketGasParams3.maxSubmissionCost, // uint256 maxSubmissionCost, + refundAddress, // address excessFeeRefundAddress, + refundAddress, // address callValueRefundAddress, + createRetryableTicketGasParams3.gasLimit, // uint256 gasLimit, + createRetryableTicketGasParams3.maxFeePerGas*2, // uint256 maxFeePerGas, + arbitrumProposalData3, // bytes calldata data + ], + value: createRetryableTicketGasParams3.deposit.mul(2), + }, + // 28. Transfer ownership of Aera vault to recipient + { + target: AERA_VAULT, + signature: 'transferOwnership(address)', + calldata: transferOwnershipCalldata, + }, + // 29. Transfer ownership of generic vault to recipient + { + contract: avantgardeVault, + signature: 'execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)', + args: [ + AVANTGARDE_VAULT, + 0, + swapOwnerCalldata, + 0, + 0, + 0, + 0, + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000', + '0x0000000000000000000000006d903f6003cca6255D85CcA4D3B5E5146dC33925000000000000000000000000000000000000000000000000000000000000004101' + ], + }, + ]; + + const WBTC = await getErc20FromAddress(deploymentManager, withdrawConfigV2.cWBTC2.asset); + const USDC = await getErc20FromAddress(deploymentManager, withdrawConfigV2.cUSDC.asset); + const USDT = await getErc20FromAddress(deploymentManager, withdrawConfigV2.cUSDT.asset); + const BAT = await getErc20FromAddress(deploymentManager, withdrawConfigV2.cBAT.asset); + const UNI = await getErc20FromAddress(deploymentManager, withdrawConfigV2.cUNI.asset); + const TUSD = await getErc20FromAddress(deploymentManager, withdrawConfigV2.cTUSD.asset); + const LINK = await getErc20FromAddress(deploymentManager, withdrawConfigV2.cLINK.asset); + const AAVE = await getErc20FromAddress(deploymentManager, withdrawConfigV2.cAAVE.asset); + const COMP = await getErc20FromAddress(deploymentManager, withdrawConfigV2.cCOMP.asset); + const WETH = await getErc20FromAddress(deploymentManager, withdrawConfigV2.cETH.asset); + + balancesBefore = { + WBTC: await WBTC.balanceOf(recipient), + USDC: await USDC.balanceOf(recipient), + USDT: await USDT.balanceOf(recipient), + BAT: await BAT.balanceOf(recipient), + UNI: await UNI.balanceOf(recipient), + TUSD: await TUSD.balanceOf(recipient), + LINK: await LINK.balanceOf(recipient), + AAVE: await AAVE.balanceOf(recipient), + COMP: await COMP.balanceOf(recipient), + ETH: BigNumber.from(await deploymentManager.hre.ethers.provider.getBalance(recipient)), + WETH: await WETH.balanceOf(recipient), + }; + + const description = `# Establishment of Treasury Management Program and Treasury Management Committee + +This proposal establishes the Compound Treasury Management Program (TMP) and deploys the on-chain infrastructure required to consolidate and manage protocol treasury assets under the oversight of a newly constituted Treasury Management Committee (TMC). + +Upon execution, this proposal: + +1. Withdraws deprecated V2 reserves (~$18.95M) to Treasury Escrow. +2. Transfers Aera vault ownership (~$28.21M) from the Governor Timelock to Treasury Timelock. +3. Transfers Avantgarde vault ownership (~$3.8M) from the Governor Timelock to Treasury Timelock. +4. Withdraws V3 surplus reserves (~$6.94M) above the reserve floor to Treasury Escrow. + +All withdrawals from Treasury Escrow are subject to a 2-day cooldown before execution, a 7-day expiration window, and Safeguard cancellation rights. The Treasury Timelock enforces a 2-day minimum delay on governance-level operations. Both contracts have been audited by ChainSecurity and Certora. + +### Audit + +Treasury manager has been audited by [Certora](https://www.certora.com/) and the report can be found [here](https://www.certora.com/reports/compound-treasury-manager). + +Full proposal details, fund source methodology, on-chain controls, and TMC composition: [Establishment of Treasury Management Program and Treasury Management Committee](https://www.comp.xyz/t/establishment-of-treasury-management-program-and-treasury-management-committee/7710). +`; + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 600_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + const WBTC = await getErc20FromAddress(deploymentManager, withdrawConfigV2.cWBTC2.asset); + const USDC = await getErc20FromAddress(deploymentManager, withdrawConfigV2.cUSDC.asset); + const USDT = await getErc20FromAddress(deploymentManager, withdrawConfigV2.cUSDT.asset); + const BAT = await getErc20FromAddress(deploymentManager, withdrawConfigV2.cBAT.asset); + const UNI = await getErc20FromAddress(deploymentManager, withdrawConfigV2.cUNI.asset); + const TUSD = await getErc20FromAddress(deploymentManager, withdrawConfigV2.cTUSD.asset); + const LINK = await getErc20FromAddress(deploymentManager, withdrawConfigV2.cLINK.asset); + const AAVE = await getErc20FromAddress(deploymentManager, withdrawConfigV2.cAAVE.asset); + const COMP = await getErc20FromAddress(deploymentManager, withdrawConfigV2.cCOMP.asset); + const WETH = await getErc20FromAddress(deploymentManager, withdrawConfigV2.cETH.asset); + + const balancesAfter = { + WBTC: await WBTC.balanceOf(recipient), + USDC: await USDC.balanceOf(recipient), + USDT: await USDT.balanceOf(recipient), + BAT: await BAT.balanceOf(recipient), + UNI: await UNI.balanceOf(recipient), + TUSD: await TUSD.balanceOf(recipient), + LINK: await LINK.balanceOf(recipient), + AAVE: await AAVE.balanceOf(recipient), + COMP: await COMP.balanceOf(recipient), + ETH: BigNumber.from(await deploymentManager.hre.ethers.provider.getBalance(recipient)), + WETH: await WETH.balanceOf(recipient), + }; + + const aeraVault = new Contract( + AERA_VAULT, + ['function pendingOwner() view returns (address)'], + await deploymentManager.getSigner() + ); + const pendingVaultOwner = await aeraVault.pendingOwner(); + expect(pendingVaultOwner).to.equal(newVaultOwner); + + const avantgardeVault = new Contract( + AVANTGARDE_VAULT, + ['function getOwners() view returns (address[])'], + await deploymentManager.getSigner() + ); + const vaultOwner2 = await avantgardeVault.getOwners(); + expect(vaultOwner2).to.deep.equal([newVaultOwner]); + + expect(balancesAfter.WBTC.sub(balancesBefore.WBTC)).to.equal(exp(withdrawConfigV2.cWBTC2.amount, withdrawConfigV2.cWBTC2.decimals)); + expect(balancesAfter.USDC.sub(balancesBefore.USDC)).to.equal( + exp(withdrawConfigV2.cUSDC.amount, withdrawConfigV2.cUSDC.decimals) + + exp(withdrawConfigV3.mainnet.cUSDCv3.amount, withdrawConfigV3.mainnet.cUSDCv3.decimals) + + exp(withdrawConfigV3.optimism.cUSDCv3.amount, withdrawConfigV3.optimism.cUSDCv3.decimals) + + exp(withdrawConfigV3.base.cUSDbCv3.amount, withdrawConfigV3.base.cUSDbCv3.decimals) + + exp(withdrawConfigV3.arbitrum.cUSDCv3.amount, withdrawConfigV3.arbitrum.cUSDCv3.decimals) + + exp(withdrawConfigV3.arbitrum.cUSDCev3.amount, withdrawConfigV3.arbitrum.cUSDCev3.decimals) + ); + expect(balancesAfter.USDT.sub(balancesBefore.USDT)).to.equal( + exp(withdrawConfigV2.cUSDT.amount, withdrawConfigV2.cUSDT.decimals) + + exp(withdrawConfigV3.optimism.cUSDTv3.amount, withdrawConfigV3.optimism.cUSDTv3.decimals) + ); + expect(balancesAfter.BAT.sub(balancesBefore.BAT)).to.equal(exp(withdrawConfigV2.cBAT.amount, withdrawConfigV2.cBAT.decimals)); + expect(balancesAfter.UNI.sub(balancesBefore.UNI)).to.equal(exp(withdrawConfigV2.cUNI.amount, withdrawConfigV2.cUNI.decimals)); + expect(balancesAfter.TUSD.sub(balancesBefore.TUSD)).to.equal(exp(withdrawConfigV2.cTUSD.amount, withdrawConfigV2.cTUSD.decimals)); + expect(balancesAfter.LINK.sub(balancesBefore.LINK)).to.equal(exp(withdrawConfigV2.cLINK.amount, withdrawConfigV2.cLINK.decimals)); + expect(balancesAfter.AAVE.sub(balancesBefore.AAVE)).to.equal(exp(withdrawConfigV2.cAAVE.amount, withdrawConfigV2.cAAVE.decimals)); + expect(balancesAfter.COMP.sub(balancesBefore.COMP)).to.equal(exp(withdrawConfigV2.cCOMP.amount, withdrawConfigV2.cCOMP.decimals)); + expect(balancesAfter.ETH.sub(balancesBefore.ETH)).to.equal(exp(withdrawConfigV2.cETH.amount, withdrawConfigV2.cETH.decimals)); + expect(balancesAfter.WETH.sub(balancesBefore.WETH)).to.equal(exp(withdrawConfigV3.arbitrum.cWETHv3.amount, withdrawConfigV3.arbitrum.cWETHv3.decimals)); + }, +}); diff --git a/deployments/mainnet/usdc/migrations/1776768296_update_curve_params_on_l2.ts b/deployments/mainnet/usdc/migrations/1776768296_update_curve_params_on_l2.ts new file mode 100644 index 000000000..2cb140437 --- /dev/null +++ b/deployments/mainnet/usdc/migrations/1776768296_update_curve_params_on_l2.ts @@ -0,0 +1,483 @@ +import { expect } from 'chai'; +import { BigNumber, utils } from 'ethers'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { proposal } from '../../../../src/deploy'; +import { forkedHreForBase } from '../../../../plugins/scenario/utils/hreForBase'; +import { applyL1ToL2Alias, estimateL2Transaction } from '../../../../scenario/utils/arbitrumUtils'; + +/* +Comet Kink Rate Max Rate +Base WETH 1.50% 3.00% +Arbitrum WETH 1.50% 3.00% +Optimism WETH 1.50% 3.00% +Linea WETH 1.50% 3.00% +Unichain WETH 1.50% 3.00% + +Params: + +Optimism WETH changes +borrowPerYearInterestRateSlopeLow : 5555555555555555 +borrowPerYearInterestRateSlopeHigh : 150000000000000000 +supplyPerYearInterestRateSlopeLow : 15000000000000000 +supplyPerYearInterestRateSlopeHigh : 135000000000000000 + +Base WETH changes +borrowPerYearInterestRateSlopeLow : 5555555555555555 +borrowPerYearInterestRateSlopeHigh : 150000000000000000 +supplyPerYearInterestRateSlopeLow : 15000000000000000 +supplyPerYearInterestRateSlopeHigh : 135000000000000000 + +Arbitrum WETH changes +borrowPerYearInterestRateSlopeLow : 5555555555555555 +borrowPerYearInterestRateSlopeHigh : 150000000000000000 +supplyPerYearInterestRateSlopeLow : 15000000000000000 +supplyPerYearInterestRateSlopeHigh : 135000000000000000 + +Linea WETH changes +borrowPerYearInterestRateSlopeLow : 5555555555555555 +borrowPerYearInterestRateSlopeHigh : 150000000000000000 +supplyPerYearInterestRateSlopeLow : 15000000000000000 +supplyPerYearInterestRateSlopeHigh : 135000000000000000 + +Unichain WETH changes +borrowPerYearInterestRateSlopeLow : 5555555555555555 +borrowPerYearInterestRateSlopeHigh : 150000000000000000 +supplyPerYearInterestRateSlopeLow : 15000000000000000 +supplyPerYearInterestRateSlopeHigh : 135000000000000000 + +*/ +const borrowPerYearInterestRateSlopeLow = '5555555555555555'; +const borrowPerYearInterestRateSlopeHigh = '150000000000000000'; + +const supplyPerYearInterestRateSlopeLow = '15000000000000000'; +const supplyPerYearInterestRateSlopeHigh = '135000000000000000'; + +let expectedBorrowPerSecondInterestRateSlopeLow: BigNumber; +let expectedBorrowPerSecondInterestRateSlopeHigh: BigNumber; + +let expectedSupplyPerSecondInterestRateSlopeLow: BigNumber; +let expectedSupplyPerSecondInterestRateSlopeHigh: BigNumber; + +export default migration('1776768296_update_curve_params_on_l2', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const { + timelock, + governor, + opL1CrossDomainMessenger, + baseL1CrossDomainMessenger, + arbitrumInbox, + lineaMessageService, + unichainL1CrossDomainMessenger + } = await deploymentManager.getContracts(); + + expectedBorrowPerSecondInterestRateSlopeLow = BigNumber.from(borrowPerYearInterestRateSlopeLow).div(365 * 86400); + expectedBorrowPerSecondInterestRateSlopeHigh = BigNumber.from(borrowPerYearInterestRateSlopeHigh).div(365 * 86400); + + expectedSupplyPerSecondInterestRateSlopeLow = BigNumber.from(supplyPerYearInterestRateSlopeLow).div(365 * 86400); + expectedSupplyPerSecondInterestRateSlopeHigh = BigNumber.from(supplyPerYearInterestRateSlopeHigh).div(365 * 86400); + + // Optimism + const opHre = await forkedHreForBase({ name: 'optimism-weth', network: 'optimism', deployment: 'weth' }); + const opDm = await deploymentManager.addBridgedDeploymentManager('optimism', 'weth', opHre); + const { + bridgeReceiver : opBridgeReceiver, + configurator: opConfigurator, + cometAdmin: opCometAdmin, + comet: opWethComet, + } = await opDm.getContracts(); + + const optimismSetBorrowPerYearInterestRateSlopeLowCalldata = utils.defaultAbiCoder.encode(['address', 'uint64'], [opWethComet.address, borrowPerYearInterestRateSlopeLow]); + const optimismSetBorrowPerYearInterestRateSlopeHighCalldata = utils.defaultAbiCoder.encode(['address', 'uint64'], [opWethComet.address, borrowPerYearInterestRateSlopeHigh]); + const optimismSetSupplyPerYearInterestRateSlopeLowCalldata = utils.defaultAbiCoder.encode(['address', 'uint64'], [opWethComet.address, supplyPerYearInterestRateSlopeLow]); + const optimismSetSupplyPerYearInterestRateSlopeHighCalldata = utils.defaultAbiCoder.encode(['address', 'uint64'], [opWethComet.address, supplyPerYearInterestRateSlopeHigh]); + const optimismDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [opConfigurator.address, opWethComet.address]); + + const opProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + opConfigurator.address, opConfigurator.address, + opConfigurator.address, opConfigurator.address, + opCometAdmin.address, + ], + [ + 0, 0, + 0, 0, + 0 + ], + [ + 'setBorrowPerYearInterestRateSlopeLow(address,uint64)', + 'setBorrowPerYearInterestRateSlopeHigh(address,uint64)', + 'setSupplyPerYearInterestRateSlopeLow(address,uint64)', + 'setSupplyPerYearInterestRateSlopeHigh(address,uint64)', + 'deployAndUpgradeTo(address,address)', + ], + [ + optimismSetBorrowPerYearInterestRateSlopeLowCalldata, optimismSetBorrowPerYearInterestRateSlopeHighCalldata, + optimismSetSupplyPerYearInterestRateSlopeLowCalldata, optimismSetSupplyPerYearInterestRateSlopeHighCalldata, + optimismDeployAndUpgradeToCalldata + ], + ] + ); + + // Base + const baseHre = await forkedHreForBase({ name: 'base-weth', network: 'base', deployment: 'weth' }); + const baseDm = await deploymentManager.addBridgedDeploymentManager('base', 'weth', baseHre); + const { + bridgeReceiver : baseBridgeReceiver, + configurator: baseConfigurator, + cometAdmin: baseCometAdmin, + comet: baseWethComet, + } = await baseDm.getContracts(); + + const baseSetBorrowPerYearInterestRateSlopeLowCalldata = utils.defaultAbiCoder.encode(['address', 'uint64'], [baseWethComet.address, borrowPerYearInterestRateSlopeLow]); + const baseSetBorrowPerYearInterestRateSlopeHighCalldata = utils.defaultAbiCoder.encode(['address', 'uint64'], [baseWethComet.address, borrowPerYearInterestRateSlopeHigh]); + const baseSetSupplyPerYearInterestRateSlopeLowCalldata = utils.defaultAbiCoder.encode(['address', 'uint64'], [baseWethComet.address, supplyPerYearInterestRateSlopeLow]); + const baseSetSupplyPerYearInterestRateSlopeHighCalldata = utils.defaultAbiCoder.encode(['address', 'uint64'], [baseWethComet.address, supplyPerYearInterestRateSlopeHigh]); + const baseDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [baseConfigurator.address, baseWethComet.address]); + + const baseProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + baseConfigurator.address, baseConfigurator.address, + baseConfigurator.address, baseConfigurator.address, + baseCometAdmin.address, + ], + [ + 0, 0, + 0, 0, + 0 + ], + [ + 'setBorrowPerYearInterestRateSlopeLow(address,uint64)', + 'setBorrowPerYearInterestRateSlopeHigh(address,uint64)', + 'setSupplyPerYearInterestRateSlopeLow(address,uint64)', + 'setSupplyPerYearInterestRateSlopeHigh(address,uint64)', + 'deployAndUpgradeTo(address,address)', + ], + [ + baseSetBorrowPerYearInterestRateSlopeLowCalldata, baseSetBorrowPerYearInterestRateSlopeHighCalldata, + baseSetSupplyPerYearInterestRateSlopeLowCalldata, baseSetSupplyPerYearInterestRateSlopeHighCalldata, + baseDeployAndUpgradeToCalldata + ], + ] + ); + + // Arbitrum + const arbitrumHre = await forkedHreForBase({ name: 'arbitrum-weth', network: 'arbitrum', deployment: 'weth' }); + const arbitrumDm = await deploymentManager.addBridgedDeploymentManager('arbitrum', 'weth', arbitrumHre); + const { + bridgeReceiver: arbitrumBridgeReceiver, + configurator: arbitrumConfigurator, + cometAdmin: arbitrumCometAdmin, + comet: arbitrumWethComet, + timelock: arbitrumTimelock, + } = await arbitrumDm.getContracts(); + + const arbitrumSetBorrowPerYearInterestRateSlopeLowCalldata = utils.defaultAbiCoder.encode(['address', 'uint64'], [arbitrumWethComet.address, borrowPerYearInterestRateSlopeLow]); + const arbitrumSetBorrowPerYearInterestRateSlopeHighCalldata = utils.defaultAbiCoder.encode(['address', 'uint64'], [arbitrumWethComet.address, borrowPerYearInterestRateSlopeHigh]); + const arbitrumSetSupplyPerYearInterestRateSlopeLowCalldata = utils.defaultAbiCoder.encode(['address', 'uint64'], [arbitrumWethComet.address, supplyPerYearInterestRateSlopeLow]); + const arbitrumSetSupplyPerYearInterestRateSlopeHighCalldata = utils.defaultAbiCoder.encode(['address', 'uint64'], [arbitrumWethComet.address, supplyPerYearInterestRateSlopeHigh]); + const arbitrumDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [arbitrumConfigurator.address, arbitrumWethComet.address]); + + const arbitrumProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + arbitrumConfigurator.address, arbitrumConfigurator.address, + arbitrumConfigurator.address, arbitrumConfigurator.address, + arbitrumCometAdmin.address, + ], + [ + 0, 0, + 0, 0, + 0 + ], + [ + 'setBorrowPerYearInterestRateSlopeLow(address,uint64)', + 'setBorrowPerYearInterestRateSlopeHigh(address,uint64)', + 'setSupplyPerYearInterestRateSlopeLow(address,uint64)', + 'setSupplyPerYearInterestRateSlopeHigh(address,uint64)', + 'deployAndUpgradeTo(address,address)', + ], + [ + arbitrumSetBorrowPerYearInterestRateSlopeLowCalldata, arbitrumSetBorrowPerYearInterestRateSlopeHighCalldata, + arbitrumSetSupplyPerYearInterestRateSlopeLowCalldata, arbitrumSetSupplyPerYearInterestRateSlopeHighCalldata, + arbitrumDeployAndUpgradeToCalldata + ], + ] + ); + const createRetryableTicketGasParams = await estimateL2Transaction( + { + from: applyL1ToL2Alias(timelock.address), + to: arbitrumBridgeReceiver.address, + data: arbitrumProposalData + }, + arbitrumDm + ); + + // Linea + const lineaHre = await forkedHreForBase({ name: 'linea-weth', network: 'linea', deployment: 'weth' }); + const lineaDm = await deploymentManager.addBridgedDeploymentManager('linea', 'weth', lineaHre); + const { + bridgeReceiver: lineaBridgeReceiver, + configurator: lineaConfigurator, + cometAdmin: lineaCometAdmin, + comet: lineaWethComet, + } = await lineaDm.getContracts(); + + const lineaSetBorrowPerYearInterestRateSlopeLowCalldata = utils.defaultAbiCoder.encode(['address', 'uint64'], [lineaWethComet.address, borrowPerYearInterestRateSlopeLow]); + const lineaSetBorrowPerYearInterestRateSlopeHighCalldata = utils.defaultAbiCoder.encode(['address', 'uint64'], [lineaWethComet.address, borrowPerYearInterestRateSlopeHigh]); + const lineaSetSupplyPerYearInterestRateSlopeLowCalldata = utils.defaultAbiCoder.encode(['address', 'uint64'], [lineaWethComet.address, supplyPerYearInterestRateSlopeLow]); + const lineaSetSupplyPerYearInterestRateSlopeHighCalldata = utils.defaultAbiCoder.encode(['address', 'uint64'], [lineaWethComet.address, supplyPerYearInterestRateSlopeHigh]); + const lineaDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [lineaConfigurator.address, lineaWethComet.address]); + + const lineaProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + lineaConfigurator.address, lineaConfigurator.address, + lineaConfigurator.address, lineaConfigurator.address, + lineaCometAdmin.address, + ], + [ + 0, 0, + 0, 0, + 0 + ], + [ + 'setBorrowPerYearInterestRateSlopeLow(address,uint64)', + 'setBorrowPerYearInterestRateSlopeHigh(address,uint64)', + 'setSupplyPerYearInterestRateSlopeLow(address,uint64)', + 'setSupplyPerYearInterestRateSlopeHigh(address,uint64)', + 'deployAndUpgradeTo(address,address)', + ], + [ + lineaSetBorrowPerYearInterestRateSlopeLowCalldata, lineaSetBorrowPerYearInterestRateSlopeHighCalldata, + lineaSetSupplyPerYearInterestRateSlopeLowCalldata, lineaSetSupplyPerYearInterestRateSlopeHighCalldata, + lineaDeployAndUpgradeToCalldata + ], + ] + ); + + // Unichain + const unichainHre = await forkedHreForBase({ name: 'unichain-weth', network: 'unichain', deployment: 'weth' }); + const unichainDm = await deploymentManager.addBridgedDeploymentManager('unichain', 'weth', unichainHre); + const { + bridgeReceiver: unichainBridgeReceiver, + configurator: unichainConfigurator, + cometAdmin: unichainCometAdmin, + comet: unichainWethComet, + } = await unichainDm.getContracts(); + + const unichainSetBorrowPerYearInterestRateSlopeLowCalldata = utils.defaultAbiCoder.encode(['address', 'uint64'], [unichainWethComet.address, borrowPerYearInterestRateSlopeLow]); + const unichainSetBorrowPerYearInterestRateSlopeHighCalldata = utils.defaultAbiCoder.encode(['address', 'uint64'], [unichainWethComet.address, borrowPerYearInterestRateSlopeHigh]); + const unichainSetSupplyPerYearInterestRateSlopeLowCalldata = utils.defaultAbiCoder.encode(['address', 'uint64'], [unichainWethComet.address, supplyPerYearInterestRateSlopeLow]); + const unichainSetSupplyPerYearInterestRateSlopeHighCalldata = utils.defaultAbiCoder.encode(['address', 'uint64'], [unichainWethComet.address, supplyPerYearInterestRateSlopeHigh]); + const unichainDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [unichainConfigurator.address, unichainWethComet.address]); + + const unichainProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + unichainConfigurator.address, unichainConfigurator.address, + unichainConfigurator.address, unichainConfigurator.address, + unichainCometAdmin.address, + ], + [ + 0, 0, + 0, 0, + 0 + ], + [ + 'setBorrowPerYearInterestRateSlopeLow(address,uint64)', + 'setBorrowPerYearInterestRateSlopeHigh(address,uint64)', + 'setSupplyPerYearInterestRateSlopeLow(address,uint64)', + 'setSupplyPerYearInterestRateSlopeHigh(address,uint64)', + 'deployAndUpgradeTo(address,address)', + ], + [ + unichainSetBorrowPerYearInterestRateSlopeLowCalldata, unichainSetBorrowPerYearInterestRateSlopeHighCalldata, + unichainSetSupplyPerYearInterestRateSlopeLowCalldata, unichainSetSupplyPerYearInterestRateSlopeHighCalldata, + unichainDeployAndUpgradeToCalldata + ], + ] + ); + + + + const mainnetActions = [ + // Optimism proposal + { + contract: opL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [opBridgeReceiver.address, opProposalData, 3_000_000] + }, + // Base proposal + { + contract: baseL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [baseBridgeReceiver.address, baseProposalData, 3_000_000] + }, + // Arbitrum proposal + { + contract: arbitrumInbox, + signature: 'createRetryableTicket(address,uint256,uint256,address,address,uint256,uint256,bytes)', + args: [ + arbitrumBridgeReceiver.address, // address to, + 0, // uint256 l2CallValue, + createRetryableTicketGasParams.maxSubmissionCost, // uint256 maxSubmissionCost, + arbitrumTimelock.address, // address excessFeeRefundAddress, + arbitrumTimelock.address, // address callValueRefundAddress, + createRetryableTicketGasParams.gasLimit, // uint256 gasLimit, + createRetryableTicketGasParams.maxFeePerGas*2, // uint256 maxFeePerGas, + arbitrumProposalData, // bytes calldata data + ], + value: createRetryableTicketGasParams.deposit.mul(2), + }, + // Linea proposal + { + contract: lineaMessageService, + signature: 'sendMessage(address,uint256,bytes)', + args: [lineaBridgeReceiver.address, 0, lineaProposalData], + }, + // Unichain proposal + { + contract: unichainL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [unichainBridgeReceiver.address, unichainProposalData, 3_000_000], + }, + ]; + + const description = `# WETH Comets Interest Rate Curve Recommendations on L2 networks + +## Simple Summary + +Given heightened market activity and elevated volatility across ETH markets Gauntlet recommends the following Interest Rate (IR) Curve updates across WETH comets on L2 networks. These changes are designed to keep borrow costs low and avoid liquidations during the volatile period. + +## Motivation +The recent Kelp exploit has led to heightened volatility and shifting dynamics across ETH-correlated assets. In this environment LST/LRT-based looping strategies are facing a significantly high negative carry. The recommendations below flatten the slope below kink and compress the slope above kink resulting in lower kink and max borrow rates across all WETH markets. + +The intent is to: +* Keep Compound’s WETH borrow rates not too high so that unwinding can happen gradually in a volatile environment. +* Decrease existing borrow positions gradually without pushing rates to a level that would unwind a high amount of the existing ETH-leverage positions. We will continue to monitor utilization and reserve growth and will adjust as conditions evolve. + +## Specification +Target APRs at kink and at 100% utilization across the comets: +| Comet | Kink Rate | Max Rate | +| --------------- | --------- | -------- | +| Base WETH | 1.50% | 3.00% | +| Arbitrum WETH | 1.50% | 3.00% | +| Optimism WETH | 1.50% | 3.00% | +| Linea WETH | 1.50% | 3.00% | +| Unichain WETH | 1.50% | 3.00% | +Borrow kink is held at 90% across all markets. The base rate is held constant at current values. Slope Low and Slope High are updated to achieve the target kink and max rates above. [Forum Post](https://www.comp.xyz/t/weth-comet-interest-rate-curve-recommendations/7749)`; + + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 600_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + // Optimism + const opDm = deploymentManager.bridgedDeploymentManagers.get('optimism:weth') as DeploymentManager; + const { comet } = await opDm.getContracts(); + + const currentBorrowPerSecondInterestRateSlopeLow = await comet.borrowPerSecondInterestRateSlopeLow(); + const currentBorrowPerSecondInterestRateSlopeHigh = await comet.borrowPerSecondInterestRateSlopeHigh(); + + const currentSupplyPerSecondInterestRateSlopeLow = await comet.supplyPerSecondInterestRateSlopeLow(); + const currentSupplyPerSecondInterestRateSlopeHigh = await comet.supplyPerSecondInterestRateSlopeHigh(); + + expect(currentBorrowPerSecondInterestRateSlopeLow.toString()).to.equal(expectedBorrowPerSecondInterestRateSlopeLow.toString()); + expect(currentBorrowPerSecondInterestRateSlopeHigh.toString()).to.equal(expectedBorrowPerSecondInterestRateSlopeHigh.toString()); + + expect(currentSupplyPerSecondInterestRateSlopeLow.toString()).to.equal(expectedSupplyPerSecondInterestRateSlopeLow.toString()); + expect(currentSupplyPerSecondInterestRateSlopeHigh.toString()).to.equal(expectedSupplyPerSecondInterestRateSlopeHigh.toString()); + + // Base + const baseDm = deploymentManager.bridgedDeploymentManagers.get('base:weth') as DeploymentManager; + const { comet: baseComet } = await baseDm.getContracts(); + + const baseCurrentBorrowPerSecondInterestRateSlopeLow = await baseComet.borrowPerSecondInterestRateSlopeLow(); + const baseCurrentBorrowPerSecondInterestRateSlopeHigh = await baseComet.borrowPerSecondInterestRateSlopeHigh(); + + const baseCurrentSupplyPerSecondInterestRateSlopeLow = await baseComet.supplyPerSecondInterestRateSlopeLow(); + const baseCurrentSupplyPerSecondInterestRateSlopeHigh = await baseComet.supplyPerSecondInterestRateSlopeHigh(); + + expect(baseCurrentBorrowPerSecondInterestRateSlopeLow.toString()).to.equal(expectedBorrowPerSecondInterestRateSlopeLow.toString()); + expect(baseCurrentBorrowPerSecondInterestRateSlopeHigh.toString()).to.equal(expectedBorrowPerSecondInterestRateSlopeHigh.toString()); + + expect(baseCurrentSupplyPerSecondInterestRateSlopeLow.toString()).to.equal(expectedSupplyPerSecondInterestRateSlopeLow.toString()); + expect(baseCurrentSupplyPerSecondInterestRateSlopeHigh.toString()).to.equal(expectedSupplyPerSecondInterestRateSlopeHigh.toString()); + + // Arbitrum + const arbitrumDm = deploymentManager.bridgedDeploymentManagers.get('arbitrum:weth') as DeploymentManager; + const { comet: arbitrumComet } = await arbitrumDm.getContracts(); + + const arbitrumCurrentBorrowPerSecondInterestRateSlopeLow = await arbitrumComet.borrowPerSecondInterestRateSlopeLow(); + const arbitrumCurrentBorrowPerSecondInterestRateSlopeHigh = await arbitrumComet.borrowPerSecondInterestRateSlopeHigh(); + + const arbitrumCurrentSupplyPerSecondInterestRateSlopeLow = await arbitrumComet.supplyPerSecondInterestRateSlopeLow(); + const arbitrumCurrentSupplyPerSecondInterestRateSlopeHigh = await arbitrumComet.supplyPerSecondInterestRateSlopeHigh(); + + expect(arbitrumCurrentBorrowPerSecondInterestRateSlopeLow.toString()).to.equal(expectedBorrowPerSecondInterestRateSlopeLow.toString()); + expect(arbitrumCurrentBorrowPerSecondInterestRateSlopeHigh.toString()).to.equal(expectedBorrowPerSecondInterestRateSlopeHigh.toString()); + + expect(arbitrumCurrentSupplyPerSecondInterestRateSlopeLow.toString()).to.equal(expectedSupplyPerSecondInterestRateSlopeLow.toString()); + expect(arbitrumCurrentSupplyPerSecondInterestRateSlopeHigh.toString()).to.equal(expectedSupplyPerSecondInterestRateSlopeHigh.toString()); + + // Linea + const lineaDm = deploymentManager.bridgedDeploymentManagers.get('linea:weth') as DeploymentManager; + const { comet: lineaComet } = await lineaDm.getContracts(); + + const lineaCurrentBorrowPerSecondInterestRateSlopeLow = await lineaComet.borrowPerSecondInterestRateSlopeLow(); + const lineaCurrentBorrowPerSecondInterestRateSlopeHigh = await lineaComet.borrowPerSecondInterestRateSlopeHigh(); + + const lineaCurrentSupplyPerSecondInterestRateSlopeLow = await lineaComet.supplyPerSecondInterestRateSlopeLow(); + const lineaCurrentSupplyPerSecondInterestRateSlopeHigh = await lineaComet.supplyPerSecondInterestRateSlopeHigh(); + + expect(lineaCurrentBorrowPerSecondInterestRateSlopeLow.toString()).to.equal(expectedBorrowPerSecondInterestRateSlopeLow.toString()); + expect(lineaCurrentBorrowPerSecondInterestRateSlopeHigh.toString()).to.equal(expectedBorrowPerSecondInterestRateSlopeHigh.toString()); + + expect(lineaCurrentSupplyPerSecondInterestRateSlopeLow.toString()).to.equal(expectedSupplyPerSecondInterestRateSlopeLow.toString()); + expect(lineaCurrentSupplyPerSecondInterestRateSlopeHigh.toString()).to.equal(expectedSupplyPerSecondInterestRateSlopeHigh.toString()); + + // Unichain + const unichainDm = deploymentManager.bridgedDeploymentManagers.get('unichain:weth') as DeploymentManager; + const { comet: unichainComet } = await unichainDm.getContracts(); + + const unichainCurrentBorrowPerSecondInterestRateSlopeLow = await unichainComet.borrowPerSecondInterestRateSlopeLow(); + const unichainCurrentBorrowPerSecondInterestRateSlopeHigh = await unichainComet.borrowPerSecondInterestRateSlopeHigh(); + + const unichainCurrentSupplyPerSecondInterestRateSlopeLow = await unichainComet.supplyPerSecondInterestRateSlopeLow(); + const unichainCurrentSupplyPerSecondInterestRateSlopeHigh = await unichainComet.supplyPerSecondInterestRateSlopeHigh(); + + expect(unichainCurrentBorrowPerSecondInterestRateSlopeLow.toString()).to.equal(expectedBorrowPerSecondInterestRateSlopeLow.toString()); + expect(unichainCurrentBorrowPerSecondInterestRateSlopeHigh.toString()).to.equal(expectedBorrowPerSecondInterestRateSlopeHigh.toString()); + + expect(unichainCurrentSupplyPerSecondInterestRateSlopeLow.toString()).to.equal(expectedSupplyPerSecondInterestRateSlopeLow.toString()); + expect(unichainCurrentSupplyPerSecondInterestRateSlopeHigh.toString()).to.equal(expectedSupplyPerSecondInterestRateSlopeHigh.toString()); + }, +}); \ No newline at end of file diff --git a/deployments/mainnet/usdc/migrations/1776940217_update_rseth_pricefeeds_across_l2.ts b/deployments/mainnet/usdc/migrations/1776940217_update_rseth_pricefeeds_across_l2.ts new file mode 100644 index 000000000..b19841338 --- /dev/null +++ b/deployments/mainnet/usdc/migrations/1776940217_update_rseth_pricefeeds_across_l2.ts @@ -0,0 +1,441 @@ +import { expect } from 'chai'; +import { utils } from 'ethers'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { proposal } from '../../../../src/deploy'; +import { forkedHreForBase } from '../../../../plugins/scenario/utils/hreForBase'; +import { applyL1ToL2Alias, estimateL2Transaction } from '../../../../scenario/utils/arbitrumUtils'; + +let optimismPriceFeedAddress: string; +let arbitrumPriceFeedAddress: string; +let basePriceFeedAddress: string; +let lineaPriceFeedAddress: string; +let unichainPriceFeedAddress: string; + +export default migration('1776940217_update_rseth_pricefeeds_across_l2', { + async prepare(deploymentManager: DeploymentManager) { + // Optimism + const opHre = await forkedHreForBase({ name: 'optimism-weth', network: 'optimism', deployment: 'weth' }); + const opDm = await deploymentManager.addBridgedDeploymentManager('optimism', 'weth', opHre); + + const optimismRsETHPriceFeed = await opDm.deploy( + 'wrsETH:priceFeed', + 'pricefeeds/ConstantPriceFeed.sol', + [ + 8, // decimals + 1 // constantPrice + ], + true + ); + + // Base + const baseHre = await forkedHreForBase({ name: 'base-weth', network: 'base', deployment: 'weth' }); + const baseDm = await deploymentManager.addBridgedDeploymentManager('base', 'weth', baseHre); + + const baseRsETHPriceFeed = await baseDm.deploy( + 'wrsETH:priceFeed', + 'pricefeeds/ConstantPriceFeed.sol', + [ + 8, // decimals + 1 // constantPrice + ], + true + ); + + // Arbitrum + const arbitrumHre = await forkedHreForBase({ name: 'arbitrum-weth', network: 'arbitrum', deployment: 'weth' }); + const arbitrumDm = await deploymentManager.addBridgedDeploymentManager('arbitrum', 'weth', arbitrumHre); + + const arbitrumRsETHPriceFeed = await arbitrumDm.deploy( + 'rsETH:priceFeed', + 'pricefeeds/ConstantPriceFeed.sol', + [ + 8, // decimals + 1 // constantPrice + ], + true + ); + + // Linea + const lineaHre = await forkedHreForBase({ name: 'linea-weth', network: 'linea', deployment: 'weth' }); + const lineaDm = await deploymentManager.addBridgedDeploymentManager('linea', 'weth', lineaHre); + + const lineaRsETHPriceFeed = await lineaDm.deploy( + 'wrsETH:priceFeed', + 'pricefeeds/ConstantPriceFeed.sol', + [ + 8, // decimals + 1 // constantPrice + ], + true + ); + + // Unichain + const unichainHre = await forkedHreForBase({ name: 'unichain-weth', network: 'unichain', deployment: 'weth' }); + const unichainDm = await deploymentManager.addBridgedDeploymentManager('unichain', 'weth', unichainHre); + + const unichainRsETHPriceFeed = await unichainDm.deploy( + 'rsETH:priceFeed', + 'pricefeeds/ConstantPriceFeed.sol', + [ + 8, // decimals + 1 // constantPrice + ], + true + ); + + optimismPriceFeedAddress = optimismRsETHPriceFeed.address; + arbitrumPriceFeedAddress = arbitrumRsETHPriceFeed.address; + basePriceFeedAddress = baseRsETHPriceFeed.address; + lineaPriceFeedAddress = lineaRsETHPriceFeed.address; + unichainPriceFeedAddress = unichainRsETHPriceFeed.address; + + return {}; + }, + + async enact(deploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const { + timelock, + governor, + opL1CrossDomainMessenger, + baseL1CrossDomainMessenger, + arbitrumInbox, + lineaMessageService, + unichainL1CrossDomainMessenger + } = await deploymentManager.getContracts(); + + // Optimism + // const opHre = await forkedHreForBase({ name: 'optimism-weth', network: 'optimism', deployment: 'weth' }); + // const opDm = await deploymentManager.addBridgedDeploymentManager('optimism', 'weth', opHre); + const opDm = await deploymentManager.bridgedDeploymentManagers.get('optimism:weth') as DeploymentManager; + const { + bridgeReceiver : opBridgeReceiver, + configurator: opConfigurator, + cometAdmin: opCometAdmin, + comet: opWethComet, + wrsETH: opRsETH, + } = await opDm.getContracts(); + + const optimismUpdateAssetPriceFeedCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'address'], [opWethComet.address, opRsETH.address, optimismPriceFeedAddress]); + const optimismDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [opConfigurator.address, opWethComet.address]); + + const opProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + opConfigurator.address, + opCometAdmin.address, + ], + [ + 0, 0, + ], + [ + 'updateAssetPriceFeed(address,address,address)', + 'deployAndUpgradeTo(address,address)', + ], + [ + optimismUpdateAssetPriceFeedCalldata, + optimismDeployAndUpgradeToCalldata + ], + ] + ); + + // Base + // const baseHre = await forkedHreForBase({ name: 'base-weth', network: 'base', deployment: 'weth' }); + // const baseDm = await deploymentManager.addBridgedDeploymentManager('base', 'weth', baseHre); + const baseDm = await deploymentManager.bridgedDeploymentManagers.get('base:weth') as DeploymentManager; + const { + bridgeReceiver : baseBridgeReceiver, + configurator: baseConfigurator, + cometAdmin: baseCometAdmin, + comet: baseWethComet, + wrsETH: baseRsETH, + } = await baseDm.getContracts(); + + const baseUpdateAssetPriceFeedCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'address'], [baseWethComet.address, baseRsETH.address, basePriceFeedAddress]); + const baseDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [baseConfigurator.address, baseWethComet.address]); + + const baseProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + baseConfigurator.address, + baseCometAdmin.address, + ], + [ + 0, 0 + ], + [ + 'updateAssetPriceFeed(address,address,address)', + 'deployAndUpgradeTo(address,address)', + ], + [ + baseUpdateAssetPriceFeedCalldata, + baseDeployAndUpgradeToCalldata + ], + ] + ); + + // Arbitrum + // const arbitrumHre = await forkedHreForBase({ name: 'arbitrum-weth', network: 'arbitrum', deployment: 'weth' }); + // const arbitrumDm = await deploymentManager.addBridgedDeploymentManager('arbitrum', 'weth', arbitrumHre); + const arbitrumDm = await deploymentManager.bridgedDeploymentManagers.get('arbitrum:weth') as DeploymentManager; + const { + bridgeReceiver: arbitrumBridgeReceiver, + configurator: arbitrumConfigurator, + cometAdmin: arbitrumCometAdmin, + comet: arbitrumWethComet, + timelock: arbitrumTimelock, + rsETH: arbitrumRsETH, + } = await arbitrumDm.getContracts(); + + const arbitrumUpdateAssetPriceFeedCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'address'], [arbitrumWethComet.address, arbitrumRsETH.address, arbitrumPriceFeedAddress]); + const arbitrumDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [arbitrumConfigurator.address, arbitrumWethComet.address]); + + const arbitrumProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + arbitrumConfigurator.address, + arbitrumCometAdmin.address, + ], + [ + 0, 0, + ], + [ + 'updateAssetPriceFeed(address,address,address)', + 'deployAndUpgradeTo(address,address)', + ], + [ + arbitrumUpdateAssetPriceFeedCalldata, + arbitrumDeployAndUpgradeToCalldata + ], + ] + ); + const createRetryableTicketGasParams = await estimateL2Transaction( + { + from: applyL1ToL2Alias(timelock.address), + to: arbitrumBridgeReceiver.address, + data: arbitrumProposalData + }, + arbitrumDm + ); + + // Linea + // const lineaHre = await forkedHreForBase({ name: 'linea-weth', network: 'linea', deployment: 'weth' }); + // const lineaDm = await deploymentManager.addBridgedDeploymentManager('linea', 'weth', lineaHre); + const lineaDm = await deploymentManager.bridgedDeploymentManagers.get('linea:weth') as DeploymentManager; + const { + bridgeReceiver: lineaBridgeReceiver, + configurator: lineaConfigurator, + cometAdmin: lineaCometAdmin, + comet: lineaWethComet, + wrsETH: lineaRsETH, + } = await lineaDm.getContracts(); + + const updateAssetPriceFeedCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'address'], [lineaWethComet.address, lineaRsETH.address, lineaPriceFeedAddress]); + const lineaDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [lineaConfigurator.address, lineaWethComet.address]); + + const lineaProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + lineaConfigurator.address, + lineaCometAdmin.address, + ], + [ + 0, 0, + ], + [ + 'updateAssetPriceFeed(address,address,address)', + 'deployAndUpgradeTo(address,address)', + ], + [ + updateAssetPriceFeedCalldata, + lineaDeployAndUpgradeToCalldata + ], + ] + ); + + // Unichain + // const unichainHre = await forkedHreForBase({ name: 'unichain-weth', network: 'unichain', deployment: 'weth' }); + // const unichainDm = await deploymentManager.addBridgedDeploymentManager('unichain', 'weth', unichainHre); + const unichainDm = await deploymentManager.bridgedDeploymentManagers.get('unichain:weth') as DeploymentManager; + const { + bridgeReceiver: unichainBridgeReceiver, + configurator: unichainConfigurator, + cometAdmin: unichainCometAdmin, + comet: unichainWethComet, + rsETH: unichainRsETH, + } = await unichainDm.getContracts(); + + const unichainUpdateAssetPriceFeedCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'address'], [unichainWethComet.address, unichainRsETH.address, unichainPriceFeedAddress]); + const unichainDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [unichainConfigurator.address, unichainWethComet.address]); + + const unichainProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + unichainConfigurator.address, + unichainCometAdmin.address, + ], + [ + 0, 0, + ], + [ + 'updateAssetPriceFeed(address,address,address)', + 'deployAndUpgradeTo(address,address)', + ], + [ + unichainUpdateAssetPriceFeedCalldata, + unichainDeployAndUpgradeToCalldata + ], + ] + ); + + const mainnetActions = [ + // 1. Optimism proposal + { + contract: opL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [opBridgeReceiver.address, opProposalData, 3_000_000] + }, + // 2. Base proposal + { + contract: baseL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [baseBridgeReceiver.address, baseProposalData, 3_000_000] + }, + // 3. Arbitrum proposal + { + contract: arbitrumInbox, + signature: 'createRetryableTicket(address,uint256,uint256,address,address,uint256,uint256,bytes)', + args: [ + arbitrumBridgeReceiver.address, // address to, + 0, // uint256 l2CallValue, + createRetryableTicketGasParams.maxSubmissionCost, // uint256 maxSubmissionCost, + arbitrumTimelock.address, // address excessFeeRefundAddress, + arbitrumTimelock.address, // address callValueRefundAddress, + createRetryableTicketGasParams.gasLimit, // uint256 gasLimit, + createRetryableTicketGasParams.maxFeePerGas*2, // uint256 maxFeePerGas, + arbitrumProposalData, // bytes calldata data + ], + value: createRetryableTicketGasParams.deposit.mul(2), + }, + // 4. Linea proposal + { + contract: lineaMessageService, + signature: 'sendMessage(address,uint256,bytes)', + args: [lineaBridgeReceiver.address, 0, lineaProposalData], + }, + // 5. Unichain proposal + { + contract: unichainL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [unichainBridgeReceiver.address, unichainProposalData, 3_000_000], + }, + ]; + + const description = `# Update rsETH Price Feeds on WETH Markets (L2) + +## Summary + +It is proposed to migrate the rsETH price feeds on the Optimism, Base, Arbitrum, Linea, and Unichain WETH Comets to a new 'MinMaxConstantPriceFeed' contract. This follows [Gauntlet's proposal](<>) in response to the April 18 Kelp rsETH bridge exploit, and gives the Community Multisig a faster defensive lever than a full governance cycle. + +This is intended as a temporary measure. Once the rsETH situation is resolved, a subsequent governance proposal will revert the price feeds to the prior configuration. + +## New Price Feed + +The new feed wraps the existing Kelp exchange rate and operates in one of two modes, set by the Community Multisig: + +1. **Bounded exchange rate (default).** Passes the Kelp exchange rate through unchanged when it sits between configured 'min' and 'max' bounds. If the rate falls below 'min' or rises above 'max', the feed returns the bound. Setting 'min = 0' and 'max = ∞' reproduces the existing oracle behavior. +2. **Constant price.** Returns a fixed price set by the multisig, bypassing the underlying feed. Intended for cases where the exchange rate can no longer be trusted. + +Bounds and mode changes are multisig-only, with no cooldown. A cursory review by SSPs was already performed and a final audit confirmation will be linked on the forum prior to proposal vote. + +Implementation details: [PR #1113](https://github.com/compound-finance/comet/pull/1114). + +## Proposal Actions + +1. Sends a message to update the rsETH price feed on the Optimism WETH market. +2. Sends a message to update the rsETH price feed on the Base WETH market. +3. Sends a message to update the rsETH price feed on the Arbitrum WETH market. +4. Sends a message to update the rsETH price feed on the Linea WETH market. +5. Sends a message to update the rsETH price feed on the Unichain WETH market. + +On execution, the liquidation pause on rsETH/wrsETH collateral in these markets will be lifted. A follow-up proposal will revert these markets to their prior price feed configuration once the incident is resolved. +`; + + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 600_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + // Optimism + const opDm = deploymentManager.bridgedDeploymentManagers.get('optimism:weth') as DeploymentManager; + const { + comet:optimismComet, + wrsETH: optimismRsETH, + } = await opDm.getContracts(); + + const optimismCometAssetInfo = await optimismComet.getAssetInfoByAddress(optimismRsETH.address); + + expect(optimismCometAssetInfo.priceFeed).to.equal(optimismPriceFeedAddress); + + // Base + const baseDm = deploymentManager.bridgedDeploymentManagers.get('base:weth') as DeploymentManager; + const { + comet: baseComet, + wrsETH: baseRsETH, + } = await baseDm.getContracts(); + + const baseCometAssetInfo = await baseComet.getAssetInfoByAddress(baseRsETH.address); + expect(baseCometAssetInfo.priceFeed).to.equal(basePriceFeedAddress); + + // Arbitrum + const arbitrumDm = deploymentManager.bridgedDeploymentManagers.get('arbitrum:weth') as DeploymentManager; + const { + comet: arbitrumComet, + rsETH: arbitrumRsETH, + } = await arbitrumDm.getContracts(); + + const arbitrumCometAssetInfo = await arbitrumComet.getAssetInfoByAddress(arbitrumRsETH.address); + expect(arbitrumCometAssetInfo.priceFeed).to.equal(arbitrumPriceFeedAddress); + + // Linea + const lineaDm = deploymentManager.bridgedDeploymentManagers.get('linea:weth') as DeploymentManager; + const { + comet: lineaComet, + wrsETH: lineaRsETH, + } = await lineaDm.getContracts(); + + const lineaCometAssetInfo = await lineaComet.getAssetInfoByAddress(lineaRsETH.address); + expect(lineaCometAssetInfo.priceFeed).to.equal(lineaPriceFeedAddress); + + // Unichain + const unichainDm = deploymentManager.bridgedDeploymentManagers.get('unichain:weth') as DeploymentManager; + const { + comet: unichainComet, + rsETH: unichainRsETH, + } = await unichainDm.getContracts(); + + const unichainCometAssetInfo = await unichainComet.getAssetInfoByAddress(unichainRsETH.address); + expect(unichainCometAssetInfo.priceFeed).to.equal(unichainPriceFeedAddress); + }, +}); diff --git a/deployments/mainnet/usdc/migrations/1778758319_update_supply_caps_on_l2.ts b/deployments/mainnet/usdc/migrations/1778758319_update_supply_caps_on_l2.ts new file mode 100644 index 000000000..69d734c09 --- /dev/null +++ b/deployments/mainnet/usdc/migrations/1778758319_update_supply_caps_on_l2.ts @@ -0,0 +1,861 @@ +import { expect } from 'chai'; +import { Contract, utils } from 'ethers'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { exp, proposal } from '../../../../src/deploy'; +import { forkedHreForBase } from '../../../../plugins/scenario/utils/hreForBase'; +import { applyL1ToL2Alias, estimateL2Transaction } from '../../../../scenario/utils/arbitrumUtils'; + +/* +// Arbitrum + +Arbitrum USDC Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +tETH 50 0 0.26% 0 Rule 1 +tBTC 40 1 3.23% 0 Rule 1 (see note) +ezETH 1,400 78 5.59% 102 Rule 2 (~31% buffer) +GMX 120,000 1,997 1.66% 2,596 Rule 2 (~30% buffer) +ARB 16,000,000 1,497,565 9.36% 1,946,834 Rule 2 (~30% buffer) + +Arbitrum USDC.e Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +GMX 25,000 3 0.01% 0 Rule 1 +ARB 2,000,000 22,962 1.15% 29,851 Rule 2 (~30% buffer) + +Arbitrum USDT Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +tETH 25 0 0.01% 0 Rule 1 +tBTC 80 2 2.68% 3 Rule 2 (integer-rounded buffer) +GMX 50,000 2,099 4.20% 2,729 Rule 2 (~30% buffer) +ARB 7,500,000 349,311 4.66% 454,105 Rule 2 (~30% buffer) + +Arbitrum WETH Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +tETH 25 0 0.61% 0 Rule 1 +rETH 3,750 5 0.14% 0 Rule 1 +weETH 24,000 585 2.44% 760 Rule 2 (~30% buffer) +ezETH 12,000 447 3.73% 582 Rule 2 (~30% buffer) + +// Base + +Base USDC Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +tBTC 75 15 20.06% 20 Rule 2 (~33% buffer) + +Base WETH Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +wsuperOETHb 2,000 676 33.81% 811 Rule 2 (~20% buffer) +weETH 7,500 363 4.84% 472 Rule 2 (~30% buffer) +ezETH 1,000 182 18.23% 237 Rule 2 (~30% buffer) + +// Linea + +Linea WETH Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +ezETH 4,830 8 0.16% 0 Rule 1 +weETH 3,550 93 2.63% 121 Rule 2 (~30% buffer) + +// Mantle + +Mantle USDe Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +mETH 3,000 1,533 51.09% 1,993 Rule 2 (~30% buffer) +FBTC 120 4 3.42% 5 Rule 2 (~25% buffer) +*/ + +const cometConfig = { + Arbitrum: { + USDC: { + address: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf', + }, + USDCe: { + address: '0xA5EDBDD9646f8dFF606d7448e414884C7d905dCA', + }, + USDT: { + address: '0xd98Be00b5D27fc98112BdE293e487f8D4cA57d07', + }, + WETH: { + address: '0x6f7D514bbD4aFf3BcD1140B7344b32f063dEe486', + }, + }, + Base: { + USDC: { + address: '0xb125E6687d4313864e53df431d5425969c15Eb2F', + }, + WETH: { + address: '0x46e6b214b524310239732D51387075E0e70970bf', + }, + }, + Linea: { + WETH: { + address: '0x60F2058379716A64a7A5d29219397e79bC552194', + }, + }, + Mantle: { + USDe: { + address: '0x606174f62cd968d8e684c645080fa694c1D7786E', + }, + }, +}; + +const supplyCapConfig = { + Arbitrum: { + USDC: { + tETH: { + newCap: 0, + decimals: 18, + }, + tBTC: { + newCap: 0, + decimals: 18, + }, + ezETH: { + newCap: 102, + decimals: 18, + }, + GMX: { + newCap: 2_596, + decimals: 18, + }, + ARB: { + newCap: 1_946_834, + decimals: 18, + }, + }, + USDCe: { + GMX: { + newCap: 0, + decimals: 18, + }, + ARB: { + newCap: 29_851, + decimals: 18, + }, + }, + USDT: { + tETH: { + newCap: 0, + decimals: 18, + }, + tBTC: { + newCap: 3, + decimals: 18, + }, + GMX: { + newCap: 2_729, + decimals: 18, + }, + ARB: { + newCap: 454_105, + decimals: 18, + }, + }, + WETH: { + tETH: { + newCap: 0, + decimals: 18, + }, + rETH: { + newCap: 0, + decimals: 18, + }, + weETH: { + newCap: 760, + decimals: 18, + }, + ezETH: { + newCap: 582, + decimals: 18, + }, + }, + }, + Base: { + USDC: { + tBTC: { + newCap: 20, + decimals: 18, + }, + }, + WETH: { + wsuperOETHb: { + newCap: 811, + decimals: 18, + }, + weETH: { + newCap: 472, + decimals: 18, + }, + ezETH: { + newCap: 237, + decimals: 18, + }, + }, + }, + Linea: { + WETH: { + ezETH: { + newCap: 0, + decimals: 18, + }, + weETH: { + newCap: 121, + decimals: 18, + }, + }, + }, + Mantle: { + USDe: { + mETH: { + newCap: 1_993, + decimals: 18, + }, + FBTC: { + newCap: 5, + decimals: 8, + }, + }, + }, +}; + + +export default migration('1778758319_update_supply_caps_on_l2', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const { + timelock, + governor, + baseL1CrossDomainMessenger, + arbitrumInbox, + lineaMessageService, + mantleL1CrossDomainMessenger + } = await deploymentManager.getContracts(); + + // Arbitrum + const arbitrumHre = await forkedHreForBase({ name: 'arbitrum-usdc', network: 'arbitrum', deployment: 'usdc' }); + const arbitrumDm = await deploymentManager.addBridgedDeploymentManager('arbitrum', 'usdc', arbitrumHre); + const { + bridgeReceiver: arbitrumBridgeReceiver, + configurator: arbitrumConfigurator, + cometAdmin: arbitrumCometAdmin, + tETH: arbitrumTETH, + tBTC: arbitrumTBTC, + ezETH: arbitrumEZETH, + GMX: arbitrumGMX, + ARB: arbitrumARB, + timelock: arbitrumTimelock, + } = await arbitrumDm.getContracts(); + + const arbitrumUsdcUpdateTETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDC.address, arbitrumTETH.address, exp(supplyCapConfig.Arbitrum.USDC.tETH.newCap, supplyCapConfig.Arbitrum.USDC.tETH.decimals)]); + const arbitrumUsdcUpdateTBTCSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDC.address, arbitrumTBTC.address, exp(supplyCapConfig.Arbitrum.USDC.tBTC.newCap, supplyCapConfig.Arbitrum.USDC.tBTC.decimals)]); + const arbitrumUsdcUpdateEZETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDC.address, arbitrumEZETH.address, exp(supplyCapConfig.Arbitrum.USDC.ezETH.newCap, supplyCapConfig.Arbitrum.USDC.ezETH.decimals)]); + const arbitrumUsdcUpdateGMXSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDC.address, arbitrumGMX.address, exp(supplyCapConfig.Arbitrum.USDC.GMX.newCap, supplyCapConfig.Arbitrum.USDC.GMX.decimals)]); + const arbitrumUsdcUpdateARBSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDC.address, arbitrumARB.address, exp(supplyCapConfig.Arbitrum.USDC.ARB.newCap, supplyCapConfig.Arbitrum.USDC.ARB.decimals)]); + const arbitrumUsdcDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [arbitrumConfigurator.address, cometConfig.Arbitrum.USDC.address]); + + const arbitrumUsdceUpdateGMXSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDCe.address, arbitrumGMX.address, exp(supplyCapConfig.Arbitrum.USDCe.GMX.newCap, supplyCapConfig.Arbitrum.USDCe.GMX.decimals)]); + const arbitrumUsdceUpdateARBSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDCe.address, arbitrumARB.address, exp(supplyCapConfig.Arbitrum.USDCe.ARB.newCap, supplyCapConfig.Arbitrum.USDCe.ARB.decimals)]); + const arbitrumUsdceDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [arbitrumConfigurator.address, cometConfig.Arbitrum.USDCe.address]); + + const arbitrumProposalData1 = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + // USDC Comet + arbitrumConfigurator.address, // tETH + arbitrumConfigurator.address, // tBTC + arbitrumConfigurator.address, // ezETH + arbitrumConfigurator.address, // GMX + arbitrumConfigurator.address, // ARB + arbitrumCometAdmin.address, + // USDC.e Comet + arbitrumConfigurator.address, // GMX + arbitrumConfigurator.address, // ARB + arbitrumCometAdmin.address, + ], + [ + // USDC Comet + 0, // tETH + 0, // tBTC + 0, // ezETH + 0, // GMX + 0, // ARB + 0, + // USDC.e Comet + 0, // GMX + 0, // ARB + 0, + ], + [ + // USDC Comet + 'updateAssetSupplyCap(address,address,uint128)', // tETH + 'updateAssetSupplyCap(address,address,uint128)', // tBTC + 'updateAssetSupplyCap(address,address,uint128)', // ezETH + 'updateAssetSupplyCap(address,address,uint128)', // GMX + 'updateAssetSupplyCap(address,address,uint128)', // ARB + 'deployAndUpgradeTo(address,address)', + // USDC.e Comet + 'updateAssetSupplyCap(address,address,uint128)', // GMX + 'updateAssetSupplyCap(address,address,uint128)', // ARB + 'deployAndUpgradeTo(address,address)', + ], + [ + // USDC Comet + arbitrumUsdcUpdateTETHSupplyCapCalldata, + arbitrumUsdcUpdateTBTCSupplyCapCalldata, + arbitrumUsdcUpdateEZETHSupplyCapCalldata, + arbitrumUsdcUpdateGMXSupplyCapCalldata, + arbitrumUsdcUpdateARBSupplyCapCalldata, + arbitrumUsdcDeployAndUpgradeToCalldata, + // USDC.e Comet + arbitrumUsdceUpdateGMXSupplyCapCalldata, + arbitrumUsdceUpdateARBSupplyCapCalldata, + arbitrumUsdceDeployAndUpgradeToCalldata, + ], + ] + ); + const createRetryableTicketGasParams1 = await estimateL2Transaction( + { + from: applyL1ToL2Alias(timelock.address), + to: arbitrumBridgeReceiver.address, + data: arbitrumProposalData1 + }, + arbitrumDm + ); + + const arbitrumUsdtUpdateTETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDT.address, arbitrumTETH.address, exp(supplyCapConfig.Arbitrum.USDT.tETH.newCap, supplyCapConfig.Arbitrum.USDT.tETH.decimals)]); + const arbitrumUsdtUpdateTBTCSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDT.address, arbitrumTBTC.address, exp(supplyCapConfig.Arbitrum.USDT.tBTC.newCap, supplyCapConfig.Arbitrum.USDT.tBTC.decimals)]); + const arbitrumUsdtUpdateGMXSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDT.address, arbitrumGMX.address, exp(supplyCapConfig.Arbitrum.USDT.GMX.newCap, supplyCapConfig.Arbitrum.USDT.GMX.decimals)]); + const arbitrumUsdtUpdateARBSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.USDT.address, arbitrumARB.address, exp(supplyCapConfig.Arbitrum.USDT.ARB.newCap, supplyCapConfig.Arbitrum.USDT.ARB.decimals)]); + const arbitrumUsdtDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [arbitrumConfigurator.address, cometConfig.Arbitrum.USDT.address]); + + const arbitrumDmWeth = await deploymentManager.addBridgedDeploymentManager('arbitrum', 'weth', arbitrumHre); + const { + rETH: arbitrumRETH, + weETH: arbitrumWeETH, + ezETH: arbitrumEzETH, + } = await arbitrumDmWeth.getContracts(); + + const arbitrumWethUpdateTETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.WETH.address, arbitrumTETH.address, exp(supplyCapConfig.Arbitrum.WETH.tETH.newCap, supplyCapConfig.Arbitrum.WETH.tETH.decimals)]); + const arbitrumWethUpdateRETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.WETH.address, arbitrumRETH.address, exp(supplyCapConfig.Arbitrum.WETH.rETH.newCap, supplyCapConfig.Arbitrum.WETH.rETH.decimals)]); + const arbitrumWethUpdateWeETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.WETH.address, arbitrumWeETH.address, exp(supplyCapConfig.Arbitrum.WETH.weETH.newCap, supplyCapConfig.Arbitrum.WETH.weETH.decimals)]); + const arbitrumWethUpdateEzETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Arbitrum.WETH.address, arbitrumEzETH.address, exp(supplyCapConfig.Arbitrum.WETH.ezETH.newCap, supplyCapConfig.Arbitrum.WETH.ezETH.decimals)]); + const arbitrumWethDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [arbitrumConfigurator.address, cometConfig.Arbitrum.WETH.address]); + + const arbitrumProposalData2 = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + // USDT Comet + arbitrumConfigurator.address, // tETH + arbitrumConfigurator.address, // tBTC + arbitrumConfigurator.address, // GMX + arbitrumConfigurator.address, // ARB + arbitrumCometAdmin.address, + // WETH Comet + arbitrumConfigurator.address, // tETH + arbitrumConfigurator.address, // rETH + arbitrumConfigurator.address, // weETH + arbitrumConfigurator.address, // ezETH + arbitrumCometAdmin.address, + ], + [ + // USDT Comet + 0, // tETH + 0, // tBTC + 0, // GMX + 0, // ARB + 0, + // WETH Comet + 0, // tETH + 0, // rETH + 0, // weETH + 0, // ezETH + 0, + ], + [ + // USDT Comet + 'updateAssetSupplyCap(address,address,uint128)', // tETH + 'updateAssetSupplyCap(address,address,uint128)', // tBTC + 'updateAssetSupplyCap(address,address,uint128)', // GMX + 'updateAssetSupplyCap(address,address,uint128)', // ARB + 'deployAndUpgradeTo(address,address)', + // WETH Comet + 'updateAssetSupplyCap(address,address,uint128)', // tETH + 'updateAssetSupplyCap(address,address,uint128)', // rETH + 'updateAssetSupplyCap(address,address,uint128)', // weETH + 'updateAssetSupplyCap(address,address,uint128)', // ezETH + 'deployAndUpgradeTo(address,address)', + ], + [ + // USDT Comet + arbitrumUsdtUpdateTETHSupplyCapCalldata, + arbitrumUsdtUpdateTBTCSupplyCapCalldata, + arbitrumUsdtUpdateGMXSupplyCapCalldata, + arbitrumUsdtUpdateARBSupplyCapCalldata, + arbitrumUsdtDeployAndUpgradeToCalldata, + // WETH Comet + arbitrumWethUpdateTETHSupplyCapCalldata, + arbitrumWethUpdateRETHSupplyCapCalldata, + arbitrumWethUpdateWeETHSupplyCapCalldata, + arbitrumWethUpdateEzETHSupplyCapCalldata, + arbitrumWethDeployAndUpgradeToCalldata, + ] + ] + ); + + const createRetryableTicketGasParams2 = await estimateL2Transaction( + { + from: applyL1ToL2Alias(timelock.address), + to: arbitrumBridgeReceiver.address, + data: arbitrumProposalData2 + }, + arbitrumDm + ); + + // Base + const baseHre = await forkedHreForBase({ name: 'base-usdc', network: 'base', deployment: 'usdc' }); + const baseDmUsdc = await deploymentManager.addBridgedDeploymentManager('base', 'usdc', baseHre); + const { + bridgeReceiver : baseBridgeReceiver, + configurator: baseConfigurator, + cometAdmin: baseCometAdmin, + tBTC: baseTBTC, + } = await baseDmUsdc.getContracts(); + + const baseUsdcUpdateTBTCSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Base.USDC.address, baseTBTC.address, exp(supplyCapConfig.Base.USDC.tBTC.newCap, supplyCapConfig.Base.USDC.tBTC.decimals)]); + const baseUsdcDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [baseConfigurator.address, cometConfig.Base.USDC.address]); + + const baseDmWeth = await deploymentManager.addBridgedDeploymentManager('base', 'weth', baseHre); + const { + wsuperOETHb: baseSuperOETHb, + weETH: baseWeETH, + ezETH: baseEzETH, + } = await baseDmWeth.getContracts(); + + const baseWethUpdateSuperOETHbSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Base.WETH.address, baseSuperOETHb.address, exp(supplyCapConfig.Base.WETH.wsuperOETHb.newCap, supplyCapConfig.Base.WETH.wsuperOETHb.decimals)]); + const baseWethUpdateWeETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Base.WETH.address, baseWeETH.address, exp(supplyCapConfig.Base.WETH.weETH.newCap, supplyCapConfig.Base.WETH.weETH.decimals)]); + const baseWethUpdateEzETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Base.WETH.address, baseEzETH.address, exp(supplyCapConfig.Base.WETH.ezETH.newCap, supplyCapConfig.Base.WETH.ezETH.decimals)]); + const baseWethDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [baseConfigurator.address, cometConfig.Base.WETH.address]); + + const baseProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + // USDC Comet + baseConfigurator.address, // tBTC + baseCometAdmin.address, + // WETH Comet + baseConfigurator.address, // wsuperOETHb + baseConfigurator.address, // weETH + baseConfigurator.address, // ezETH + baseCometAdmin.address, + ], + [ + // USDC Comet + 0, // tBTC + 0, + // WETH Comet + 0, // wsuperOETHb + 0, // weETH + 0, // ezETH + 0, + ], + [ + // USDC Comet + 'updateAssetSupplyCap(address,address,uint128)', // tBTC + 'deployAndUpgradeTo(address,address)', + // WETH Comet + 'updateAssetSupplyCap(address,address,uint128)', // wsuperOETHb + 'updateAssetSupplyCap(address,address,uint128)', // weETH + 'updateAssetSupplyCap(address,address,uint128)', // ezETH + 'deployAndUpgradeTo(address,address)', + ], + [ + // USDC Comet + baseUsdcUpdateTBTCSupplyCapCalldata, + baseUsdcDeployAndUpgradeToCalldata, + // WETH Comet + baseWethUpdateSuperOETHbSupplyCapCalldata, + baseWethUpdateWeETHSupplyCapCalldata, + baseWethUpdateEzETHSupplyCapCalldata, + baseWethDeployAndUpgradeToCalldata, + ], + ] + ); + + + // Linea + const lineaHre = await forkedHreForBase({ name: 'linea-weth', network: 'linea', deployment: 'weth' }); + const lineaDm = await deploymentManager.addBridgedDeploymentManager('linea', 'weth', lineaHre); + const { + bridgeReceiver: lineaBridgeReceiver, + configurator: lineaConfigurator, + cometAdmin: lineaCometAdmin, + ezETH: lineaEzETH, + weETH: lineaWeETH, + } = await lineaDm.getContracts(); + + const lineaWethUpdateEZETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Linea.WETH.address, lineaEzETH.address, exp(supplyCapConfig.Linea.WETH.ezETH.newCap, supplyCapConfig.Linea.WETH.ezETH.decimals)]); + const lineaWethUpdateWeETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Linea.WETH.address, lineaWeETH.address, exp(supplyCapConfig.Linea.WETH.weETH.newCap, supplyCapConfig.Linea.WETH.weETH.decimals)]); + const lineaDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [lineaConfigurator.address, cometConfig.Linea.WETH.address]); + + const lineaProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + // WETH Comet + lineaConfigurator.address, + lineaConfigurator.address, + lineaCometAdmin.address, + ], + [ + // WETH Comet + 0, + 0, + 0 + ], + [ + // WETH Comet + 'updateAssetSupplyCap(address,address,uint128)', + 'updateAssetSupplyCap(address,address,uint128)', + 'deployAndUpgradeTo(address,address)', + ], + [ + // WETH Comet + lineaWethUpdateEZETHSupplyCapCalldata, + lineaWethUpdateWeETHSupplyCapCalldata, + lineaDeployAndUpgradeToCalldata + ], + ] + ); + + // Mantle + const mantleHre = await forkedHreForBase({ name: 'mantle-usde', network: 'mantle', deployment: 'usde' }); + const mantleDm = await deploymentManager.addBridgedDeploymentManager('mantle', 'usde', mantleHre); + const { + bridgeReceiver: mantleBridgeReceiver, + configurator: mantleConfigurator, + cometAdmin: mantleCometAdmin, + mETH: mantleMETH, + FBTC: mantleFBTC, + } = await mantleDm.getContracts(); + + const mantleMETHUpdateSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Mantle.USDe.address, mantleMETH.address, exp(supplyCapConfig.Mantle.USDe.mETH.newCap, supplyCapConfig.Mantle.USDe.mETH.decimals)]); + const mantleFBTCUpdateSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Mantle.USDe.address, mantleFBTC.address, exp(supplyCapConfig.Mantle.USDe.FBTC.newCap, supplyCapConfig.Mantle.USDe.FBTC.decimals)]); + const mantleDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [mantleConfigurator.address, cometConfig.Mantle.USDe.address]); + + const mantleProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + // USDe Comet + mantleConfigurator.address, // mETH + mantleConfigurator.address, // FBTC + mantleCometAdmin.address, + ], + [ + // USDe Comet + 0, // mETH + 0, // FBTC + 0, + ], + [ + // USDe Comet + 'updateAssetSupplyCap(address,address,uint128)', // mETH + 'updateAssetSupplyCap(address,address,uint128)', // FBTC + 'deployAndUpgradeTo(address,address)', + ], + [ + // USDe Comet + mantleMETHUpdateSupplyCapCalldata, + mantleFBTCUpdateSupplyCapCalldata, + mantleDeployAndUpgradeToCalldata, + ], + ] + ); + + const mainnetActions = [ + // 1. Arbitrum proposal USDC + USDC.e + { + contract: arbitrumInbox, + signature: 'createRetryableTicket(address,uint256,uint256,address,address,uint256,uint256,bytes)', + args: [ + arbitrumBridgeReceiver.address, // address to, + 0, // uint256 l2CallValue, + createRetryableTicketGasParams1.maxSubmissionCost, // uint256 maxSubmissionCost, + arbitrumTimelock.address, // address excessFeeRefundAddress, + arbitrumTimelock.address, // address callValueRefundAddress, + createRetryableTicketGasParams1.gasLimit, // uint256 gasLimit, + createRetryableTicketGasParams1.maxFeePerGas*2, // uint256 maxFeePerGas, + arbitrumProposalData1, // bytes calldata data + ], + value: createRetryableTicketGasParams1.deposit.mul(2), + }, + // 2. Arbitrum proposal USDT + WETH + { + contract: arbitrumInbox, + signature: 'createRetryableTicket(address,uint256,uint256,address,address,uint256,uint256,bytes)', + args: [ + arbitrumBridgeReceiver.address, // address to, + 0, // uint256 l2CallValue, + createRetryableTicketGasParams2.maxSubmissionCost, // uint256 maxSubmissionCost, + arbitrumTimelock.address, // address excessFeeRefundAddress, + arbitrumTimelock.address, // address callValueRefundAddress, + createRetryableTicketGasParams2.gasLimit, // uint256 gasLimit, + createRetryableTicketGasParams2.maxFeePerGas*2, // uint256 maxFeePerGas, + arbitrumProposalData2, // bytes calldata data + ], + value: createRetryableTicketGasParams2.deposit.mul(2), + }, + // 3. Base proposal + { + contract: baseL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [baseBridgeReceiver.address, baseProposalData, 3_000_000] + }, + // 4. Linea proposal + { + contract: lineaMessageService, + signature: 'sendMessage(address,uint256,bytes)', + args: [lineaBridgeReceiver.address, 0, lineaProposalData], + }, + // 5. Mantle proposal + { + contract: mantleL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [mantleBridgeReceiver.address, mantleProposalData, 2_500_000], + }, + ]; + + const description = `# Supply Cap Reduction Across L2 Comets + +## Proposal summary + +WOOF! proposes to update supply caps on cUSDCv3, cUSDC.ev3, cUSDTv3 and cWETHv3 on Arbitrum, cUSDCv3 and cWETHv3 on Base, cWETHv3 on Linea and cUSDev3 on Mantle networks. This proposal takes the governance steps recommended and necessary to update Compound III markets on each network. Simulations have confirmed the market’s readiness, as much as possible, using the [Comet scenario suite](https://github.com/compound-finance/comet/tree/main/scenario). The new parameters are based on the [recommendations from Gauntlet](https://www.comp.xyz/t/supply-cap-reduction-across-l2-comets/7794/1). + +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1120) and [forum discussion](https://www.comp.xyz/t/supply-cap-reduction-across-l2-comets/7794). + + +## Proposal Actions + +The first action sends a message to the Arbitrum network to update supply caps on the USDC and USDC.e Comets. + +The second action sends a message to the Arbitrum network to update supply caps on the USDT and WETH Comets. + +The third action sends a message to the Base network to update supply caps on the USDC and WETH Comets. + +The fourth action sends a message to the Linea network to update supply caps on the WETH Comet. + +The fifth action sends a message to the Mantle network to update supply caps on the USDe Comet. +`; + + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 600_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + // Arbitrum + const arbitrumDm = deploymentManager.bridgedDeploymentManagers.get('arbitrum:usdc') as DeploymentManager; + + const { + tETH: arbitrumTETH, + tBTC: arbitrumTBTC, + ezETH: arbitrumEZETH, + GMX: arbitrumGMX, + ARB: arbitrumARB, + } = await arbitrumDm.getContracts(); + + // USDC Comet + const arbitrumUsdcComet = new Contract( + cometConfig.Arbitrum.USDC.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await arbitrumDm.getSigner() + ); + + const tETHAssetInfoUsdc = await arbitrumUsdcComet.getAssetInfoByAddress(arbitrumTETH.address); + const tBTCAssetInfoUsdc = await arbitrumUsdcComet.getAssetInfoByAddress(arbitrumTBTC.address); + const ezETHAssetInfoUsdc = await arbitrumUsdcComet.getAssetInfoByAddress(arbitrumEZETH.address); + const GMXAssetInfoUsdc = await arbitrumUsdcComet.getAssetInfoByAddress(arbitrumGMX.address); + const ARBAssetInfoUsdc = await arbitrumUsdcComet.getAssetInfoByAddress(arbitrumARB.address); + + expect(tETHAssetInfoUsdc.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDC.tETH.decimals)); + expect(tBTCAssetInfoUsdc.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDC.tBTC.decimals)); + expect(ezETHAssetInfoUsdc.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDC.ezETH.decimals)); + expect(GMXAssetInfoUsdc.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDC.GMX.decimals)); + expect(ARBAssetInfoUsdc.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDC.ARB.decimals)); + + expect(tETHAssetInfoUsdc.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDC.tETH.newCap, supplyCapConfig.Arbitrum.USDC.tETH.decimals)); + expect(tBTCAssetInfoUsdc.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDC.tBTC.newCap, supplyCapConfig.Arbitrum.USDC.tBTC.decimals)); + expect(ezETHAssetInfoUsdc.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDC.ezETH.newCap, supplyCapConfig.Arbitrum.USDC.ezETH.decimals)); + expect(GMXAssetInfoUsdc.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDC.GMX.newCap, supplyCapConfig.Arbitrum.USDC.GMX.decimals)); + expect(ARBAssetInfoUsdc.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDC.ARB.newCap, supplyCapConfig.Arbitrum.USDC.ARB.decimals)); + + // USDC.e Comet + const arbitrumUsdceComet = new Contract( + cometConfig.Arbitrum.USDCe.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await arbitrumDm.getSigner() + ); + + const GMXAssetInfoUsdce = await arbitrumUsdceComet.getAssetInfoByAddress(arbitrumGMX.address); + const ARBAssetInfoUsdce = await arbitrumUsdceComet.getAssetInfoByAddress(arbitrumARB.address); + + expect(GMXAssetInfoUsdce.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDCe.GMX.decimals)); + expect(ARBAssetInfoUsdce.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDCe.ARB.decimals)); + + expect(GMXAssetInfoUsdce.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDCe.GMX.newCap, supplyCapConfig.Arbitrum.USDCe.GMX.decimals)); + expect(ARBAssetInfoUsdce.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDCe.ARB.newCap, supplyCapConfig.Arbitrum.USDCe.ARB.decimals)); + + const arbitrumUsdtComet = new Contract( + cometConfig.Arbitrum.USDT.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await arbitrumDm.getSigner() + ); + + const tETHAssetInfoUsdt = await arbitrumUsdtComet.getAssetInfoByAddress(arbitrumTETH.address); + const tBTCAssetInfoUsdt = await arbitrumUsdtComet.getAssetInfoByAddress(arbitrumTBTC.address); + const GMXAssetInfoUsdt = await arbitrumUsdtComet.getAssetInfoByAddress(arbitrumGMX.address); + const ARBAssetInfoUsdt = await arbitrumUsdtComet.getAssetInfoByAddress(arbitrumARB.address); + + expect(tETHAssetInfoUsdt.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDT.tETH.decimals)); + expect(tBTCAssetInfoUsdt.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDT.tBTC.decimals)); + expect(GMXAssetInfoUsdt.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDT.GMX.decimals)); + expect(ARBAssetInfoUsdt.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.USDT.ARB.decimals)); + expect(tETHAssetInfoUsdt.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDT.tETH.newCap, supplyCapConfig.Arbitrum.USDT.tETH.decimals)); + expect(tBTCAssetInfoUsdt.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDT.tBTC.newCap, supplyCapConfig.Arbitrum.USDT.tBTC.decimals)); + expect(GMXAssetInfoUsdt.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDT.GMX.newCap, supplyCapConfig.Arbitrum.USDT.GMX.decimals)); + expect(ARBAssetInfoUsdt.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.USDT.ARB.newCap, supplyCapConfig.Arbitrum.USDT.ARB.decimals)); + + const arbitrumDmWeth = deploymentManager.bridgedDeploymentManagers.get('arbitrum:weth') as DeploymentManager; + const { + rETH: arbitrumRETH, + weETH: arbitrumWeETH, + ezETH: arbitrumEzETH, + } = await arbitrumDmWeth.getContracts(); + const arbitrumWethComet = new Contract( + cometConfig.Arbitrum.WETH.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await arbitrumDmWeth.getSigner() + ); + + const tETHAssetInfoWeth = await arbitrumWethComet.getAssetInfoByAddress(arbitrumTETH.address); + const rETHAssetInfoWeth = await arbitrumWethComet.getAssetInfoByAddress(arbitrumRETH.address); + const weETHAssetInfoWeth = await arbitrumWethComet.getAssetInfoByAddress(arbitrumWeETH.address); + const ezETHAssetInfoWeth = await arbitrumWethComet.getAssetInfoByAddress(arbitrumEzETH.address); + + expect(tETHAssetInfoWeth.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.WETH.tETH.decimals)); + expect(rETHAssetInfoWeth.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.WETH.rETH.decimals)); + expect(weETHAssetInfoWeth.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.WETH.weETH.decimals)); + expect(ezETHAssetInfoWeth.scale).to.equal(exp(1, supplyCapConfig.Arbitrum.WETH.ezETH.decimals)); + + expect(tETHAssetInfoWeth.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.WETH.tETH.newCap, supplyCapConfig.Arbitrum.WETH.tETH.decimals)); + expect(rETHAssetInfoWeth.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.WETH.rETH.newCap, supplyCapConfig.Arbitrum.WETH.rETH.decimals)); + expect(weETHAssetInfoWeth.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.WETH.weETH.newCap, supplyCapConfig.Arbitrum.WETH.weETH.decimals)); + expect(ezETHAssetInfoWeth.supplyCap).to.equal(exp(supplyCapConfig.Arbitrum.WETH.ezETH.newCap, supplyCapConfig.Arbitrum.WETH.ezETH.decimals)); + + // Base + const baseDmUsdc = deploymentManager.bridgedDeploymentManagers.get('base:usdc') as DeploymentManager; + const { + tBTC: baseTBTC, + } = await baseDmUsdc.getContracts(); + + const baseUsdcComet = new Contract( + cometConfig.Base.USDC.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await baseDmUsdc.getSigner() + ); + + const tBTCAssetInfoBaseUsdc = await baseUsdcComet.getAssetInfoByAddress(baseTBTC.address); + + expect(tBTCAssetInfoBaseUsdc.scale).to.equal(exp(1, supplyCapConfig.Base.USDC.tBTC.decimals)); + expect(tBTCAssetInfoBaseUsdc.supplyCap).to.equal(exp(supplyCapConfig.Base.USDC.tBTC.newCap, supplyCapConfig.Base.USDC.tBTC.decimals)); + + const baseDmWeth = deploymentManager.bridgedDeploymentManagers.get('base:weth') as DeploymentManager; + const { + wsuperOETHb: baseSuperOETHb, + weETH: baseWeETH, + ezETH: baseEzETH, + } = await baseDmWeth.getContracts(); + + const baseWethComet = new Contract( + cometConfig.Base.WETH.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await baseDmWeth.getSigner() + ); + + const superOETHbAssetInfoBaseWeth = await baseWethComet.getAssetInfoByAddress(baseSuperOETHb.address); + const weETHAssetInfoBaseWeth = await baseWethComet.getAssetInfoByAddress(baseWeETH.address); + const ezETHAssetInfoBaseWeth = await baseWethComet.getAssetInfoByAddress(baseEzETH.address); + + expect(superOETHbAssetInfoBaseWeth.scale).to.equal(exp(1, supplyCapConfig.Base.WETH.wsuperOETHb.decimals)); + expect(weETHAssetInfoBaseWeth.scale).to.equal(exp(1, supplyCapConfig.Base.WETH.weETH.decimals)); + expect(ezETHAssetInfoBaseWeth.scale).to.equal(exp(1, supplyCapConfig.Base.WETH.ezETH.decimals)); + + expect(superOETHbAssetInfoBaseWeth.supplyCap).to.equal(exp(supplyCapConfig.Base.WETH.wsuperOETHb.newCap, supplyCapConfig.Base.WETH.wsuperOETHb.decimals)); + expect(weETHAssetInfoBaseWeth.supplyCap).to.equal(exp(supplyCapConfig.Base.WETH.weETH.newCap, supplyCapConfig.Base.WETH.weETH.decimals)); + expect(ezETHAssetInfoBaseWeth.supplyCap).to.equal(exp(supplyCapConfig.Base.WETH.ezETH.newCap, supplyCapConfig.Base.WETH.ezETH.decimals)); + + // Linea + const lineaDm = deploymentManager.bridgedDeploymentManagers.get('linea:weth') as DeploymentManager; + const { + ezETH: lineaEzETH, + weETH: lineaWeETH, + } = await lineaDm.getContracts(); + + const lineaWethComet = new Contract( + cometConfig.Linea.WETH.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await lineaDm.getSigner() + ); + + const ezETHAssetInfoLineaWeth = await lineaWethComet.getAssetInfoByAddress(lineaEzETH.address); + const weETHAssetInfoLineaWeth = await lineaWethComet.getAssetInfoByAddress(lineaWeETH.address); + + expect(ezETHAssetInfoLineaWeth.scale).to.equal(exp(1, supplyCapConfig.Linea.WETH.ezETH.decimals)); + expect(weETHAssetInfoLineaWeth.scale).to.equal(exp(1, supplyCapConfig.Linea.WETH.weETH.decimals)); + + expect(ezETHAssetInfoLineaWeth.supplyCap).to.equal(exp(supplyCapConfig.Linea.WETH.ezETH.newCap, supplyCapConfig.Linea.WETH.ezETH.decimals)); + expect(weETHAssetInfoLineaWeth.supplyCap).to.equal(exp(supplyCapConfig.Linea.WETH.weETH.newCap, supplyCapConfig.Linea.WETH.weETH.decimals)); + + // Mantle + const mantleDm = deploymentManager.bridgedDeploymentManagers.get('mantle:usde') as DeploymentManager; + const { + mETH: mantleMETH, + FBTC: mantleFBTC, + } = await mantleDm.getContracts(); + + const mantleUsdeComet = new Contract( + cometConfig.Mantle.USDe.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await mantleDm.getSigner() + ); + + const mETHAssetInfoMantleUsde = await mantleUsdeComet.getAssetInfoByAddress(mantleMETH.address); + const FBTCAssetInfoMantleUsde = await mantleUsdeComet.getAssetInfoByAddress(mantleFBTC.address); + + expect(mETHAssetInfoMantleUsde.scale).to.equal(exp(1, supplyCapConfig.Mantle.USDe.mETH.decimals)); + expect(FBTCAssetInfoMantleUsde.scale).to.equal(exp(1, supplyCapConfig.Mantle.USDe.FBTC.decimals)); + + expect(mETHAssetInfoMantleUsde.supplyCap).to.equal(exp(supplyCapConfig.Mantle.USDe.mETH.newCap, supplyCapConfig.Mantle.USDe.mETH.decimals)); + expect(FBTCAssetInfoMantleUsde.supplyCap).to.equal(exp(supplyCapConfig.Mantle.USDe.FBTC.newCap, supplyCapConfig.Mantle.USDe.FBTC.decimals)); + }, +}); diff --git a/deployments/mainnet/usdc/migrations/1779114960_update_supply_caps_on_l2.ts b/deployments/mainnet/usdc/migrations/1779114960_update_supply_caps_on_l2.ts new file mode 100644 index 000000000..3350241ef --- /dev/null +++ b/deployments/mainnet/usdc/migrations/1779114960_update_supply_caps_on_l2.ts @@ -0,0 +1,580 @@ +import { expect } from 'chai'; +import { Contract, utils } from 'ethers'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { exp, proposal } from '../../../../src/deploy'; +import { forkedHreForBase } from '../../../../plugins/scenario/utils/hreForBase'; + +/* +// Optimism + +Optimism USDC Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +OP 1,400,000 122,116 8.72% 158,750 Rule 2 (~30% buffer) + +Optimism USDT Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +OP 1,000,000 311,056 31.11% 404,373 Rule 2 (~30% buffer) + +Optimism WETH Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +weETH 1,600 804 50.27% 1,046 Rule 2 (~30% buffer) +rETH 5,000 76 1.52% 99 Rule 2 (~30% buffer) +ezETH 3,200 212 6.63% 276 Rule 2 (~30% buffer) + +// Polygon + +Polygon USDC Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +WPOL 8,000,000 377,485 4.72% 490,731 Rule 2 (~30% buffer) +MaticX 3,200,000 183,489 5.73% 238,536 Rule 2 (~30% buffer) + +Polygon USDT Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +WPOL 5,000,000 155,574 3.11% 202,246 Rule 2 (~30% buffer) +MaticX 4,160,000 123,953 2.98% 161,140 Rule 2 (~30% buffer) + +// Unichain + +Unichain USDC Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +UNI 100,000 3,313 3.31% 4,307 Rule 2 (~30% buffer) + +Unichain WETH Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +ezETH 2,200 0 0.00% 0 Rule 1 +UNI 500,000 20 0.00% 0 Rule 1 +weETH 5,000 733 14.65% 952 Rule 2 (~30% buffer) +*/ + +const cometConfig = { + Optimism: { + USDC: { + address: '0x2e44e174f7D53F0212823acC11C01A11d58c5bCB', + }, + USDT: { + address: '0x995E394b8B2437aC8Ce61Ee0bC610D617962B214', + }, + WETH: { + address: '0xE36A30D249f7761327fd973001A32010b521b6Fd', + }, + }, + Polygon: { + USDC: { + address: '0xF25212E676D1F7F89Cd72fFEe66158f541246445', + }, + USDT: { + address: '0xaeB318360f27748Acb200CE616E389A6C9409a07', + }, + }, + Unichain: { + USDC: { + address: '0x2c7118c4C88B9841FCF839074c26Ae8f035f2921', + }, + WETH: { + address: '0x6C987dDE50dB1dcDd32Cd4175778C2a291978E2a', + }, + }, +}; + +const supplyCapConfig = { + Optimism : { + USDC: { + OP: { + newCap: 158_750, + decimals: 18, + }, + }, + USDT: { + OP: { + newCap: 404_373, + decimals: 18, + }, + }, + WETH: { + weETH: { + newCap: 1_046, + decimals: 18, + }, + rETH: { + newCap: 99, + decimals: 18, + }, + ezETH: { + newCap: 276, + decimals: 18, + }, + }, + }, + Polygon: { + USDC: { + WPOL: { + newCap: 490_731, + decimals: 18, + }, + MaticX: { + newCap: 238_536, + decimals: 18, + }, + }, + USDT: { + WPOL: { + newCap: 202_246, + decimals: 18, + }, + MaticX: { + newCap: 161_140, + decimals: 18, + }, + }, + }, + Unichain: { + USDC: { + UNI: { + newCap: 4_307, + decimals: 18, + }, + }, + WETH: { + ezETH: { + newCap: 0, + decimals: 18, + }, + UNI: { + newCap: 0, + decimals: 18, + }, + weETH: { + newCap: 952, + decimals: 18, + }, + }, + }, +}; + + +export default migration('1779114960_update_supply_caps_on_l2', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const { + governor, + fxRoot, + opL1CrossDomainMessenger, + unichainL1CrossDomainMessenger, + } = await deploymentManager.getContracts(); + + // Optimism + const optimismHre = await forkedHreForBase({ name: 'optimism-usdc', network: 'optimism', deployment: 'usdc' }); + const optimismDm = await deploymentManager.addBridgedDeploymentManager('optimism', 'usdc', optimismHre); + const { + bridgeReceiver: optimismBridgeReceiver, + configurator: optimismConfigurator, + cometAdmin: optimismCometAdmin, + OP: optimismOP, + } = await optimismDm.getContracts(); + + const optimismUsdcUpdateOpSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Optimism.USDC.address, optimismOP.address, exp(supplyCapConfig.Optimism.USDC.OP.newCap, supplyCapConfig.Optimism.USDC.OP.decimals)]); + const optimismUsdcDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [optimismConfigurator.address, cometConfig.Optimism.USDC.address]); + + const optimismUsdtUpdateOpSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Optimism.USDT.address, optimismOP.address, exp(supplyCapConfig.Optimism.USDT.OP.newCap, supplyCapConfig.Optimism.USDT.OP.decimals)]); + const optimismUsdtDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [optimismConfigurator.address, cometConfig.Optimism.USDT.address]); + + const optimismDmWeth = await deploymentManager.addBridgedDeploymentManager('optimism', 'weth', optimismHre); + const { + weETH: optimismWeETH, + rETH: optimismRETH, + ezETH: optimismEzETH, + } = await optimismDmWeth.getContracts(); + + const optimismWethUpdateWeETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Optimism.WETH.address, optimismWeETH.address, exp(supplyCapConfig.Optimism.WETH.weETH.newCap, supplyCapConfig.Optimism.WETH.weETH.decimals)]); + const optimismWethUpdateRETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Optimism.WETH.address, optimismRETH.address, exp(supplyCapConfig.Optimism.WETH.rETH.newCap, supplyCapConfig.Optimism.WETH.rETH.decimals)]); + const optimismWethUpdateEzETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Optimism.WETH.address, optimismEzETH.address, exp(supplyCapConfig.Optimism.WETH.ezETH.newCap, supplyCapConfig.Optimism.WETH.ezETH.decimals)]); + const optimismWethDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [optimismConfigurator.address, cometConfig.Optimism.WETH.address]); + + const optimismProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + // USDC Comet + optimismConfigurator.address, // OP + optimismCometAdmin.address, + // USDT Comet + optimismConfigurator.address, // OP + optimismCometAdmin.address, + // WETH Comet + optimismConfigurator.address, // weETH + optimismConfigurator.address, // rETH + optimismConfigurator.address, // ezETH + optimismCometAdmin.address, + ], + [ + // USDC Comet + 0, // OP + 0, + // USDT Comet + 0, // OP + 0, + // WETH Comet + 0, // weETH + 0, // rETH + 0, // ezETH + 0, + ], + [ + // USDC Comet + 'updateAssetSupplyCap(address,address,uint128)', // OP + 'deployAndUpgradeTo(address,address)', + // USDT Comet + 'updateAssetSupplyCap(address,address,uint128)', // OP + 'deployAndUpgradeTo(address,address)', + // WETH Comet + 'updateAssetSupplyCap(address,address,uint128)', // weETH + 'updateAssetSupplyCap(address,address,uint128)', // rETH + 'updateAssetSupplyCap(address,address,uint128)', // ezETH + 'deployAndUpgradeTo(address,address)', + ], + [ + // USDC Comet + optimismUsdcUpdateOpSupplyCapCalldata, + optimismUsdcDeployAndUpgradeToCalldata, + // USDT Comet + optimismUsdtUpdateOpSupplyCapCalldata, + optimismUsdtDeployAndUpgradeToCalldata, + // WETH Comet + optimismWethUpdateWeETHSupplyCapCalldata, + optimismWethUpdateRETHSupplyCapCalldata, + optimismWethUpdateEzETHSupplyCapCalldata, + optimismWethDeployAndUpgradeToCalldata, + ], + ] + ); + + // Polygon + const polygonHre = await forkedHreForBase({ name: 'polygon-usdc', network: 'polygon', deployment: 'usdc' }); + const polygonDm = await deploymentManager.addBridgedDeploymentManager('polygon', 'usdc', polygonHre); + const { + bridgeReceiver: polygonBridgeReceiver, + configurator: polygonConfigurator, + cometAdmin: polygonCometAdmin, + WPOL: polygonWPOL, + MaticX: polygonMaticX, + } = await polygonDm.getContracts(); + + const polygonUsdcUpdateWPOLSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Polygon.USDC.address, polygonWPOL.address, exp(supplyCapConfig.Polygon.USDC.WPOL.newCap, supplyCapConfig.Polygon.USDC.WPOL.decimals)]); + const polygonUsdcUpdateMaticXSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Polygon.USDC.address, polygonMaticX.address, exp(supplyCapConfig.Polygon.USDC.MaticX.newCap, supplyCapConfig.Polygon.USDC.MaticX.decimals)]); + const polygonUsdcDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [polygonConfigurator.address, cometConfig.Polygon.USDC.address]); + + const polygonUsdtUpdateWPOLSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Polygon.USDT.address, polygonWPOL.address, exp(supplyCapConfig.Polygon.USDT.WPOL.newCap, supplyCapConfig.Polygon.USDT.WPOL.decimals)]); + const polygonUsdtUpdateMaticXSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Polygon.USDT.address, polygonMaticX.address, exp(supplyCapConfig.Polygon.USDT.MaticX.newCap, supplyCapConfig.Polygon.USDT.MaticX.decimals)]); + const polygonUsdtDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [polygonConfigurator.address, cometConfig.Polygon.USDT.address]); + + const polygonProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + // USDC Comet + polygonConfigurator.address, + polygonConfigurator.address, + polygonCometAdmin.address, + // USDT Comet + polygonConfigurator.address, + polygonConfigurator.address, + polygonCometAdmin.address, + ], + [ + // USDC Comet + 0, + 0, + 0, + // USDT Comet + 0, + 0, + 0, + ], + [ + // USDC Comet + 'updateAssetSupplyCap(address,address,uint128)', + 'updateAssetSupplyCap(address,address,uint128)', + 'deployAndUpgradeTo(address,address)', + // USDT Comet + 'updateAssetSupplyCap(address,address,uint128)', + 'updateAssetSupplyCap(address,address,uint128)', + 'deployAndUpgradeTo(address,address)', + ], + [ + // USDC Comet + polygonUsdcUpdateWPOLSupplyCapCalldata, + polygonUsdcUpdateMaticXSupplyCapCalldata, + polygonUsdcDeployAndUpgradeToCalldata, + // USDT Comet + polygonUsdtUpdateWPOLSupplyCapCalldata, + polygonUsdtUpdateMaticXSupplyCapCalldata, + polygonUsdtDeployAndUpgradeToCalldata + ], + ] + ); + + // Unichain + const unichainHre = await forkedHreForBase({ name: 'unichain-weth', network: 'unichain', deployment: 'weth' }); + const unichainDm = await deploymentManager.addBridgedDeploymentManager('unichain', 'weth', unichainHre); + const { + bridgeReceiver: unichainBridgeReceiver, + configurator: unichainConfigurator, + cometAdmin: unichainCometAdmin, + UNI: unichainUNI, + ezETH: unichainEzETH, + weETH: unichainWeETH, + } = await unichainDm.getContracts(); + + const unichainUsdcUniUpdateSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Unichain.USDC.address, unichainUNI.address, exp(supplyCapConfig.Unichain.USDC.UNI.newCap, supplyCapConfig.Unichain.USDC.UNI.decimals)]); + const unichainUsdcDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [unichainConfigurator.address, cometConfig.Unichain.USDC.address]); + + const unichainWethUniUpdateSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Unichain.WETH.address, unichainUNI.address, exp(supplyCapConfig.Unichain.WETH.UNI.newCap, supplyCapConfig.Unichain.WETH.UNI.decimals)]); + const unichainWethEzEthUpdateSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Unichain.WETH.address, unichainEzETH.address, exp(supplyCapConfig.Unichain.WETH.ezETH.newCap, supplyCapConfig.Unichain.WETH.ezETH.decimals)]); + const unichainWethWeEthUpdateSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Unichain.WETH.address, unichainWeETH.address, exp(supplyCapConfig.Unichain.WETH.weETH.newCap, supplyCapConfig.Unichain.WETH.weETH.decimals)]); + const unichainWethDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [unichainConfigurator.address, cometConfig.Unichain.WETH.address]); + + const unichainProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + // USDC Comet + unichainConfigurator.address, // UNI + unichainCometAdmin.address, + // WETH Comet + unichainConfigurator.address, // UNI + unichainConfigurator.address, // ezETH + unichainConfigurator.address, // weETH + unichainCometAdmin.address, + ], + [ + // USDC Comet + 0, // UNI + 0, + // WETH Comet + 0, // UNI + 0, // ezETH + 0, // weETH + 0, + ], + [ + // USDC Comet + 'updateAssetSupplyCap(address,address,uint128)', // UNI + 'deployAndUpgradeTo(address,address)', + // WETH Comet + 'updateAssetSupplyCap(address,address,uint128)', // UNI + 'updateAssetSupplyCap(address,address,uint128)', // ezETH + 'updateAssetSupplyCap(address,address,uint128)', // weETH + 'deployAndUpgradeTo(address,address)', + ], + [ + // USDC Comet + unichainUsdcUniUpdateSupplyCapCalldata, + unichainUsdcDeployAndUpgradeToCalldata, + // WETH Comet + unichainWethUniUpdateSupplyCapCalldata, + unichainWethEzEthUpdateSupplyCapCalldata, + unichainWethWeEthUpdateSupplyCapCalldata, + unichainWethDeployAndUpgradeToCalldata, + ], + ] + ); + + const mainnetActions = [ + // 1. Optimism proposal + { + contract: opL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [optimismBridgeReceiver.address, optimismProposalData, 3_000_000] + }, + // 2. Polygon proposal + { + contract: fxRoot, + signature: 'sendMessageToChild(address,bytes)', + args: [polygonBridgeReceiver.address, polygonProposalData], + }, + // 3. Unichain proposal + { + contract: unichainL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [unichainBridgeReceiver.address, unichainProposalData, 3_000_000], + }, + ]; + + const description = `# Supply Cap Reduction Across L2 Comets (Part 2) + +## Proposal summary + +WOOF! proposes to update supply caps on cUSDCv3, cUSDTv3 and cWETHv3 on Optimism, cUSDCv3 and cUSDTv3 on Polygon, cUSDCv3 and cWETHv3 on Unichain networks. This proposal takes the governance steps recommended and necessary to update Compound III markets on each network. Simulations have confirmed the market’s readiness, as much as possible, using the [Comet scenario suite](https://github.com/compound-finance/comet/tree/main/scenario). The new parameters are based on the [recommendations from Gauntlet](https://www.comp.xyz/t/supply-cap-reduction-across-l2-comets/7794/1). + +Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1124) and [forum discussion](https://www.comp.xyz/t/supply-cap-reduction-across-l2-comets/7794). + + +## Proposal Actions + +The first action sends a message to the Optimism network to update supply caps on the USDC, USDT and WETH Comets. + +The second action sends a message to the Polygon network to update supply caps on the USDC and USDT Comets. + +The third action sends a message to the Unichain network to update supply caps on the USDC and WETH Comets. +`; + + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 600_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(deploymentManager: DeploymentManager): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + // Optimism + const optimismDm = deploymentManager.bridgedDeploymentManagers.get('optimism:usdc') as DeploymentManager; + + const { + OP: optimismOP, + } = await optimismDm.getContracts(); + + // USDC Comet + const optimismUsdcComet = new Contract( + cometConfig.Optimism.USDC.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await optimismDm.getSigner() + ); + + const OPAssetInfoUsdc = await optimismUsdcComet.getAssetInfoByAddress(optimismOP.address); + + expect(OPAssetInfoUsdc.scale).to.equal(exp(1, supplyCapConfig.Optimism.USDC.OP.decimals)); + expect(OPAssetInfoUsdc.supplyCap).to.equal(exp(supplyCapConfig.Optimism.USDC.OP.newCap, supplyCapConfig.Optimism.USDC.OP.decimals)); + + // USDT Comet + const optimismUsdtComet = new Contract( + cometConfig.Optimism.USDT.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await optimismDm.getSigner() + ); + const OPAssetInfoUsdt = await optimismUsdtComet.getAssetInfoByAddress(optimismOP.address); + expect(OPAssetInfoUsdt.scale).to.equal(exp(1, supplyCapConfig.Optimism.USDT.OP.decimals)); + expect(OPAssetInfoUsdt.supplyCap).to.equal(exp(supplyCapConfig.Optimism.USDT.OP.newCap, supplyCapConfig.Optimism.USDT.OP.decimals)); + + // WETH Comet + const optimismWethComet = new Contract( + cometConfig.Optimism.WETH.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await optimismDm.getSigner() + ); + const optimismDmWeth = deploymentManager.bridgedDeploymentManagers.get('optimism:weth') as DeploymentManager; + const { + weETH: optimismWeETH, + rETH: optimismRETH, + ezETH: optimismEzETH, + } = await optimismDmWeth.getContracts(); + + const weETHAssetInfoWeth = await optimismWethComet.getAssetInfoByAddress(optimismWeETH.address); + const rETHAssetInfoWeth = await optimismWethComet.getAssetInfoByAddress(optimismRETH.address); + const ezETHAssetInfoWeth = await optimismWethComet.getAssetInfoByAddress(optimismEzETH.address); + + expect(weETHAssetInfoWeth.scale).to.equal(exp(1, supplyCapConfig.Optimism.WETH.weETH.decimals)); + expect(rETHAssetInfoWeth.scale).to.equal(exp(1, supplyCapConfig.Optimism.WETH.rETH.decimals)); + expect(ezETHAssetInfoWeth.scale).to.equal(exp(1, supplyCapConfig.Optimism.WETH.ezETH.decimals)); + + expect(weETHAssetInfoWeth.supplyCap).to.equal(exp(supplyCapConfig.Optimism.WETH.weETH.newCap, supplyCapConfig.Optimism.WETH.weETH.decimals)); + expect(rETHAssetInfoWeth.supplyCap).to.equal(exp(supplyCapConfig.Optimism.WETH.rETH.newCap, supplyCapConfig.Optimism.WETH.rETH.decimals)); + expect(ezETHAssetInfoWeth.supplyCap).to.equal(exp(supplyCapConfig.Optimism.WETH.ezETH.newCap, supplyCapConfig.Optimism.WETH.ezETH.decimals)); + + // Polygon + const polygonDm = deploymentManager.bridgedDeploymentManagers.get('polygon:usdc') as DeploymentManager; + + const { + WPOL: polygonWPOL, + MaticX: polygonMaticX, + } = await polygonDm.getContracts(); + + // USDC Comet + const polygonUsdcComet = new Contract( + cometConfig.Polygon.USDC.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await polygonDm.getSigner() + ); + + const WPOLAssetInfoUsdc = await polygonUsdcComet.getAssetInfoByAddress(polygonWPOL.address); + const MaticXAssetInfoUsdc = await polygonUsdcComet.getAssetInfoByAddress(polygonMaticX.address); + + expect(WPOLAssetInfoUsdc.scale).to.equal(exp(1, supplyCapConfig.Polygon.USDC.WPOL.decimals)); + expect(WPOLAssetInfoUsdc.supplyCap).to.equal(exp(supplyCapConfig.Polygon.USDC.WPOL.newCap, supplyCapConfig.Polygon.USDC.WPOL.decimals)); + + expect(MaticXAssetInfoUsdc.scale).to.equal(exp(1, supplyCapConfig.Polygon.USDC.MaticX.decimals)); + expect(MaticXAssetInfoUsdc.supplyCap).to.equal(exp(supplyCapConfig.Polygon.USDC.MaticX.newCap, supplyCapConfig.Polygon.USDC.MaticX.decimals)); + + // USDT Comet + const polygonUsdtComet = new Contract( + cometConfig.Polygon.USDT.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await polygonDm.getSigner() + ); + + const WPOLAssetInfoUsdt = await polygonUsdtComet.getAssetInfoByAddress(polygonWPOL.address); + const MaticXAssetInfoUsdt = await polygonUsdtComet.getAssetInfoByAddress(polygonMaticX.address); + + expect(WPOLAssetInfoUsdt.scale).to.equal(exp(1, supplyCapConfig.Polygon.USDT.WPOL.decimals)); + expect(WPOLAssetInfoUsdt.supplyCap).to.equal(exp(supplyCapConfig.Polygon.USDT.WPOL.newCap, supplyCapConfig.Polygon.USDT.WPOL.decimals)); + + expect(MaticXAssetInfoUsdt.scale).to.equal(exp(1, supplyCapConfig.Polygon.USDT.MaticX.decimals)); + expect(MaticXAssetInfoUsdt.supplyCap).to.equal(exp(supplyCapConfig.Polygon.USDT.MaticX.newCap, supplyCapConfig.Polygon.USDT.MaticX.decimals)); + + // Unichain + const unichainDm = deploymentManager.bridgedDeploymentManagers.get('unichain:weth') as DeploymentManager; + + const { + UNI: unichainUNI, + ezETH: unichainEzETH, + weETH: unichainWeETH, + } = await unichainDm.getContracts(); + + // USDC Comet + const unichainUsdcComet = new Contract( + cometConfig.Unichain.USDC.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await unichainDm.getSigner() + ); + + const unichainUNIAssetInfoUsdc = await unichainUsdcComet.getAssetInfoByAddress(unichainUNI.address); + + expect(unichainUNIAssetInfoUsdc.scale).to.equal(exp(1, supplyCapConfig.Unichain.USDC.UNI.decimals)); + expect(unichainUNIAssetInfoUsdc.supplyCap).to.equal(exp(supplyCapConfig.Unichain.USDC.UNI.newCap, supplyCapConfig.Unichain.USDC.UNI.decimals)); + + // WETH Comet + const unichainWethComet = new Contract( + cometConfig.Unichain.WETH.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await unichainDm.getSigner() + ); + + const unichainUniAssetInfoWeth = await unichainWethComet.getAssetInfoByAddress(unichainUNI.address); + const unichainEzETHAssetInfoWeth = await unichainWethComet.getAssetInfoByAddress(unichainEzETH.address); + const unichainWeETHAssetInfoWeth = await unichainWethComet.getAssetInfoByAddress(unichainWeETH.address); + + expect(unichainUniAssetInfoWeth.scale).to.equal(exp(1, supplyCapConfig.Unichain.WETH.UNI.decimals)); + expect(unichainEzETHAssetInfoWeth.scale).to.equal(exp(1, supplyCapConfig.Unichain.WETH.ezETH.decimals)); + expect(unichainWeETHAssetInfoWeth.scale).to.equal(exp(1, supplyCapConfig.Unichain.WETH.weETH.decimals)); + + expect(unichainUniAssetInfoWeth.supplyCap).to.equal(exp(supplyCapConfig.Unichain.WETH.UNI.newCap, supplyCapConfig.Unichain.WETH.UNI.decimals)); + expect(unichainEzETHAssetInfoWeth.supplyCap).to.equal(exp(supplyCapConfig.Unichain.WETH.ezETH.newCap, supplyCapConfig.Unichain.WETH.ezETH.decimals)); + expect(unichainWeETHAssetInfoWeth.supplyCap).to.equal(exp(supplyCapConfig.Unichain.WETH.weETH.newCap, supplyCapConfig.Unichain.WETH.weETH.decimals)); + }, +}); diff --git a/deployments/mantle/usde/migrations/1778758319_update_supply_caps_on_l2.ts b/deployments/mantle/usde/migrations/1778758319_update_supply_caps_on_l2.ts new file mode 100644 index 000000000..3cb12b260 --- /dev/null +++ b/deployments/mantle/usde/migrations/1778758319_update_supply_caps_on_l2.ts @@ -0,0 +1,147 @@ +import { expect } from 'chai'; +import { Contract, utils } from 'ethers'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { exp, proposal } from '../../../../src/deploy'; + +/* +// Mantle + +Mantle USDe Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +mETH 3,000 1,533 51.09% 1,993 Rule 2 (~30% buffer) +FBTC 120 4 3.42% 5 Rule 2 (~25% buffer) +*/ + +const cometConfig = { + Mantle: { + USDe: { + address: '0x606174f62cd968d8e684c645080fa694c1D7786E', + }, + }, +}; + +const supplyCapConfig = { + Mantle: { + USDe: { + mETH: { + newCap: 1_993, + decimals: 18, + }, + FBTC: { + newCap: 5, + decimals: 8, + }, + }, + }, +}; + + +export default migration('1778758319_update_supply_caps_on_l2', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager, govDeploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const { + governor, + mantleL1CrossDomainMessenger + } = await govDeploymentManager.getContracts(); + + // Mantle + const { + bridgeReceiver: mantleBridgeReceiver, + configurator: mantleConfigurator, + cometAdmin: mantleCometAdmin, + mETH: mantleMETH, + FBTC: mantleFBTC, + } = await deploymentManager.getContracts(); + + const mantleMETHUpdateSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Mantle.USDe.address, mantleMETH.address, exp(supplyCapConfig.Mantle.USDe.mETH.newCap, supplyCapConfig.Mantle.USDe.mETH.decimals)]); + const mantleFBTCUpdateSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Mantle.USDe.address, mantleFBTC.address, exp(supplyCapConfig.Mantle.USDe.FBTC.newCap, supplyCapConfig.Mantle.USDe.FBTC.decimals)]); + const mantleDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [mantleConfigurator.address, cometConfig.Mantle.USDe.address]); + + const mantleProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + // USDe Comet + mantleConfigurator.address, // mETH + mantleConfigurator.address, // FBTC + mantleCometAdmin.address, + ], + [ + // USDe Comet + 0, // mETH + 0, // FBTC + 0, + ], + [ + // USDe Comet + 'updateAssetSupplyCap(address,address,uint128)', // mETH + 'updateAssetSupplyCap(address,address,uint128)', // FBTC + 'deployAndUpgradeTo(address,address)', + ], + [ + // USDe Comet + mantleMETHUpdateSupplyCapCalldata, + mantleFBTCUpdateSupplyCapCalldata, + mantleDeployAndUpgradeToCalldata, + ], + ] + ); + + const mainnetActions = [ + // 1. Mantle proposal + { + contract: mantleL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [mantleBridgeReceiver.address, mantleProposalData, 2_500_000], + }, + ]; + + const description = `DESCRIPTION`; + + const txn = await govDeploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 600_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + // Mantle + const { + mETH: mantleMETH, + FBTC: mantleFBTC, + } = await deploymentManager.getContracts(); + + const mantleUsdeComet = new Contract( + cometConfig.Mantle.USDe.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await deploymentManager.getSigner() + ); + + const mETHAssetInfoMantleUsde = await mantleUsdeComet.getAssetInfoByAddress(mantleMETH.address); + const FBTCAssetInfoMantleUsde = await mantleUsdeComet.getAssetInfoByAddress(mantleFBTC.address); + + expect(mETHAssetInfoMantleUsde.scale).to.equal(exp(1, supplyCapConfig.Mantle.USDe.mETH.decimals)); + expect(FBTCAssetInfoMantleUsde.scale).to.equal(exp(1, supplyCapConfig.Mantle.USDe.FBTC.decimals)); + + expect(mETHAssetInfoMantleUsde.supplyCap).to.equal(exp(supplyCapConfig.Mantle.USDe.mETH.newCap, supplyCapConfig.Mantle.USDe.mETH.decimals)); + expect(FBTCAssetInfoMantleUsde.supplyCap).to.equal(exp(supplyCapConfig.Mantle.USDe.FBTC.newCap, supplyCapConfig.Mantle.USDe.FBTC.decimals)); + }, +}); diff --git a/deployments/optimism/usdc/migrations/1779114960_update_supply_caps_on_l2.ts b/deployments/optimism/usdc/migrations/1779114960_update_supply_caps_on_l2.ts new file mode 100644 index 000000000..c6abc134a --- /dev/null +++ b/deployments/optimism/usdc/migrations/1779114960_update_supply_caps_on_l2.ts @@ -0,0 +1,251 @@ +import { expect } from 'chai'; +import { Contract, utils } from 'ethers'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { exp, proposal } from '../../../../src/deploy'; + +/* +// Optimism + +Optimism USDC Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +OP 1,400,000 122,116 8.72% 158,750 Rule 2 (~30% buffer) + +Optimism USDT Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +OP 1,000,000 311,056 31.11% 404,373 Rule 2 (~30% buffer) + +Optimism WETH Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +weETH 1,600 804 50.27% 1,046 Rule 2 (~30% buffer) +rETH 5,000 76 1.52% 99 Rule 2 (~30% buffer) +ezETH 3,200 212 6.63% 276 Rule 2 (~30% buffer) + +*/ + +const cometConfig = { + Optimism: { + USDC: { + address: '0x2e44e174f7D53F0212823acC11C01A11d58c5bCB', + }, + USDT: { + address: '0x995E394b8B2437aC8Ce61Ee0bC610D617962B214', + }, + WETH: { + address: '0xE36A30D249f7761327fd973001A32010b521b6Fd', + }, + }, +}; + +const supplyCapConfig = { + Optimism : { + USDC: { + OP: { + newCap: 158_750, + decimals: 18, + }, + }, + USDT: { + OP: { + newCap: 404_373, + decimals: 18, + }, + }, + WETH: { + weETH: { + newCap: 1_046, + decimals: 18, + }, + rETH: { + newCap: 99, + decimals: 18, + }, + ezETH: { + newCap: 276, + decimals: 18, + }, + }, + }, +}; + + +export default migration('1779114960_update_supply_caps_on_l2', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager, governanceDeploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const { + governor, + opL1CrossDomainMessenger, + } = await governanceDeploymentManager.getContracts(); + + // Optimism + const { + bridgeReceiver: optimismBridgeReceiver, + configurator: optimismConfigurator, + cometAdmin: optimismCometAdmin, + OP: optimismOP, + } = await deploymentManager.getContracts(); + + const optimismUsdcUpdateOpSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Optimism.USDC.address, optimismOP.address, exp(supplyCapConfig.Optimism.USDC.OP.newCap, supplyCapConfig.Optimism.USDC.OP.decimals)]); + const optimismUsdcDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [optimismConfigurator.address, cometConfig.Optimism.USDC.address]); + + const optimismUsdtUpdateOpSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Optimism.USDT.address, optimismOP.address, exp(supplyCapConfig.Optimism.USDT.OP.newCap, supplyCapConfig.Optimism.USDT.OP.decimals)]); + const optimismUsdtDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [optimismConfigurator.address, cometConfig.Optimism.USDT.address]); + + const optimismDmWeth = await deploymentManager.addBridgedDeploymentManager('optimism', 'weth', deploymentManager.hre); + const { + weETH: optimismWeETH, + rETH: optimismRETH, + ezETH: optimismEzETH, + } = await optimismDmWeth.getContracts(); + + const optimismWethUpdateWeETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Optimism.WETH.address, optimismWeETH.address, exp(supplyCapConfig.Optimism.WETH.weETH.newCap, supplyCapConfig.Optimism.WETH.weETH.decimals)]); + const optimismWethUpdateRETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Optimism.WETH.address, optimismRETH.address, exp(supplyCapConfig.Optimism.WETH.rETH.newCap, supplyCapConfig.Optimism.WETH.rETH.decimals)]); + const optimismWethUpdateEzETHSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Optimism.WETH.address, optimismEzETH.address, exp(supplyCapConfig.Optimism.WETH.ezETH.newCap, supplyCapConfig.Optimism.WETH.ezETH.decimals)]); + const optimismWethDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [optimismConfigurator.address, cometConfig.Optimism.WETH.address]); + + const optimismProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + // USDC Comet + optimismConfigurator.address, // OP + optimismCometAdmin.address, + // USDT Comet + optimismConfigurator.address, // OP + optimismCometAdmin.address, + // WETH Comet + optimismConfigurator.address, // weETH + optimismConfigurator.address, // rETH + optimismConfigurator.address, // ezETH + optimismCometAdmin.address, + ], + [ + // USDC Comet + 0, // OP + 0, + // USDT Comet + 0, // OP + 0, + // WETH Comet + 0, // weETH + 0, // rETH + 0, // ezETH + 0, + ], + [ + // USDC Comet + 'updateAssetSupplyCap(address,address,uint128)', // OP + 'deployAndUpgradeTo(address,address)', + // USDT Comet + 'updateAssetSupplyCap(address,address,uint128)', // OP + 'deployAndUpgradeTo(address,address)', + // WETH Comet + 'updateAssetSupplyCap(address,address,uint128)', // weETH + 'updateAssetSupplyCap(address,address,uint128)', // rETH + 'updateAssetSupplyCap(address,address,uint128)', // ezETH + 'deployAndUpgradeTo(address,address)', + ], + [ + // USDC Comet + optimismUsdcUpdateOpSupplyCapCalldata, + optimismUsdcDeployAndUpgradeToCalldata, + // USDT Comet + optimismUsdtUpdateOpSupplyCapCalldata, + optimismUsdtDeployAndUpgradeToCalldata, + // WETH Comet + optimismWethUpdateWeETHSupplyCapCalldata, + optimismWethUpdateRETHSupplyCapCalldata, + optimismWethUpdateEzETHSupplyCapCalldata, + optimismWethDeployAndUpgradeToCalldata, + ], + ] + ); + + const mainnetActions = [ + // 1. Optimism proposal + { + contract: opL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [optimismBridgeReceiver.address, optimismProposalData, 3_000_000] + }, + ]; + + const description = `DESCRIPTION`; + + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 600_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + // Optimism + const { + OP: optimismOP, + } = await deploymentManager.getContracts(); + + // USDC Comet + const optimismUsdcComet = new Contract( + cometConfig.Optimism.USDC.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await deploymentManager.getSigner() + ); + + const OPAssetInfoUsdc = await optimismUsdcComet.getAssetInfoByAddress(optimismOP.address); + + expect(OPAssetInfoUsdc.scale).to.equal(exp(1, supplyCapConfig.Optimism.USDC.OP.decimals)); + expect(OPAssetInfoUsdc.supplyCap).to.equal(exp(supplyCapConfig.Optimism.USDC.OP.newCap, supplyCapConfig.Optimism.USDC.OP.decimals)); + + // USDT Comet + const optimismUsdtComet = new Contract( + cometConfig.Optimism.USDT.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await deploymentManager.getSigner() + ); + const OPAssetInfoUsdt = await optimismUsdtComet.getAssetInfoByAddress(optimismOP.address); + expect(OPAssetInfoUsdt.scale).to.equal(exp(1, supplyCapConfig.Optimism.USDT.OP.decimals)); + expect(OPAssetInfoUsdt.supplyCap).to.equal(exp(supplyCapConfig.Optimism.USDT.OP.newCap, supplyCapConfig.Optimism.USDT.OP.decimals)); + + // WETH Comet + const optimismWethComet = new Contract( + cometConfig.Optimism.WETH.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await deploymentManager.getSigner() + ); + const optimismDmWeth = deploymentManager.bridgedDeploymentManagers.get('optimism:weth') as DeploymentManager; + const { + weETH: optimismWeETH, + rETH: optimismRETH, + ezETH: optimismEzETH, + } = await optimismDmWeth.getContracts(); + + const weETHAssetInfoWeth = await optimismWethComet.getAssetInfoByAddress(optimismWeETH.address); + const rETHAssetInfoWeth = await optimismWethComet.getAssetInfoByAddress(optimismRETH.address); + const ezETHAssetInfoWeth = await optimismWethComet.getAssetInfoByAddress(optimismEzETH.address); + + expect(weETHAssetInfoWeth.scale).to.equal(exp(1, supplyCapConfig.Optimism.WETH.weETH.decimals)); + expect(rETHAssetInfoWeth.scale).to.equal(exp(1, supplyCapConfig.Optimism.WETH.rETH.decimals)); + expect(ezETHAssetInfoWeth.scale).to.equal(exp(1, supplyCapConfig.Optimism.WETH.ezETH.decimals)); + + expect(weETHAssetInfoWeth.supplyCap).to.equal(exp(supplyCapConfig.Optimism.WETH.weETH.newCap, supplyCapConfig.Optimism.WETH.weETH.decimals)); + expect(rETHAssetInfoWeth.supplyCap).to.equal(exp(supplyCapConfig.Optimism.WETH.rETH.newCap, supplyCapConfig.Optimism.WETH.rETH.decimals)); + expect(ezETHAssetInfoWeth.supplyCap).to.equal(exp(supplyCapConfig.Optimism.WETH.ezETH.newCap, supplyCapConfig.Optimism.WETH.ezETH.decimals)); + }, +}); diff --git a/deployments/polygon/usdc/migrations/1779114960_update_supply_caps_on_l2.ts b/deployments/polygon/usdc/migrations/1779114960_update_supply_caps_on_l2.ts new file mode 100644 index 000000000..b27f10dcc --- /dev/null +++ b/deployments/polygon/usdc/migrations/1779114960_update_supply_caps_on_l2.ts @@ -0,0 +1,203 @@ +import { expect } from 'chai'; +import { Contract, utils } from 'ethers'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { exp, proposal } from '../../../../src/deploy'; + +/* +// Polygon + +Polygon USDC Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +WPOL 8,000,000 377,485 4.72% 490,731 Rule 2 (~30% buffer) +MaticX 3,200,000 183,489 5.73% 238,536 Rule 2 (~30% buffer) + +Polygon USDT Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +WPOL 5,000,000 155,574 3.11% 202,246 Rule 2 (~30% buffer) +MaticX 4,160,000 123,953 2.98% 161,140 Rule 2 (~30% buffer) + +*/ + +const cometConfig = { + Polygon: { + USDC: { + address: '0xF25212E676D1F7F89Cd72fFEe66158f541246445', + }, + USDT: { + address: '0xaeB318360f27748Acb200CE616E389A6C9409a07', + }, + }, +}; + +const supplyCapConfig = { + Polygon: { + USDC: { + WPOL: { + newCap: 490_731, + decimals: 18, + }, + MaticX: { + newCap: 238_536, + decimals: 18, + }, + }, + USDT: { + WPOL: { + newCap: 202_246, + decimals: 18, + }, + MaticX: { + newCap: 161_140, + decimals: 18, + }, + }, + }, +}; + + +export default migration('1779114960_update_supply_caps_on_l2', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager, governanceDeploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const { + governor, + fxRoot, + } = await governanceDeploymentManager.getContracts(); + + // Polygon + const { + bridgeReceiver: polygonBridgeReceiver, + configurator: polygonConfigurator, + cometAdmin: polygonCometAdmin, + WPOL: polygonWPOL, + MaticX: polygonMaticX, + } = await deploymentManager.getContracts(); + + const polygonUsdcUpdateWPOLSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Polygon.USDC.address, polygonWPOL.address, exp(supplyCapConfig.Polygon.USDC.WPOL.newCap, supplyCapConfig.Polygon.USDC.WPOL.decimals)]); + const polygonUsdcUpdateMaticXSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Polygon.USDC.address, polygonMaticX.address, exp(supplyCapConfig.Polygon.USDC.MaticX.newCap, supplyCapConfig.Polygon.USDC.MaticX.decimals)]); + const polygonUsdcDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [polygonConfigurator.address, cometConfig.Polygon.USDC.address]); + + const polygonUsdtUpdateWPOLSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Polygon.USDT.address, polygonWPOL.address, exp(supplyCapConfig.Polygon.USDT.WPOL.newCap, supplyCapConfig.Polygon.USDT.WPOL.decimals)]); + const polygonUsdtUpdateMaticXSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Polygon.USDT.address, polygonMaticX.address, exp(supplyCapConfig.Polygon.USDT.MaticX.newCap, supplyCapConfig.Polygon.USDT.MaticX.decimals)]); + const polygonUsdtDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [polygonConfigurator.address, cometConfig.Polygon.USDT.address]); + + const polygonProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + // USDC Comet + polygonConfigurator.address, + polygonConfigurator.address, + polygonCometAdmin.address, + // USDT Comet + polygonConfigurator.address, + polygonConfigurator.address, + polygonCometAdmin.address, + ], + [ + // USDC Comet + 0, + 0, + 0, + // USDT Comet + 0, + 0, + 0, + ], + [ + // USDC Comet + 'updateAssetSupplyCap(address,address,uint128)', + 'updateAssetSupplyCap(address,address,uint128)', + 'deployAndUpgradeTo(address,address)', + // USDT Comet + 'updateAssetSupplyCap(address,address,uint128)', + 'updateAssetSupplyCap(address,address,uint128)', + 'deployAndUpgradeTo(address,address)', + ], + [ + // USDC Comet + polygonUsdcUpdateWPOLSupplyCapCalldata, + polygonUsdcUpdateMaticXSupplyCapCalldata, + polygonUsdcDeployAndUpgradeToCalldata, + // USDT Comet + polygonUsdtUpdateWPOLSupplyCapCalldata, + polygonUsdtUpdateMaticXSupplyCapCalldata, + polygonUsdtDeployAndUpgradeToCalldata + ], + ] + ); + + const mainnetActions = [ + // 1. Polygon proposal + { + contract: fxRoot, + signature: 'sendMessageToChild(address,bytes)', + args: [polygonBridgeReceiver.address, polygonProposalData], + }, + ]; + + const description = `DESCRIPTION`; + + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 600_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager) { + // Polygon + const { + WPOL: polygonWPOL, + MaticX: polygonMaticX, + } = await deploymentManager.getContracts(); + + // USDC Comet + const polygonUsdcComet = new Contract( + cometConfig.Polygon.USDC.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await deploymentManager.getSigner() + ); + + const WPOLAssetInfoUsdc = await polygonUsdcComet.getAssetInfoByAddress(polygonWPOL.address); + const MaticXAssetInfoUsdc = await polygonUsdcComet.getAssetInfoByAddress(polygonMaticX.address); + + expect(WPOLAssetInfoUsdc.scale).to.equal(exp(1, supplyCapConfig.Polygon.USDC.WPOL.decimals)); + expect(WPOLAssetInfoUsdc.supplyCap).to.equal(exp(supplyCapConfig.Polygon.USDC.WPOL.newCap, supplyCapConfig.Polygon.USDC.WPOL.decimals)); + + expect(MaticXAssetInfoUsdc.scale).to.equal(exp(1, supplyCapConfig.Polygon.USDC.MaticX.decimals)); + expect(MaticXAssetInfoUsdc.supplyCap).to.equal(exp(supplyCapConfig.Polygon.USDC.MaticX.newCap, supplyCapConfig.Polygon.USDC.MaticX.decimals)); + + // USDT Comet + const polygonUsdtComet = new Contract( + cometConfig.Polygon.USDT.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await deploymentManager.getSigner() + ); + + const WPOLAssetInfoUsdt = await polygonUsdtComet.getAssetInfoByAddress(polygonWPOL.address); + const MaticXAssetInfoUsdt = await polygonUsdtComet.getAssetInfoByAddress(polygonMaticX.address); + + expect(WPOLAssetInfoUsdt.scale).to.equal(exp(1, supplyCapConfig.Polygon.USDT.WPOL.decimals)); + expect(WPOLAssetInfoUsdt.supplyCap).to.equal(exp(supplyCapConfig.Polygon.USDT.WPOL.newCap, supplyCapConfig.Polygon.USDT.WPOL.decimals)); + + expect(MaticXAssetInfoUsdt.scale).to.equal(exp(1, supplyCapConfig.Polygon.USDT.MaticX.decimals)); + expect(MaticXAssetInfoUsdt.supplyCap).to.equal(exp(supplyCapConfig.Polygon.USDT.MaticX.newCap, supplyCapConfig.Polygon.USDT.MaticX.decimals)); + }, +}); diff --git a/deployments/relations.ts b/deployments/relations.ts index b48345c0b..0f5b038ea 100644 --- a/deployments/relations.ts +++ b/deployments/relations.ts @@ -56,15 +56,20 @@ const relationConfigMap: RelationConfigMap = { // This is a workaround for contracts that don't work in Hardhat fork // invalid opcode when calling symbol() + // Arbitrum-specific known contract mappings if (address === '0xd09acb80c1e8f2291862c4978a008791c9167003') { return 'tETH'; } if (address === '0x5a7facb970d094b6c7ff1df0ea68d99e6e73cbff') { return 'weETH'; } - if (address.toLowerCase() === '0x87eee96d50fb761ad85b1c982d28a042169d61b1') { + if (address === '0x87eee96d50fb761ad85b1c982d28a042169d61b1') { return 'wrsETH'; } + // Mantle-specific known contract mapping + if (address === '0xcda86a272531e8640cd7f1a92c01839911b90bb0') { + return 'mETH'; + } throw new Error(`Failed to get symbol for token ${token.address}: ${e.message}`); } @@ -97,6 +102,10 @@ const relationConfigMap: RelationConfigMap = { if (address === '0x87eee96d50fb761ad85b1c982d28a042169d61b1') { return 'wrsETH:priceFeed'; } + // Known contract mapping for Mantle + if (address === '0xcda86a272531e8640cd7f1a92c01839911b90bb0') { + return 'mETH:priceFeed'; + } throw new Error(`Failed to get symbol for token ${assets[i].address}: ${e.message}`); } diff --git a/deployments/unichain/usdc/migrations/1779114960_update_supply_caps_on_l2.ts b/deployments/unichain/usdc/migrations/1779114960_update_supply_caps_on_l2.ts new file mode 100644 index 000000000..53675a169 --- /dev/null +++ b/deployments/unichain/usdc/migrations/1779114960_update_supply_caps_on_l2.ts @@ -0,0 +1,205 @@ +import { expect } from 'chai'; +import { Contract, utils } from 'ethers'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { exp, proposal } from '../../../../src/deploy'; + +/* +// Unichain + +Unichain USDC Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +UNI 100,000 3,313 3.31% 4,307 Rule 2 (~30% buffer) + +Unichain WETH Comet +Symbol Current Cap Supply Balance Utilization Proposed Cap Rule +ezETH 2,200 0 0.00% 0 Rule 1 +UNI 500,000 20 0.00% 0 Rule 1 +weETH 5,000 733 14.65% 952 Rule 2 (~30% buffer) +*/ + +const cometConfig = { + Unichain: { + USDC: { + address: '0x2c7118c4C88B9841FCF839074c26Ae8f035f2921', + }, + WETH: { + address: '0x6C987dDE50dB1dcDd32Cd4175778C2a291978E2a', + }, + }, +}; + +const supplyCapConfig = { + Unichain: { + USDC: { + UNI: { + newCap: 4_307, + decimals: 18, + }, + }, + WETH: { + ezETH: { + newCap: 0, + decimals: 18, + }, + UNI: { + newCap: 0, + decimals: 18, + }, + weETH: { + newCap: 952, + decimals: 18, + }, + }, + }, +}; + + +export default migration('1779114960_update_supply_caps_on_l2', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager, governanceDeploymentManager: DeploymentManager) { + + const trace = deploymentManager.tracer(); + + const { + governor, + unichainL1CrossDomainMessenger, + } = await governanceDeploymentManager.getContracts(); + + // Unichain + const unichainDm = await governanceDeploymentManager.addBridgedDeploymentManager('unichain', 'weth', deploymentManager.hre); + const { + bridgeReceiver: unichainBridgeReceiver, + configurator: unichainConfigurator, + cometAdmin: unichainCometAdmin, + UNI: unichainMETH, + ezETH: unichainEzETH, + weETH: unichainWeETH, + } = await unichainDm.getContracts(); + + const unichainUsdcUniUpdateSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Unichain.USDC.address, unichainMETH.address, exp(supplyCapConfig.Unichain.USDC.UNI.newCap, supplyCapConfig.Unichain.USDC.UNI.decimals)]); + const unichainUsdcDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [unichainConfigurator.address, cometConfig.Unichain.USDC.address]); + + const unichainWethUniETHUpdateSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Unichain.WETH.address, unichainEzETH.address, exp(supplyCapConfig.Unichain.WETH.UNI.newCap, supplyCapConfig.Unichain.WETH.UNI.decimals)]); + const unichainWethEzEthUpdateSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Unichain.WETH.address, unichainMETH.address, exp(supplyCapConfig.Unichain.WETH.ezETH.newCap, supplyCapConfig.Unichain.WETH.ezETH.decimals)]); + const unichainWethWeEthUpdateSupplyCapCalldata = utils.defaultAbiCoder.encode(['address', 'address', 'uint128'], [cometConfig.Unichain.WETH.address, unichainWeETH.address, exp(supplyCapConfig.Unichain.WETH.weETH.newCap, supplyCapConfig.Unichain.WETH.weETH.decimals)]); + const unichainWethDeployAndUpgradeToCalldata = utils.defaultAbiCoder.encode(['address', 'address'], [unichainConfigurator.address, cometConfig.Unichain.WETH.address]); + + const unichainProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + // USDC Comet + unichainConfigurator.address, // UNI + unichainCometAdmin.address, + // WETH Comet + unichainConfigurator.address, // UNI + unichainConfigurator.address, // ezETH + unichainConfigurator.address, // weETH + unichainCometAdmin.address, + ], + [ + // USDC Comet + 0, // UNI + 0, + // WETH Comet + 0, // UNI + 0, // ezETH + 0, // weETH + 0, + ], + [ + // USDC Comet + 'updateAssetSupplyCap(address,address,uint128)', // UNI + 'deployAndUpgradeTo(address,address)', + // WETH Comet + 'updateAssetSupplyCap(address,address,uint128)', // UNI + 'updateAssetSupplyCap(address,address,uint128)', // ezETH + 'updateAssetSupplyCap(address,address,uint128)', // weETH + 'deployAndUpgradeTo(address,address)', + ], + [ + // USDC Comet + unichainUsdcUniUpdateSupplyCapCalldata, + unichainUsdcDeployAndUpgradeToCalldata, + // WETH Comet + unichainWethUniETHUpdateSupplyCapCalldata, + unichainWethEzEthUpdateSupplyCapCalldata, + unichainWethWeEthUpdateSupplyCapCalldata, + unichainWethDeployAndUpgradeToCalldata, + ], + ] + ); + + const mainnetActions = [ + // 1. Unichain proposal + { + contract: unichainL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [unichainBridgeReceiver.address, unichainProposalData, 3_000_000], + }, + ]; + + const description = `DESCRIPTION`; + + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 600_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return true; + }, + + async verify(deploymentManager: DeploymentManager, governanceDeploymentManager: DeploymentManager) { + // Unichain + const unichainDm = governanceDeploymentManager.bridgedDeploymentManagers.get('unichain:weth') as DeploymentManager; + const { + UNI: unichainUNI, + ezETH: unichainEzETH, + weETH: unichainWeETH, + } = await unichainDm.getContracts(); + + // USDC Comet + const unichainUsdcComet = new Contract( + cometConfig.Unichain.USDC.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await deploymentManager.getSigner() + ); + + const unichainUNIAssetInfoUsdc = await unichainUsdcComet.getAssetInfoByAddress(unichainUNI.address); + + expect(unichainUNIAssetInfoUsdc.scale).to.equal(exp(1, supplyCapConfig.Unichain.USDC.UNI.decimals)); + expect(unichainUNIAssetInfoUsdc.supplyCap).to.equal(exp(supplyCapConfig.Unichain.USDC.UNI.newCap, supplyCapConfig.Unichain.USDC.UNI.decimals)); + + // WETH Comet + const unichainWethComet = new Contract( + cometConfig.Unichain.WETH.address, + ['function getAssetInfoByAddress(address asset) public view returns((uint8 offset, address asset, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap))'], + await deploymentManager.getSigner() + ); + + const unichainUniAssetInfoWeth = await unichainWethComet.getAssetInfoByAddress(unichainUNI.address); + const unichainEzETHAssetInfoWeth = await unichainWethComet.getAssetInfoByAddress(unichainEzETH.address); + const unichainWeETHAssetInfoWeth = await unichainWethComet.getAssetInfoByAddress(unichainWeETH.address); + + expect(unichainUniAssetInfoWeth.scale).to.equal(exp(1, supplyCapConfig.Unichain.WETH.UNI.decimals)); + expect(unichainEzETHAssetInfoWeth.scale).to.equal(exp(1, supplyCapConfig.Unichain.WETH.ezETH.decimals)); + expect(unichainWeETHAssetInfoWeth.scale).to.equal(exp(1, supplyCapConfig.Unichain.WETH.weETH.decimals)); + + expect(unichainUniAssetInfoWeth.supplyCap).to.equal(exp(supplyCapConfig.Unichain.WETH.UNI.newCap, supplyCapConfig.Unichain.WETH.UNI.decimals)); + expect(unichainEzETHAssetInfoWeth.supplyCap).to.equal(exp(supplyCapConfig.Unichain.WETH.ezETH.newCap, supplyCapConfig.Unichain.WETH.ezETH.decimals)); + expect(unichainWeETHAssetInfoWeth.supplyCap).to.equal(exp(supplyCapConfig.Unichain.WETH.weETH.newCap, supplyCapConfig.Unichain.WETH.weETH.decimals)); + }, +}); diff --git a/hardhat.config.ts b/hardhat.config.ts index 3b7861abd..b47fc5b71 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -3,7 +3,6 @@ import 'dotenv/config'; import { HardhatUserConfig, subtask, task } from 'hardhat/config'; import '@compound-finance/hardhat-import'; import '@nomiclabs/hardhat-etherscan'; -import '@tenderly/hardhat-tenderly'; import '@nomiclabs/hardhat-ethers'; import '@typechain/hardhat'; import 'hardhat-chai-matchers'; @@ -85,7 +84,7 @@ const { REMOTE_ACCOUNTS = '' } = process.env; -function* deriveAccounts(pk: string, n: number = 10) { +function* deriveAccounts(pk: string, n: number = 20) { for (let i = 0; i < n; i++){ if(!pk.startsWith('0x')) pk = '0x' + pk; yield (BigInt(pk) + BigInt(i)).toString(16); @@ -198,7 +197,7 @@ export const networkConfigs: NetworkConfig[] = [ { network: 'scroll', chainId: 534352, - url: 'https://scroll.drpc.org', + url: 'https://scroll-mainnet.gateway.tenderly.co', }, ]; @@ -704,13 +703,6 @@ const config: HardhatUserConfig = { ], }, - tenderly: { - project: 'comet', - username: process.env.TENDERLY_USERNAME || '', - accessKey: process.env.TENDERLY_ACCESS_KEY || '', - privateVerification: false, - }, - mocha: { reporter: 'mocha-multi-reporters', reporterOptions: { diff --git a/plugins/deployment_manager/DeploymentManager.ts b/plugins/deployment_manager/DeploymentManager.ts index 5ddf68d71..c8e7f7383 100644 --- a/plugins/deployment_manager/DeploymentManager.ts +++ b/plugins/deployment_manager/DeploymentManager.ts @@ -51,6 +51,7 @@ export class DeploymentManager { cache: Cache; // TODO: kind of a misnomer since its handling *all* path stuff contractsCache: ContractMap | null; _signers: SignerWithAddress[]; + bridgedDeploymentManagers: Map = new Map(); constructor( network: string, @@ -75,6 +76,20 @@ export class DeploymentManager { this._signers = []; } + async addBridgedDeploymentManager(network: string, deployment: string, hre?: HardhatRuntimeEnvironment): Promise { + const key = `${network}:${deployment}`; + if (!this.bridgedDeploymentManagers.has(key)) { + if(!hre && this.network !== network) { + throw new Error(`Must provide hre to bridge to a different network deployment manager`); + } + const dm = new DeploymentManager(network, deployment, hre ?? this.hre, { writeCacheToDisk: true }); + await dm.loadContractsFromExistingCache(); + await dm.spider(); + this.bridgedDeploymentManagers.set(key, dm); + } + return this.bridgedDeploymentManagers.get(key)!; + } + async getSigners(): Promise { if (this._signers.length > 0) { return this._signers; diff --git a/plugins/deployment_manager/Import.ts b/plugins/deployment_manager/Import.ts index 1c3fe593e..42214832a 100644 --- a/plugins/deployment_manager/Import.ts +++ b/plugins/deployment_manager/Import.ts @@ -23,7 +23,7 @@ export async function fetchAndCacheContract( return buildFile; } -const blockScoutNetworks = ['unichain']; +const blockScoutNetworks = ['unichain', 'scroll']; // Wrapper for pulling contract data from Etherscan export async function importContract( diff --git a/plugins/import/blockscout.ts b/plugins/import/blockscout.ts index b693c551d..7a74d70f0 100644 --- a/plugins/import/blockscout.ts +++ b/plugins/import/blockscout.ts @@ -10,6 +10,7 @@ export interface Result { export function getBlockscoutApiUrl(network: string): string { let host = { 'unichain': 'unichain.blockscout.com', + 'scroll': 'scrollscan.com' }[network]; if (!host) { @@ -22,6 +23,7 @@ export function getBlockscoutApiUrl(network: string): string { export function getBlockscoutUrl(network: string): string { let host = { 'unichain': 'unichain.blockscout.com', + 'scroll': 'scrollscan.com' }[network]; if (!host) { @@ -33,7 +35,8 @@ export function getBlockscoutUrl(network: string): string { export async function getBlockscoutRPCUrl(network: string): Promise { let host = { - 'unichain': `${process.env.UNICHAIN_QUICKNODE_LINK}`.replace('https://', '') + 'unichain': `${process.env.UNICHAIN_QUICKNODE_LINK}`.replace('https://', ''), + 'scroll': `scroll-mainnet.gateway.tenderly.co`, }[network]; if (!host) { diff --git a/plugins/scenario/utils/hreForBase.ts b/plugins/scenario/utils/hreForBase.ts index 2328074c7..ee47241bf 100644 --- a/plugins/scenario/utils/hreForBase.ts +++ b/plugins/scenario/utils/hreForBase.ts @@ -9,6 +9,7 @@ import { Environment } from 'hardhat/internal/core/runtime-environment'; import { ForkSpec } from '../World'; import { HttpNetworkUserConfig } from 'hardhat/types'; import { EthereumProvider } from 'hardhat/types/provider'; +import { networkConfigs } from '../../../hardhat.config'; /* mimics https://github.com/nomiclabs/hardhat/blob/master/packages/hardhat-core/src/internal/lib/hardhat-lib.ts @@ -91,6 +92,12 @@ function getBlockRollback(base: ForkSpec) { return 25; } +let activeMigration = false; + +export function migrationStarted() { + activeMigration = true; +} + export async function forkedHreForBase(base: ForkSpec): Promise { const ctx: HardhatContext = HardhatContext.getHardhatContext(); @@ -103,16 +110,21 @@ export async function forkedHreForBase(base: ForkSpec): Promise { + if (activeMigration){ + return networkConfigs.find(c => c.network === base.network)?.url; + } + return baseNetwork.url; + })(); + const provider = new ethers.providers.JsonRpcProvider(providerUrl); + if(providerUrl) console.log(`Forking from network: ${base.network} at block number: ${await provider.getBlockNumber() - (getBlockRollback(base) || 0)}`); // noNetwork otherwise - if (!base.blockNumber && baseNetwork.url && getBlockRollback(base) !== undefined) + if (!base.blockNumber && providerUrl && getBlockRollback(base) !== undefined) base.blockNumber = await provider.getBlockNumber() - getBlockRollback(base); // arbitrary number of blocks to go back if (getBlockRollback(base) === 0) { - const provider = new ethers.providers.JsonRpcProvider(baseNetwork.url); const block = await provider.getBlockNumber(); base.blockNumber = block - 1; } @@ -126,7 +138,7 @@ export async function forkedHreForBase(base: ForkSpec): Promise { @@ -78,24 +78,20 @@ export class ProposalConstraint implements StaticConstra ); } - // temporary hack to skip proposal 519 - if (proposal.id.eq(519)) { - console.log('Skipping proposal 519'); + // temporary hack to skip proposal 580 + if (proposal.id.eq(580)) { + console.log('Skipping proposal 580'); continue; } try { // Execute the proposal debug(`${label} Processing pending proposal ${proposal.id}`); - if (isBridged) { - await executeOpenProposalAndRelay( - governanceDeploymentManager, - ctx.world.deploymentManager, - proposal - ); - } else { - await executeOpenProposal(governanceDeploymentManager, proposal); - } + await executeOpenProposalAndRelay( + governanceDeploymentManager, + ctx.world.deploymentManager, + proposal + ); debug(`${label} Open proposal ${proposal.id} was executed`); } catch (err) { debug(`${label} Failed to execute proposal ${proposal.id}`, err.message); diff --git a/scenario/utils/index.ts b/scenario/utils/index.ts index 61e8f2c91..f87084c87 100644 --- a/scenario/utils/index.ts +++ b/scenario/utils/index.ts @@ -12,10 +12,10 @@ import { utils, } from 'ethers'; import { execSync } from 'child_process'; -import { existsSync } from 'fs'; +import { existsSync, unlinkSync } from 'fs'; import { CometContext } from '../context/CometContext'; import CometAsset from '../context/CometAsset'; -import { exp } from '../../test/helpers'; +import { ethers, exp } from '../../test/helpers'; import { DeploymentManager } from '../../plugins/deployment_manager'; import { impersonateAddress } from '../../plugins/scenario/utils'; import { ProposalState, OpenProposal } from '../context/Gov'; @@ -917,8 +917,6 @@ export async function tenderlyExecute( }, ]; - const chainId2 = bdm.hre.ethers.provider.network.chainId; - console.log(`\n========================== TENDERLY ==========================\n`); console.log(`\nExecuting Tenderly simulation for proposal ${id}...`); @@ -928,54 +926,93 @@ export async function tenderlyExecute( const exec1 = bundle[bundle.length - 1].simulation; - console.log(` >>> PROPOSAL EXECUTED ${id} \n`); + console.log(` >>> PROPOSAL EXECUTED ${id}`); console.log(`Simulation ${exec1.id} done, status: ${exec1.status}`); - console.log(`Link: https://www.tdly.co/shared/simulation/${exec1.id}`); - let proposals; - if (chainId1 !== chainId2) { - proposals = await relayMessage(gdm, bdm, parseFloat(B0.toString()), bundle[bundle.length - 1].transaction.transaction_info.logs); - - debug(`Proposals relayed: ${proposals.length}`); - const timelockL2 = await bdm.getContractOrThrow('timelock'); - const delay = await timelockL2.delay(); - const relayMessages = loadCachedRelayMessages(); - const latestL2 = await bdm.hre.ethers.provider.getBlock('latest'); - const maxEta = Math.max(...proposals.map(p => Number(p.eta || 0))) + delay.toNumber(); - const T0L2 = BigInt(Math.max(latestL2.timestamp, maxEta + 1)); - const B0L2 = Number(latestL2.number) + 1; - const simsL2 = relayMessages.map((msg, i, arr) => { - const isLast = i === arr.length - 1; - - const timestamp = isLast - ? Number(T0L2) - : latestL2.timestamp; - - const block = isLast - ? B0L2 : latestL2.number; - - return { - network_id: chainId2.toString(), - from: msg.signer, - to: msg.messenger, - block_number: Number(block), - block_header: { - timestamp: bdm.hre.ethers.utils.hexlify(Number(timestamp)) - }, - input: msg.callData, - save: true, - save_if_fails: true, - gas_price: 0, - gas_limit: 16_777_215, - }; - }); + console.log(`Link: https://www.tdly.co/shared/simulation/${exec1.id} \n`); + + const bdms = [bdm]; + for (const dm of gdm.bridgedDeploymentManagers.values()) { + if (!bdms.includes(dm)) { + bdms.push(dm); + } + } - if (simsL2.length > 0) { - const bundle2 = await simulateBundle(bdm, simsL2, Number(B0L2)); - console.log(` >>> PROPOSAL RELAYED ${id} \n`); - const sim = bundle2[bundle2.length - 1]; - await shareSimulation(bdm, sim.simulation.id); - console.log(`Simulation ${sim.simulation.id} done, status: ${sim.simulation.status}`); - console.log(`Link: https://www.tdly.co/shared/simulation/${sim.simulation.id}`); + // make bdm contain only 1 dm per network + const uniqueBdms = new Map(); + for (const dm of bdms) { + const chainId = dm.hre.ethers.provider.network.chainId; + if (!uniqueBdms.has(chainId)) { + uniqueBdms.set(chainId, dm); + } + } + bdms.length = 0; + bdms.push(...uniqueBdms.values()); + + + for (const currentBdm of bdms) { + const chainId2 = currentBdm.hre.ethers.provider.network.chainId; + let proposals; + if (chainId1 !== chainId2) { + const relayPath = path.resolve(__dirname, '../../cache/relay.json'); + if (existsSync(relayPath)) unlinkSync(relayPath); + + proposals = await relayMessage(gdm, currentBdm, parseFloat(B0.toString()), bundle[bundle.length - 1].transaction.transaction_info.logs); + + debug(`Proposals relayed to ${currentBdm.network}: ${proposals?.length ?? 0}`); + + if (proposals && proposals.length > 0) { + const timelockL2 = await currentBdm.getContractOrThrow('timelock'); + const delay = await timelockL2.delay(); + const relayMessages = loadCachedRelayMessages(); + const executeProposalSig = ethers.utils.id('executeProposal(uint256)').substring(0, 10); + + const latestL2 = await currentBdm.hre.ethers.provider.getBlock('latest'); + const maxEta = Math.max(...proposals.map(p => Number(p.eta || 0))) + delay.toNumber(); + const T0L2 = Math.max(latestL2.timestamp, maxEta + 1); + const B0L2 = Number(latestL2.number) + 1; + + let previousBlock = latestL2.number; + let previousTimestamp = T0L2; + const simsL2 = relayMessages.map((msg) => { + let block = previousBlock; + let timestamp = previousTimestamp; + + if (msg.callData.startsWith(executeProposalSig) && !msg.eta) { + block = block + 1; + timestamp = timestamp + delay.toNumber() + 1; + } + + previousBlock = block; + previousTimestamp = timestamp; + + return { + network_id: chainId2.toString(), + from: msg.signer, + to: msg.messenger, + block_number: Number(block), + block_header: { + timestamp: currentBdm.hre.ethers.utils.hexlify(Number(timestamp)) + }, + input: msg.callData, + save: true, + save_if_fails: true, + gas_price: 0, + }; + }); + + if (simsL2.length > 0) { + const bundle2 = await simulateBundle(currentBdm, simsL2, Number(B0L2)); + + // filter from bundle every entry with simulation.input that starts with 0x0d61b519 i.e. executeProposal(uint256) + const filteredBundle = bundle2.filter(entry => entry.simulation.input.startsWith(executeProposalSig)); + for (const sim of filteredBundle) { + await shareSimulation(currentBdm, sim.simulation.id); + console.log(`\nRelayed to ${currentBdm.network}`); + console.log(`Simulation ${sim.simulation.id} done, status: ${sim.simulation.status}`); + console.log(`Link: https://www.tdly.co/shared/simulation/${sim.simulation.id} \n`); + } + } + } } } @@ -991,7 +1028,9 @@ async function simulateBundle( const results = []; for (const sim of simulations) { - const { username, project, accessKey } = (dm.hre.config as any).tenderly; + const project = 'comet'; + const username = process.env.TENDERLY_USERNAME || ''; + const accessKey = process.env.TENDERLY_ACCESS_KEY || ''; // Merge rolling state changes with simulation's own state_objects const stateObjects = sim.state_objects @@ -1049,7 +1088,9 @@ async function simulateBundle( } async function shareSimulation(dm: DeploymentManager, simulationId: string) { - const { username, project, accessKey } = (dm.hre.config as any).tenderly; + const project = 'comet'; + const username = process.env.TENDERLY_USERNAME || ''; + const accessKey = process.env.TENDERLY_ACCESS_KEY || ''; return axios.post( `https://api.tenderly.co/api/v1/account/${username}/project/${project}/simulations/${simulationId}/share`, {}, @@ -1511,25 +1552,26 @@ export async function executeOpenProposalAndRelay( await governanceDeploymentManager.hre.ethers.provider.getBlockNumber(); await executeOpenProposal(governanceDeploymentManager, openProposal); console.log(`Executed proposal ${openProposal.id} on ${governanceDeploymentManager.network}, checking if relay to ${bridgeDeploymentManager.network} is needed...`); - await mockAllRedstoneOracles(bridgeDeploymentManager); console.log(`All Redstone oracles on ${bridgeDeploymentManager.network} are mocked`); - if ( - await isBridgeProposal( - governanceDeploymentManager, - bridgeDeploymentManager, - openProposal - ) - ) { - await relayMessage( - governanceDeploymentManager, - bridgeDeploymentManager, - startingBlockNumber - ); - } else { - console.log( - `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Proposal ${openProposal.id} doesn't target bridge; not relaying` - ); - return; + const bridgeManagers = await isBridgeProposal( + governanceDeploymentManager, + bridgeDeploymentManager, + openProposal + ); + for (const bridgeManager of bridgeManagers) { + await mockAllRedstoneOracles(bridgeManager); + if (bridgeManager) { + await relayMessage( + governanceDeploymentManager, + bridgeManager, + startingBlockNumber + ); + } else { + console.log( + `[${governanceDeploymentManager.network} -> ${bridgeManager.network}] Proposal ${openProposal.id} doesn't target bridge; not relaying` + ); + return; + } } } diff --git a/scenario/utils/isBridgeProposal.ts b/scenario/utils/isBridgeProposal.ts index f2d4ac362..63957eccf 100644 --- a/scenario/utils/isBridgeProposal.ts +++ b/scenario/utils/isBridgeProposal.ts @@ -1,142 +1,155 @@ import { DeploymentManager } from '../../plugins/deployment_manager'; +import { getRoots } from '../../plugins/deployment_manager/Roots'; import { OpenProposal } from '../context/Gov'; +import { utils } from 'ethers'; +import { forkedHreForBase } from '../../plugins/scenario/utils/hreForBase'; + +const EXCLUDED_ROOTS = ['comptrollerV2', 'comet', 'configurator', 'rewards', 'bulker', 'cometFactory']; + +const CCTP_DOMAIN_TO_NETWORK: Record = { + 0: 'mainnet', + 1: 'avalanche', + 2: 'optimism', + 3: 'arbitrum', + 6: 'base', + 7: 'polygon', +}; + +const ROOT_TO_NETWORK: Record = { + fxRoot: 'polygon', + arbitrumInbox: 'arbitrum', + arbitrumL1GatewayRouter: 'arbitrum', + baseL1CrossDomainMessenger: 'base', + baseL1StandardBridge: 'base', + baseL1USDSBridge: 'base', + opL1CrossDomainMessenger: 'optimism', + opL1StandardBridge: 'optimism', + mantleL1CrossDomainMessenger: 'mantle', + mantleL1StandardBridge: 'mantle', + unichainL1CrossDomainMessenger: 'unichain', + unichainL1StandardBridge: 'unichain', + scrollMessenger: 'scroll', + scrollL1USDCGateway: 'scroll', + lineaMessageService: 'linea', + lineaL1TokenBridge: 'linea', + lineaL1USDCBridge: 'linea', + l1CCIPRouter: 'ronin', + l1TokenAdminRegistry: 'ronin', + roninl1CCIPOnRamp: 'ronin', + roninl1NativeBridge: 'ronin', +}; + +function parseCCTPNetworks(openProposal: OpenProposal, cctpAddress: string): string[] { + const networks: string[] = []; + const cctpLower = cctpAddress.toLowerCase(); + + for (let i = 0; i < openProposal.targets.length; i++) { + if (openProposal.targets[i].toLowerCase() !== cctpLower) continue; + const sig = openProposal.signatures[i]; + if (!sig.startsWith('depositForBurn(')) continue; + + const calldata = openProposal.calldatas[i]; + // destinationDomain is the second parameter (uint32) in all depositForBurn variants + const decoded = utils.defaultAbiCoder.decode(['uint256', 'uint32'], utils.hexDataSlice(calldata, 0, 64)); + const domain = decoded[1]; + const network = CCTP_DOMAIN_TO_NETWORK[domain]; + if (network) networks.push(network); + } + return networks; +} + +export async function getProposalBridgeNetworks( + governanceDeploymentManager: DeploymentManager, + openProposal: OpenProposal +): Promise { + const roots = await getRoots(governanceDeploymentManager.cache); + const targets = openProposal.targets.map(t => t.toLowerCase()); + + const networks = new Set(); + for (const [alias, address] of roots) { + if (EXCLUDED_ROOTS.includes(alias)) continue; + + if (alias === 'CCTPTokenMessenger' && targets.includes(address.toLowerCase())) { + for (const net of parseCCTPNetworks(openProposal, address)) { + networks.add(net); + } + continue; + } + + const network = ROOT_TO_NETWORK[alias]; + if (network && targets.includes(address.toLowerCase())) { + networks.add(network); + } + } + return [...new Set(networks)]; +} + +const existingBridgeManagers: Record = {}; export async function isBridgeProposal( governanceDeploymentManager: DeploymentManager, bridgeDeploymentManager: DeploymentManager, openProposal: OpenProposal ) { - const bridgeNetwork = bridgeDeploymentManager.network; - console.log(`Checking if proposal ${openProposal.id} is a bridge proposal on ${bridgeNetwork}`); - switch (bridgeNetwork) { - case 'arbitrum': { - const inbox = await governanceDeploymentManager.getContractOrThrow('arbitrumInbox'); - const l1GatewayRouter = await governanceDeploymentManager.getContractOrThrow( - 'arbitrumL1GatewayRouter' - ); - const targets = openProposal.targets; - return targets.includes(inbox.address) || targets.includes(l1GatewayRouter.address); - } - case 'polygon': { - const { - fxRoot, - RootChainManager - } = await governanceDeploymentManager.getContracts(); - const bridgeAddresses = [fxRoot, RootChainManager] - .filter(x => x) - .map(x => x.address.toLowerCase()); - const targets = openProposal.targets; - return targets.some(t => bridgeAddresses.includes(t.toLowerCase())); - } - case 'base': { - const baseL1CrossDomainMessenger = await governanceDeploymentManager.getContractOrThrow( - 'baseL1CrossDomainMessenger' - ); - const baseL1StandardBridge = await governanceDeploymentManager.getContractOrThrow( - 'baseL1StandardBridge' - ); - const baseL1USDSBridge = await governanceDeploymentManager.getContractOrThrow( - 'baseL1USDSBridge' - ); - const targets = openProposal.targets; - const bridgeContracts = [baseL1CrossDomainMessenger.address, baseL1StandardBridge.address, baseL1USDSBridge.address]; - - return targets.some(t => bridgeContracts.includes(t)); - } - case 'linea': { - const lineaMessageService = await governanceDeploymentManager.getContractOrThrow( - 'lineaMessageService' - ); - const lineaL1USDCBridge = await governanceDeploymentManager.getContractOrThrow( - 'lineaL1USDCBridge' - ); - const lineaL1TokenBridge = await governanceDeploymentManager.getContractOrThrow( - 'lineaL1TokenBridge' - ); - const bridgeContracts = [ - lineaMessageService.address, - lineaL1USDCBridge.address, - lineaL1TokenBridge.address - ]; - const targets = openProposal.targets; - return targets.some(t => bridgeContracts.includes(t)); - } - // case 'linea': { - // const governor = await governanceDeploymentManager.getContractOrThrow('governor'); - // const lineaMessageService = await governanceDeploymentManager.getContractOrThrow( - // 'lineaMessageService' - // ); - // const { targets } = await governor.getActions(openProposal.id); - // return targets.includes(lineaMessageService.address); - // } - case 'optimism': { - const opL1CrossDomainMessenger = await governanceDeploymentManager.getContractOrThrow( - 'opL1CrossDomainMessenger' - ); - const opL1StandardBridge = await governanceDeploymentManager.getContractOrThrow( - 'opL1StandardBridge' - ); - const targets = openProposal.targets; - const bridgeContracts = [opL1CrossDomainMessenger.address, opL1StandardBridge.address]; - return targets.some(t => bridgeContracts.includes(t)); - } - case 'mantle': { - const mantleL1CrossDomainMessenger = await governanceDeploymentManager.getContractOrThrow( - 'mantleL1CrossDomainMessenger' - ); - const mantleL1StandardBridge = await governanceDeploymentManager.getContractOrThrow( - 'mantleL1StandardBridge' - ); - const targets = openProposal.targets; - const bridgeContracts = [ - mantleL1CrossDomainMessenger.address, - mantleL1StandardBridge.address - ]; - return targets.some(t => bridgeContracts.includes(t)); - } - case 'unichain': { - const unichainL1CrossDomainMessenger = await governanceDeploymentManager.getContractOrThrow( - 'unichainL1CrossDomainMessenger' - ); - const unichainL1StandardBridge = await governanceDeploymentManager.getContractOrThrow( - 'unichainL1StandardBridge' - ); - const targets = openProposal.targets; - const bridgeContracts = [ - unichainL1CrossDomainMessenger.address, - unichainL1StandardBridge.address - ]; - return targets.some(t => bridgeContracts.includes(t)); - } - case 'scroll': { - const scrollMessenger = await governanceDeploymentManager.getContractOrThrow( - 'scrollMessenger' - ); - const targets = openProposal.targets; - return targets.includes(scrollMessenger.address); + const bridgeNetworks = await getProposalBridgeNetworks(governanceDeploymentManager, openProposal); + const otherBridgeNetworks = bridgeNetworks.filter(n => n !== bridgeDeploymentManager.network); + const bridgeManagers = [bridgeDeploymentManager]; + if (!existingBridgeManagers[bridgeDeploymentManager.network]) { + existingBridgeManagers[bridgeDeploymentManager.network] = bridgeDeploymentManager; + } + if (!existingBridgeManagers[governanceDeploymentManager.network]) { + existingBridgeManagers[governanceDeploymentManager.network] = governanceDeploymentManager; + } + for(const bridgeNetwork of otherBridgeNetworks) { + if (existingBridgeManagers[bridgeNetwork]) { + bridgeManagers.push(existingBridgeManagers[bridgeNetwork]); + continue; } - case 'ronin': { - const governor = await governanceDeploymentManager.getContractOrThrow('governor'); - const l1CCIPRouter = await governanceDeploymentManager.getContractOrThrow( - 'l1CCIPRouter' - ); - const roninl1NativeBridge = await governanceDeploymentManager.getContractOrThrow( - 'roninl1NativeBridge' - ); - const roninL1OnRamp = await governanceDeploymentManager.getContractOrThrow( - 'roninl1CCIPOnRamp' - ); - const { targets } = await governor.proposalDetails(openProposal.id); - const bridgeContracts = [ - roninl1NativeBridge.address, - l1CCIPRouter.address, - roninL1OnRamp.address - ]; - return targets.some(t => bridgeContracts.includes(t)); + + let deploymentToken: string; + + let dm: DeploymentManager; + let existingBridgedDm: DeploymentManager | undefined; + for (const cachedDm of governanceDeploymentManager.bridgedDeploymentManagers.values()) { + if (cachedDm.network === bridgeNetwork) { + existingBridgedDm = cachedDm; + break; + } } - default: { - const tag = `[${bridgeNetwork} -> ${governanceDeploymentManager.network}]`; - throw new Error(`${tag} Unable to determine whether to relay Proposal ${openProposal.id}`); + + if (existingBridgedDm) { + dm = existingBridgedDm; + } else { + // default deployment token is USDC for all networks except Ronin (WETH) and Mantle (USDE) + switch (bridgeNetwork) { + case 'arbitrum': + case 'polygon': + case 'base': + case 'linea': + case 'optimism': + case 'unichain': + case 'scroll': + deploymentToken = 'usdc'; + break; + case 'mantle': + deploymentToken = 'usde'; + break; + case 'ronin': + deploymentToken = 'weth'; + break; + default: { + const tag = `[${governanceDeploymentManager.network} -> ${bridgeNetwork}]`; + throw new Error(`${tag} Unable to determine whether to relay Proposal ${openProposal.id}`); + } + } + + const hre = await forkedHreForBase({ name: '', network: bridgeNetwork, deployment: '' }); + dm = await governanceDeploymentManager.addBridgedDeploymentManager(bridgeNetwork, deploymentToken, hre); } + + existingBridgeManagers[bridgeNetwork] = dm; + bridgeManagers.push(dm); } + return bridgeManagers; } + diff --git a/scenario/utils/relayArbitrumMessage.ts b/scenario/utils/relayArbitrumMessage.ts index 550979448..3c19598a7 100644 --- a/scenario/utils/relayArbitrumMessage.ts +++ b/scenario/utils/relayArbitrumMessage.ts @@ -1,7 +1,7 @@ import { DeploymentManager } from '../../plugins/deployment_manager'; import { impersonateAddress } from '../../plugins/scenario/utils'; import { setNextBaseFeeToZero, setNextBlockTimestamp } from './hreUtils'; -import { utils, BigNumber } from 'ethers'; +import { utils, BigNumber, Contract, constants } from 'ethers'; import { Log } from '@ethersproject/abstract-provider'; import { sourceTokens } from '../../plugins/scenario/utils/TokenSourcer'; import { OpenBridgedProposal } from '../context/Gov'; @@ -84,18 +84,18 @@ export async function relayArbitrumMessage( const header = '0x'; const headerLength = header.length; const wordLength = 2 * 32; - const innnerData = header + data.slice(headerLength + (11 * wordLength)); + const innerData = header + data.slice(headerLength + (11 * wordLength)); const toValue = data.slice(headerLength + (2 * wordLength), headerLength + (3 * wordLength)); let toAddress = BigNumber.from(`0x${toValue}`).toHexString(); - // if lenght of toAddress is less than 42, then it is padded with 0s and we need to add them after 0x + // if length of toAddress is less than 42, then it is padded with 0s and we need to add them after 0x if(toAddress.length < 42) { toAddress = `0x${toAddress.slice(2).padStart(40, '0')}`; } const messageNum = topics[1]; return { - data: innnerData, + data: innerData, toAddress, messageNum }; @@ -232,6 +232,18 @@ export async function relayArbitrumMessage( await signer.getAddress() ); } else { + // Mock ArbSys precompile (0x64) — Arbitrum precompiles don't exist in Hardhat's EVM, + // but the L2 gateways call ArbSys.sendTxToL1 internally during outboundTransfer. + // Bytecode 0x60206000f3 disassembles to: PUSH1 0x20 | PUSH1 0x00 | RETURN + // which returns 32 zero bytes from uninitialized memory for any call. + await bridgeDeploymentManager.hre.network.provider.request({ + method: 'hardhat_setCode', + params: [ + '0x0000000000000000000000000000000000000064', + '0x60206000f3', + ], + }); + await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); } openBridgedProposals.push({ @@ -244,6 +256,189 @@ export async function relayArbitrumMessage( return openBridgedProposals; } +export async function simulateL2ToL1TokenBridging( + governanceDeploymentManager: DeploymentManager, + bridgeDeploymentManager: DeploymentManager, + tenderlyLogs?: any[], + proposalId?: BigNumber +) { + if(tenderlyLogs) { + return; + } + console.log('Simulating L2→L1 token bridging for any executed Arbitrum proposals...'); + + // L2 contracts + const bridgeReceiver = await bridgeDeploymentManager.getContractOrThrow('bridgeReceiver'); + + // Parse recent ProposalCreated events to find actions that bridge tokens from L2 to L1 + // ProposalCreated(address indexed rootMessageSender, uint256 id, address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, uint256 eta) + console.log('Fetching recent ProposalCreated events from BridgeReceiver...'); + const latestBlockNumber = await bridgeDeploymentManager.hre.ethers.provider.getBlockNumber(); + const proposalCreatedEvents = await bridgeDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: latestBlockNumber - 1000, // look back 1000 blocks for ProposalCreated events, which should be sufficient to cover any recent proposals given typical block times on Arbitrum + toBlock: 'latest', + address: bridgeReceiver.address, + topics: [utils.id('ProposalCreated(address,uint256,address[],uint256[],string[],bytes[],uint256)')] + }); + const outboundTransferSignature = 'outboundTransfer(address,address,uint256,bytes)'; + const outboundTransfer2Signature = 'outboundTransfer(address,address,uint256,uint256,uint256,bytes)'; + const depositForBurnSignature = 'depositForBurn(uint256,uint32,bytes32,address,bytes32,uint256,uint32)'; + const ARBITRUM_GATEWAY_ROUTER = '0x5288c571Fd7aD117beA99bF60FE0846C4E84F933'; + const ARBITRUM_BRIDGE = '0x8315177ab297ba92a06054ce80a67ed4dbd7ed3a'; + const ARBITRUM_OUTBOX = '0x667e23ABd27E623c11d4CC00ca3EC4d0bD63337a'; + const MAINNET_WETH = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'; + + for (const event of proposalCreatedEvents) { + const decodedEvent = bridgeReceiver.interface.parseLog(event); + const { id, targets, signatures, calldatas } = decodedEvent.args; + + if (proposalId && id.toString() !== proposalId.toString()) { + continue; + } + + for (let i = 0; i < signatures.length; i++) { + // Look for L2→L1 outboundTransfer calls (standard Arbitrum gateway bridge) + if (signatures[i] === outboundTransferSignature || signatures[i] === outboundTransfer2Signature) { + const [l1Token, to, amount] = (() => { + if (signatures[i] === outboundTransferSignature) { + return utils.defaultAbiCoder.decode( + ['address', 'address', 'uint256', 'bytes'], + calldatas[i] + ); + } else if (signatures[i] === outboundTransfer2Signature) { + return utils.defaultAbiCoder.decode( + ['address', 'address', 'uint256', 'uint256', 'uint256', 'bytes'], + calldatas[i] + ); + } + })(); + console.log(`Simulating L2→L1 token bridging: ${amount.toString()} of ${l1Token} to ${to}`); + + const gatewayAddress = await (async () => { + if(targets[i].toLowerCase() === ARBITRUM_GATEWAY_ROUTER.toLowerCase()) { // Arbitrum WETH gateway + const router = new Contract( + ARBITRUM_GATEWAY_ROUTER, + ['function l1TokenToGateway(address l1Token) view returns (address)'], + await governanceDeploymentManager.getSigner() + ); + return await router.l1TokenToGateway(l1Token); + } + return targets[i]; + })(); + const l2Gateway = new Contract( + gatewayAddress, + ['function counterpartGateway() view returns (address)'], + await bridgeDeploymentManager.getSigner() + ); + const l1GatewayAddress = await l2Gateway.counterpartGateway(); + + const l1Gateway = new Contract( + l1GatewayAddress, + [ + 'function finalizeInboundTransfer(address _token, address _from, address _to, uint256 _amount, bytes calldata _data)', + 'function inbox() view returns (address)' + ], + await governanceDeploymentManager.getSigner() + ); + // override 0x4 slot in outbox to L2 gateway + await governanceDeploymentManager.hre.network.provider.send('hardhat_setStorageAt', [ + ARBITRUM_OUTBOX, + '0x4', + utils.hexZeroPad(gatewayAddress, 32) + ]); + + // impersonate outbox to call finalizeInboundTransfer, as if the message came from L2 gateway + const outboxSigner = await impersonateAddress( + governanceDeploymentManager, + ARBITRUM_OUTBOX + ); + + await governanceDeploymentManager.hre.network.provider.send('hardhat_setBalance', [ + outboxSigner.address, + '0x1000000000000000000', + ]); + + const arbitrumBridge = new Contract( + ARBITRUM_BRIDGE, + ['function executeCall(address to, uint256 value, bytes calldata data)'], + outboxSigner + ); + + const data = l1Gateway.interface.encodeFunctionData( + 'finalizeInboundTransfer', + [ + l1Token, + ARBITRUM_GATEWAY_ROUTER, + to, amount, + utils.defaultAbiCoder.encode(['uint256', 'bytes'], [0, '0x']) + ]); + console.log(`Relaying message to L1 gateway at ${l1GatewayAddress} with data: ${data}`); + const bridgeTx = await arbitrumBridge.connect(outboxSigner).executeCall( + l1Gateway.address, + l1Token.toLowerCase() === MAINNET_WETH.toLowerCase() ? amount : 0, + data, + ); + await (bridgeTx).wait(); + // stop impersonation after the call + await governanceDeploymentManager.hre.network.provider.send('hardhat_stopImpersonatingAccount', [ + outboxSigner.address + ]); + // override 0x4 slot in outbox to L2 gateway + await governanceDeploymentManager.hre.network.provider.send('hardhat_setStorageAt', [ + ARBITRUM_OUTBOX, + '0x4', + utils.hexZeroPad(constants.AddressZero, 32) + ]); + } + + // Look for L2→L1 CCTP depositForBurn calls (Circle CCTP bridge, e.g. native USDC) + if (signatures[i] === depositForBurnSignature) { + const [amount, , mintRecipientBytes32, burnToken] = utils.defaultAbiCoder.decode( + ['uint256', 'uint32', 'bytes32', 'address', 'bytes32', 'uint256', 'uint32'], + calldatas[i] + ); + + const mintRecipient = utils.getAddress('0x' + utils.hexlify(mintRecipientBytes32).slice(-40)); + + try { + // L2 + const l2CCTPTokenMessenger = await bridgeDeploymentManager.getContractOrThrow('CCTPMessageTransmitter'); + // Resolve L1 token via CCTP TokenMinter: burnToken (L2) → localToken (L1) + const l1CCTPTokenMessenger = await governanceDeploymentManager.getContractOrThrow('CCTPTokenMessenger'); + const tokenMinterAddress = await l1CCTPTokenMessenger.localMinter(); + const L1TokenMinter = new Contract( + tokenMinterAddress, + ['function mint(uint32 sourceDomain, bytes32 burnToken, address recipientOne, address recipientTwo, uint256 amountOne, uint256 amountTwo) returns (address)'], + await governanceDeploymentManager.getSigner() + ); + const l1CCTPTokenMessengerSigner = await impersonateAddress( + governanceDeploymentManager, + l1CCTPTokenMessenger.address + ); + await governanceDeploymentManager.hre.network.provider.send('hardhat_setBalance', [ + l1CCTPTokenMessengerSigner.address, + '0x1000000000000000000', + ]); + const sourceDomain = await l2CCTPTokenMessenger.localDomain(); + const mintTx = await L1TokenMinter.connect(l1CCTPTokenMessengerSigner).mint( + sourceDomain, + utils.hexZeroPad(burnToken, 32), + mintRecipient, + L1TokenMinter.address, // mint to the token minter first, since some tokens (e.g. USDC) have a cap on max amount per mint, and the token minter can then transfer to the recipient + amount, + 1 + ); + console.log('Simulated CCTP mint transaction:', mintTx.hash); + await mintTx.wait(); + } catch (e) { + console.log(`Warning: Could not simulate CCTP L2→L1 bridging for depositForBurn: ${e.message}`); + } + } + await governanceDeploymentManager.hre.network.provider.send('evm_mine'); + } + } +} + export async function relayArbitrumCCTPMint( governanceDeploymentManager: DeploymentManager, bridgeDeploymentManager: DeploymentManager, diff --git a/scenario/utils/relayBaseMessage.ts b/scenario/utils/relayBaseMessage.ts index 1e5418c11..1c6491a8e 100644 --- a/scenario/utils/relayBaseMessage.ts +++ b/scenario/utils/relayBaseMessage.ts @@ -1,7 +1,7 @@ import { DeploymentManager } from '../../plugins/deployment_manager'; import { impersonateAddress } from '../../plugins/scenario/utils'; import { setNextBaseFeeToZero, setNextBlockTimestamp } from './hreUtils'; -import { BigNumber, ethers } from 'ethers'; +import { BigNumber, ethers, utils } from 'ethers'; import { Log } from '@ethersproject/abstract-provider'; import { OpenBridgedProposal } from '../context/Gov'; import { applyL1ToL2Alias, isTenderlyLog } from './index'; @@ -142,7 +142,7 @@ export default async function relayBaseMessage( } } else if (target === bridgeReceiver.address) { // Cross-chain message passing - if (!tenderlyLogs && relayMessageTxn) { + if (relayMessageTxn) { const proposalCreatedEvent = relayMessageTxn.events.find( (event) => event.address === bridgeReceiver.address ); @@ -154,28 +154,9 @@ export default async function relayBaseMessage( openBridgedProposals.push({ id, eta }); } } else { - throw new Error( - `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message` - ); - } - } - - // Handle proposal creation for tenderly - if (tenderlyLogs) { - // We need to check for ProposalCreated events since we don't get them in the loop above - const proposalFilter = bridgeReceiver.filters.ProposalCreated(); - const proposalEvents = await bridgeDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: 'latest', - toBlock: 'latest', - address: bridgeReceiver.address, - topics: proposalFilter.topics - }); - - for (let event of proposalEvents) { - const { - args: { id, eta }, - } = bridgeReceiver.interface.parseLog(event); - openBridgedProposals.push({ id, eta }); + // throw error only on last relay message and no proposal created event found + if(sentMessageEvents.indexOf(sentMessageEvent) === sentMessageEvents.length - 1 && openBridgedProposals.length === 0) + throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); } } @@ -207,4 +188,94 @@ export default async function relayBaseMessage( } return openBridgedProposals; -} \ No newline at end of file +} + +export async function simulateL2ToL1TokenBridging( + governanceDeploymentManager: DeploymentManager, + bridgeDeploymentManager: DeploymentManager, + tenderlyLogs?: any[] +) { + if(tenderlyLogs) { + return; + } + console.log('Simulating L2→L1 token bridging for any executed Base proposals...'); + + // L2 contracts + const bridgeReceiver = await bridgeDeploymentManager.getContractOrThrow('bridgeReceiver'); + const baseL2Bridge = await bridgeDeploymentManager.getContractOrThrow('l2StandardBridge'); + const l2CrossDomainMessenger = await bridgeDeploymentManager.getContractOrThrow('l2CrossDomainMessenger'); + + // L1 contracts + const baseL1CrossDomainMessenger = await governanceDeploymentManager.getContractOrThrow('baseL1CrossDomainMessenger'); + const baseL1Bridge = await governanceDeploymentManager.getContractOrThrow('baseL1StandardBridge'); + const BASE_L1_PORTAL = '0x49048044D57e1C92A77f79988d21Fa8fAF74E97e'; + + // Parse recent ProposalCreated events to find actions that bridge tokens from L2 to L1 + // ProposalCreated(address indexed rootMessageSender, uint256 id, address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, uint256 eta) + console.log('Fetching recent ProposalCreated events from BridgeReceiver...'); + const latestBlockNumber = await bridgeDeploymentManager.hre.ethers.provider.getBlockNumber(); + const proposalCreatedEvents = await bridgeDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: latestBlockNumber - 1000, // look back 1000 blocks for ProposalCreated events, which should be sufficient to cover any recent proposals given typical block times on Base + toBlock: 'latest', + address: bridgeReceiver.address, + topics: [utils.id('ProposalCreated(address,uint256,address[],uint256[],string[],bytes[],uint256)')] + }); + + const bridgeERC20ToSignature = 'bridgeERC20To(address,address,address,uint256,uint32,bytes)'; + + for (const event of proposalCreatedEvents) { + const decodedEvent = bridgeReceiver.interface.parseLog(event); + const { signatures, calldatas } = decodedEvent.args; + + + for (let i = 0; i < signatures.length; i++) { + if (signatures[i] === bridgeERC20ToSignature) { + const [localToken, remoteToken, to, amount, , extraData] = utils.defaultAbiCoder.decode( + ['address', 'address', 'address', 'uint256', 'uint32', 'bytes'], + calldatas[i] + ); + + console.log(`Simulating L2→L1 bridgeERC20To: ${amount.toString()} of ${remoteToken} to ${to}`); + + console.log('Setting up L1 state to simulate finalizeBridgeERC20...'); + console.log('Base L1 Portal address:', BASE_L1_PORTAL); + console.log('Overriding slot', utils.hexZeroPad('0x32', 32)); + console.log('l2CrossDomainMessenger:', utils.hexZeroPad(l2CrossDomainMessenger.address, 32)); + await governanceDeploymentManager.hre.network.provider.send('hardhat_setStorageAt', [ + BASE_L1_PORTAL, + utils.hexZeroPad('0x32', 32), + utils.hexZeroPad(l2CrossDomainMessenger.address, 32) + ]); + + await governanceDeploymentManager.hre.network.provider.send('hardhat_setStorageAt', [ + baseL1CrossDomainMessenger.address, + '0xcc', + utils.hexZeroPad(baseL2Bridge.address, 32) + ]); + + const domainMessengerSigner = await impersonateAddress( + governanceDeploymentManager, + baseL1CrossDomainMessenger.address + ); + + await governanceDeploymentManager.hre.network.provider.send('hardhat_setBalance', [ + domainMessengerSigner.address, + ethers.utils.hexStripZeros(ethers.utils.parseEther('1').toHexString()), + ]); + + await ( + await baseL1Bridge.connect(domainMessengerSigner).finalizeBridgeERC20( + remoteToken, localToken, bridgeReceiver.address, to, amount, extraData, + { gasPrice: 0, gasLimit: 2_500_000 } + ) + ).wait(); + + await governanceDeploymentManager.hre.network.provider.send('hardhat_setStorageAt', [ + BASE_L1_PORTAL, + utils.hexZeroPad('0x32', 32), + utils.hexZeroPad('0xdead', 32) + ]); + } + } + } +} diff --git a/scenario/utils/relayLineaMessage.ts b/scenario/utils/relayLineaMessage.ts index 78f2b0f14..0f3986550 100644 --- a/scenario/utils/relayLineaMessage.ts +++ b/scenario/utils/relayLineaMessage.ts @@ -6,7 +6,7 @@ import { OpenBridgedProposal } from '../context/Gov'; import { impersonateAddress } from '../../plugins/scenario/utils'; import { isTenderlyLog } from './index'; -const LINEA_SETTER_ROLE_ACCOUNT = '0xc1C6B09D1eB6fCA0fF3cA11027E5Bc4AeDb47F67'; +const LINEA_SETTER_ROLE_ACCOUNT = '0x2b0F9C76970975aec03784EFd763623757EF7652'; export default async function relayLineaMessage( governanceDeploymentManager: DeploymentManager, @@ -245,9 +245,9 @@ export default async function relayLineaMessage( // Add the proposal to the list of open bridged proposals to be executed after all the messages have been relayed openBridgedProposals.push({ id, eta }); } else { - throw new Error( - `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message` - ); + // throw error only on last relay message and no proposal created event found + if(messageSentEvents.indexOf(messageSentEvent) === messageSentEvents.length - 1 && openBridgedProposals.length === 0) + throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); } } @@ -276,6 +276,7 @@ export default async function relayLineaMessage( `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Executed bridged proposal ${id}` ); } + return openBridgedProposals; } diff --git a/scenario/utils/relayMantleMessage.ts b/scenario/utils/relayMantleMessage.ts index 812255b75..c052e0184 100644 --- a/scenario/utils/relayMantleMessage.ts +++ b/scenario/utils/relayMantleMessage.ts @@ -127,7 +127,9 @@ export default async function relayMantleMessage( // Add the proposal to the list of open bridged proposals to be executed after all the messages have been relayed openBridgedProposals.push({ id, eta }); } else { - throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); + // throw error only on last relay message and no proposal created event found + if(sentMessageEvents.indexOf(sentMessageEvent) === sentMessageEvents.length - 1 && openBridgedProposals.length === 0) + throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); } } @@ -158,5 +160,6 @@ export default async function relayMantleMessage( `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Executed bridged proposal ${id}` ); } + return openBridgedProposals; } diff --git a/scenario/utils/relayMessage.ts b/scenario/utils/relayMessage.ts index fa0523665..ac94cb1ae 100644 --- a/scenario/utils/relayMessage.ts +++ b/scenario/utils/relayMessage.ts @@ -1,9 +1,9 @@ import { DeploymentManager } from '../../plugins/deployment_manager'; import relayPolygonMessage from './relayPolygonMessage'; -import { relayArbitrumMessage, relayArbitrumCCTPMint } from './relayArbitrumMessage'; -import relayBaseMessage from './relayBaseMessage'; +import { relayArbitrumMessage, relayArbitrumCCTPMint, simulateL2ToL1TokenBridging } from './relayArbitrumMessage'; +import relayBaseMessage,{ simulateL2ToL1TokenBridging as simulateBaseL2ToL1TokenBridging} from './relayBaseMessage'; import relayLineaMessage from './relayLineaMessage'; -import relayOptimismMessage from './relayOptimismMessage'; +import relayOptimismMessage, { simulateL2ToL1TokenBridging as simulateOptimismL2ToL1TokenBridging } from './relayOptimismMessage'; import relayMantleMessage from './relayMantleMessage'; import { relayUnichainMessage, relayUnichainCCTPMint } from './relayUnichainMessage'; import relayScrollMessage from './relayScrollMessage'; @@ -16,23 +16,36 @@ export default async function relayMessage( tenderlyLogs?: any[] ) { const bridgeNetwork = bridgeDeploymentManager.network; + if(bridgeNetwork === governanceDeploymentManager.network) return; // no need to relay if the proposal is on the same network console.log(`Relaying messages from ${governanceDeploymentManager.network} -> ${bridgeNetwork}`); let proposal; switch (bridgeNetwork) { case 'base': - return await relayBaseMessage( + proposal = await relayBaseMessage( governanceDeploymentManager, bridgeDeploymentManager, startingBlockNumber, tenderlyLogs ); + await simulateBaseL2ToL1TokenBridging( + governanceDeploymentManager, + bridgeDeploymentManager, + tenderlyLogs + ); + return proposal; case 'optimism': - return await relayOptimismMessage( + proposal = await relayOptimismMessage( governanceDeploymentManager, bridgeDeploymentManager, startingBlockNumber, tenderlyLogs ); + await simulateOptimismL2ToL1TokenBridging( + governanceDeploymentManager, + bridgeDeploymentManager, + tenderlyLogs + ); + return proposal; case 'mantle': return await relayMantleMessage( governanceDeploymentManager, @@ -74,6 +87,11 @@ export default async function relayMessage( startingBlockNumber, tenderlyLogs ); + await simulateL2ToL1TokenBridging( + governanceDeploymentManager, + bridgeDeploymentManager, + tenderlyLogs + ); return proposal; case 'linea': return await relayLineaMessage( diff --git a/scenario/utils/relayOptimismMessage.ts b/scenario/utils/relayOptimismMessage.ts index 5ce1d076d..695ed040a 100644 --- a/scenario/utils/relayOptimismMessage.ts +++ b/scenario/utils/relayOptimismMessage.ts @@ -1,7 +1,7 @@ import { DeploymentManager } from '../../plugins/deployment_manager'; import { impersonateAddress } from '../../plugins/scenario/utils'; import { setNextBaseFeeToZero, setNextBlockTimestamp } from './hreUtils'; -import { BigNumber, ethers } from 'ethers'; +import { BigNumber, ethers, utils, Contract } from 'ethers'; import { Log } from '@ethersproject/abstract-provider'; import { OpenBridgedProposal } from '../context/Gov'; import { applyL1ToL2Alias, isTenderlyLog } from './index'; @@ -144,35 +144,169 @@ export default async function relayOptimismMessage( throw e; } } else { - throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); + // throw error only on last relay message and no proposal created event found + if(sentMessageEvents.indexOf(sentMessageEvent) === sentMessageEvents.length - 1 && openBridgedProposals.length === 0) + throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); } + } - // Execute open bridged proposals now that all messages have been bridged - for (let proposal of openBridgedProposals) { - const { eta, id } = proposal; - // Fast forward l2 time - await setNextBlockTimestamp(bridgeDeploymentManager, eta.toNumber() + 1); + // Execute open bridged proposals now that all messages have been bridged + for (let proposal of openBridgedProposals) { + const { eta, id } = proposal; + // Fast forward l2 time + await setNextBlockTimestamp(bridgeDeploymentManager, eta.toNumber() + 1); - // Execute queued proposal - await setNextBaseFeeToZero(bridgeDeploymentManager); + // Execute queued proposal + await setNextBaseFeeToZero(bridgeDeploymentManager); - if (tenderlyLogs) { - const callData = bridgeReceiver.interface.encodeFunctionData('executeProposal', [id]); - const signer = await bridgeDeploymentManager.getSigner(); + if (tenderlyLogs) { + const callData = bridgeReceiver.interface.encodeFunctionData('executeProposal', [id]); + const signer = await bridgeDeploymentManager.getSigner(); - bridgeDeploymentManager.stashRelayMessage( - bridgeReceiver.address, - callData, - signer.address - ); - } else { - await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); - } - console.log( - `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Executed bridged proposal ${id}` + bridgeDeploymentManager.stashRelayMessage( + bridgeReceiver.address, + callData, + signer.address ); + } else { + await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); } + console.log( + `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Executed bridged proposal ${id}` + ); + } + + return openBridgedProposals; +} + +export async function simulateL2ToL1TokenBridging( + governanceDeploymentManager: DeploymentManager, + bridgeDeploymentManager: DeploymentManager, + tenderlyLogs?: any[] +) { + if(tenderlyLogs) { + return; + } + console.log('Simulating L2→L1 token bridging for any executed Optimism proposals...'); + + // L2 contracts + const bridgeReceiver = await bridgeDeploymentManager.getContractOrThrow('bridgeReceiver'); + const optimismL2Bridge = await bridgeDeploymentManager.getContractOrThrow('l2StandardBridge'); + const l2CrossDomainMessenger = await bridgeDeploymentManager.getContractOrThrow('l2CrossDomainMessenger'); + + // L1 contracts + const opL1CrossDomainMessenger = await governanceDeploymentManager.getContractOrThrow('opL1CrossDomainMessenger'); + const optimismL1Bridge = await governanceDeploymentManager.getContractOrThrow('opL1StandardBridge'); + const OPTIMISM_L1_PORTAL = '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed'; - return openBridgedProposals; + // Parse recent ProposalCreated events to find actions that bridge tokens from L2 to L1 + // ProposalCreated(address indexed rootMessageSender, uint256 id, address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, uint256 eta) + console.log('Fetching recent ProposalCreated events from BridgeReceiver...'); + const latestBlockNumber = await bridgeDeploymentManager.hre.ethers.provider.getBlockNumber(); + const proposalCreatedEvents = await bridgeDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: latestBlockNumber - 1000, // look back 1000 blocks for ProposalCreated events, which should be sufficient to cover any recent proposals given typical block times on Optimism + toBlock: 'latest', + address: bridgeReceiver.address, + topics: [utils.id('ProposalCreated(address,uint256,address[],uint256[],string[],bytes[],uint256)')] + }); + + const bridgeERC20ToSignature = 'bridgeERC20To(address,address,address,uint256,uint32,bytes)'; + const depositForBurnSignature = 'depositForBurn(uint256,uint32,bytes32,address,bytes32,uint256,uint32)'; + + for (const event of proposalCreatedEvents) { + const decodedEvent = bridgeReceiver.interface.parseLog(event); + const { signatures, calldatas } = decodedEvent.args; + + for (let i = 0; i < signatures.length; i++) { + if (signatures[i] === bridgeERC20ToSignature) { + const [localToken, remoteToken, to, amount, , extraData] = utils.defaultAbiCoder.decode( + ['address', 'address', 'address', 'uint256', 'uint32', 'bytes'], + calldatas[i] + ); + + console.log(`Simulating L2→L1 bridgeERC20To: ${amount.toString()} of ${remoteToken} to ${to}`); + + console.log('Setting up L1 state to simulate finalizeBridgeERC20...'); + console.log('Optimism L1 Portal address:', OPTIMISM_L1_PORTAL); + console.log('Overriding slot', utils.hexZeroPad('0x32', 32)); + console.log('l2CrossDomainMessenger:', utils.hexZeroPad(l2CrossDomainMessenger.address, 32)); + await governanceDeploymentManager.hre.network.provider.send('hardhat_setStorageAt', [ + OPTIMISM_L1_PORTAL, + utils.hexZeroPad('0x32', 32), + utils.hexZeroPad(l2CrossDomainMessenger.address, 32) + ]); + + await governanceDeploymentManager.hre.network.provider.send('hardhat_setStorageAt', [ + opL1CrossDomainMessenger.address, + '0xcc', + utils.hexZeroPad(optimismL2Bridge.address, 32) + ]); + + const domainMessengerSigner = await impersonateAddress( + governanceDeploymentManager, + opL1CrossDomainMessenger.address + ); + await governanceDeploymentManager.hre.network.provider.send('hardhat_setBalance', [ + domainMessengerSigner.address, + ethers.utils.hexStripZeros(ethers.utils.parseEther('1').toHexString()), + ]); + + await ( + await optimismL1Bridge.connect(domainMessengerSigner).finalizeBridgeERC20( + remoteToken, localToken, bridgeReceiver.address, to, amount, extraData, + { gasPrice: 0, gasLimit: 2_500_000 } + ) + ).wait(); + await governanceDeploymentManager.hre.network.provider.send('hardhat_setStorageAt', [ + OPTIMISM_L1_PORTAL, + utils.hexZeroPad('0x32', 32), + utils.hexZeroPad('0xdead', 32) + ]); + } + + // Look for L2→L1 CCTP depositForBurn calls (Circle CCTP bridge, e.g. native USDC) + if (signatures[i] === depositForBurnSignature) { + const [amount, , mintRecipientBytes32, burnToken] = utils.defaultAbiCoder.decode( + ['uint256', 'uint32', 'bytes32', 'address', 'bytes32', 'uint256', 'uint32'], + calldatas[i] + ); + + const mintRecipient = utils.getAddress('0x' + utils.hexlify(mintRecipientBytes32).slice(-40)); + + try { + // L2 + const l2CCTPTokenMessenger = await bridgeDeploymentManager.getContractOrThrow('CCTPMessageTransmitter'); + // Resolve L1 token via CCTP TokenMinter: burnToken (L2) → localToken (L1) + const l1CCTPTokenMessenger = await governanceDeploymentManager.getContractOrThrow('CCTPTokenMessenger'); + const tokenMinterAddress = await l1CCTPTokenMessenger.localMinter(); + const L1TokenMinter = new Contract( + tokenMinterAddress, + ['function mint(uint32 sourceDomain, bytes32 burnToken, address recipientOne, address recipientTwo, uint256 amountOne, uint256 amountTwo) returns (address)'], + await governanceDeploymentManager.getSigner() + ); + const l1CCTPTokenMessengerSigner = await impersonateAddress( + governanceDeploymentManager, + l1CCTPTokenMessenger.address + ); + await governanceDeploymentManager.hre.network.provider.send('hardhat_setBalance', [ + l1CCTPTokenMessengerSigner.address, + '0x1000000000000000000', + ]); + const sourceDomain = await l2CCTPTokenMessenger.localDomain(); + const mintTx = await L1TokenMinter.connect(l1CCTPTokenMessengerSigner).mint( + sourceDomain, + utils.hexZeroPad(burnToken, 32), + mintRecipient, + L1TokenMinter.address, // mint to the token minter first, since some tokens (e.g. USDC) have a cap on max amount per mint, and the token minter can then transfer to the recipient + amount, + 1 + ); + console.log('Simulated CCTP mint transaction:', mintTx.hash); + await mintTx.wait(); + } catch (e) { + console.log(`Warning: Could not simulate CCTP L2→L1 bridging for depositForBurn: ${e.message}`); + } + } + } } } diff --git a/scenario/utils/relayScrollMessage.ts b/scenario/utils/relayScrollMessage.ts index 686658cd0..3d6b5b7bf 100644 --- a/scenario/utils/relayScrollMessage.ts +++ b/scenario/utils/relayScrollMessage.ts @@ -167,7 +167,9 @@ export default async function relayScrollMessage( // Add the proposal to the list of open bridged proposals to be executed after all the messages have been relayed openBridgedProposals.push({ id, eta }); } else { - throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); + // throw error only on last relay message and no proposal created event found + if(messageSentEvents.indexOf(messageSentEvent) === messageSentEvents.length - 1 && openBridgedProposals.length === 0) + throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); } } diff --git a/scenario/utils/relayUnichainMessage.ts b/scenario/utils/relayUnichainMessage.ts index 5b3db9b5b..5f49b9773 100644 --- a/scenario/utils/relayUnichainMessage.ts +++ b/scenario/utils/relayUnichainMessage.ts @@ -124,7 +124,7 @@ export async function relayUnichainMessage( } } else if (target === bridgeReceiver.address) { // Cross-chain message passing - if (!tenderlyLogs && relayMessageTxn) { + if (relayMessageTxn) { const proposalCreatedEvent = relayMessageTxn.events.find(event => event.address === bridgeReceiver.address); const { args: { id, eta } } = bridgeReceiver.interface.parseLog(proposalCreatedEvent); @@ -132,26 +132,9 @@ export async function relayUnichainMessage( openBridgedProposals.push({ id, eta }); } } else { - throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); - } - } - - // Handle proposal creation for tenderly - if (tenderlyLogs) { - // We need to check for ProposalCreated events since we don't get them in the loop above - const proposalFilter = bridgeReceiver.filters.ProposalCreated(); - const proposalEvents = await bridgeDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: 'latest', - toBlock: 'latest', - address: bridgeReceiver.address, - topics: proposalFilter.topics - }); - - for (let event of proposalEvents) { - const { - args: { id, eta }, - } = bridgeReceiver.interface.parseLog(event); - openBridgedProposals.push({ id, eta }); + // throw error only on last relay message and no proposal created event found + if(sentMessageEvents.indexOf(sentMessageEvent) === sentMessageEvents.length - 1 && openBridgedProposals.length === 0) + throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); } } diff --git a/scenario/utils/scenarioHelper.ts b/scenario/utils/scenarioHelper.ts index e8d64fa40..2dd22e823 100644 --- a/scenario/utils/scenarioHelper.ts +++ b/scenario/utils/scenarioHelper.ts @@ -217,7 +217,14 @@ export function getConfigForScenario(ctx: CometContext, i?: number) { if (ctx.world.base.network === 'scroll' && ctx.world.base.deployment === 'usdc') { config.bulkerAsset = 200; - config.bulkerAsset1 = 200; + config.bulkerAsset1 = 50; + config.liquidationBase = 1000; + config.liquidationAsset = 2; + if(i == 1) { // tBTC + config.supplyCollateral = 10; + config.transferCollateral = 10; + config.withdrawCollateral = 10; + } } if (ctx.world.base.network === 'sepolia' && ctx.world.base.deployment === 'usdc') { @@ -233,8 +240,8 @@ export function getConfigForScenario(ctx: CometContext, i?: number) { } if (ctx.world.base.network === 'linea' && ctx.world.base.deployment === 'usdc') { - config.bulkerAsset = 500; - config.bulkerAsset1 = 500; + config.bulkerAsset = 10; + config.bulkerAsset1 = 15; config.supplyCollateral = 10; config.transferCollateral = 10; config.withdrawCollateral = 10; diff --git a/src/deploy/index.ts b/src/deploy/index.ts index 92559e8c5..8d2ea4953 100644 --- a/src/deploy/index.ts +++ b/src/deploy/index.ts @@ -113,6 +113,7 @@ export const WHALES = { '0x9152e9C04e8fE8373EDaa8f5841E25d4015658B7', // pumpBTC whale '0xd4Cc9b31e9eF33E392FF2f81AD52BE8523e0993b', // pumpBTC whale '0x65906988ADEe75306021C417a1A3458040239602', // LBTC whale + '0xF469fBD2abcd6B9de8E169d128226C0Fc90a012e', // wbtc whale '0x7667095Caa12b79fCa489ff6E2198Ca01fDAe057', ], polygon: [ @@ -148,6 +149,8 @@ export const WHALES = { '0x186cF879186986A20aADFb7eAD50e3C20cb26CeC', // tBTC whale '0x620Fe90b1EAcaEa936ea199e7B05F998CA65836a', // tBTC whale '0x54b5569deC8A6A8AE61A36Fd34e5c8945810db8b', // tBTC whale + '0xd98Be00b5D27fc98112BdE293e487f8D4cA57d07', // tBTC whale + '0x68863dDE14303BcED249cA8ec6AF85d4694dea6A', // tBTC whale '0xDBD974Eb5360d053ea0c56B4DaCF4A9D3E894Ee2', // tETH whale '0xbA1333333333a1BA1108E8412f11850A5C319bA9', // tETH whale '0xEA1132120ddcDDA2F119e99Fa7A27a0d036F7Ac9', // ezETH whale @@ -155,6 +158,9 @@ export const WHALES = { base: [ '0x6D3c5a4a7aC4B1428368310E4EC3bB1350d01455', // USDbC whale '0x46e6b214b524310239732D51387075E0e70970bf', // ezETH whale + '0xDD5745756C2de109183c6B5bB886F9207bEF114D', // ezETH whale + '0x7c468017FA704A1Cca3aa3d075eC21018FAd5E72', // ezETH whale + '0x6e01Eb6BbEd4407deA78EBF532055B04d0d08f0F', // ezETH whale '0x07CFA5Df24fB17486AF0CBf6C910F24253a674D3', // cbETH whale TODO: need to update this whale, not enough '0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb', // cbETH whale '0x3bf93770f2d4a794c3d9EBEfBAeBAE2a8f09A5E5', // cbETH whale @@ -162,10 +168,16 @@ export const WHALES = { '0xb125E6687d4313864e53df431d5425969c15Eb2F', // cbETH whale '0x1539A4611f16a139891c14365Cab86599F3A8AFC', // tBTC whale '0x0a1d576f3eFeF75b330424287a95A366e8281D54', // USDbC whale + '0x98c7A2338336d2d354663246F64676009c7bDa97', // USDbC whale + '0x0E635F8EeED4F7279d56692D552F034ECE136019', // USDbC whale + '0x58Ee32056D946a37f5b49582dE3dEE1dAc0Bb974', // USDbC whale + '0x80a94C36747CF51b2FbabDfF045f6D22c1930eD1', // wrsETH whale ], scroll: [ '0xaaaaAAAACB71BF2C8CaE522EA5fa455571A74106', // USDC whale '0x5B1322eeb46240b02e20062b8F0F9908d525B09c', // wstETH whale + '0x7fA3dC8729b7D56dC36651D01aB4a27e882fDCF1', // wstETH whale + `0xf610A9dfB7C89644979b4A0f27063E9e7d7Cda32`, // wstETH whale ], optimism: [ '0x2A82Ae142b2e62Cb7D10b55E323ACB1Cab663a26', // OP whale @@ -175,6 +187,18 @@ export const WHALES = { '0xc45A479877e1e9Dfe9FcD4056c699575a1045dAA', // wstETH whale '0x6e57181D6b4b7c138a6F956AD16DAF4f27FC5E04', // COMP whale '0xE36A30D249f7761327fd973001A32010b521b6Fd', // ezETH whale + '0xb40DA71c49c745Dd3ab801882b1D410760541678', // ezETH whale + '0x540B1E0D69244057cD0Da2AF4Bca87dA87A824bE', // ezETH whale + '0x12ee4BE944b993C81b6840e088bA1dCc57F07B1D', // ezETH whale + '0x87711795890ea632E3c8851F6B47BA1c6b2CF0Ee', // ezETH whale + '0xE36A30D249f7761327fd973001A32010b521b6Fd', // weETH whale + '0xb2cFb909e8657C0EC44D3dD898C1053b87804755', // weETH whale + '0xb8051464C8c92209C92F3a4CD9C73746C4c3CFb3', // weETH whale + '0x2478d48B8a5Dd0A9876a12858C917D556EB93811', // weETH whale + '0xE36A30D249f7761327fd973001A32010b521b6Fd', // wrsETH whale + '0x181bA797ccF779D8aB339721ED6ee827E758668e', // wrsETH whale + '0xbA1333333333a1BA1108E8412f11850A5C319bA9', // wrsETH whale + '0x44ed9cE901B367B1EF9DDBD4974C82A514c50DEc', // wrsETH whale ], mantle: [ '0x588846213A30fd36244e0ae0eBB2374516dA836C', // USDe whale diff --git a/tasks/deployment_manager/task.ts b/tasks/deployment_manager/task.ts index d4378cb64..47bfc06c7 100644 --- a/tasks/deployment_manager/task.ts +++ b/tasks/deployment_manager/task.ts @@ -4,7 +4,7 @@ import { writeEnacted } from '../../plugins/deployment_manager/Enacted'; import { HardhatRuntimeEnvironment, HardhatConfig } from 'hardhat/types'; import { DeploymentManager, VerifyArgs } from '../../plugins/deployment_manager'; import { impersonateAddress } from '../../plugins/scenario/utils'; -import hreForBase from '../../plugins/scenario/utils/hreForBase'; +import hreForBase, { migrationStarted} from '../../plugins/scenario/utils/hreForBase'; // TODO: Don't depend on scenario's hreForBase async function getForkEnv(env: HardhatRuntimeEnvironment, deployment: string): Promise { @@ -248,6 +248,7 @@ task('migrate', 'Runs migration') governanceDm = dm; } + migrationStarted(); if (impersonate && !simulate) { throw new Error('Cannot impersonate an address if not simulating a migration. Please specify --simulate to simulate.'); } else if (impersonate && simulate) { @@ -376,6 +377,7 @@ task('deploy_and_migrate', 'Runs deploy and migration') governanceDm = dm; } + migrationStarted(); if (impersonate && !simulate) { throw new Error('Cannot impersonate an address if not simulating a migration. Please specify --simulate to simulate.'); } else if (impersonate && simulate) { From e24f281bb7813a32200ebd1525ff12b30cf030c7 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Mon, 1 Jun 2026 15:45:50 +0300 Subject: [PATCH 54/65] fix: remove Comet.sol, drop Sepolia and Fuji deployments, and update tests accordingly --- .github/workflows/deploy-market.yaml | 8 +- .github/workflows/enact-migration.yaml | 10 +- .github/workflows/prepare-migration.yaml | 10 +- .github/workflows/run-contract-linter.yaml | 2 - .github/workflows/run-coverage.yaml | 2 - .github/workflows/run-eslint.yaml | 2 - .github/workflows/run-forge-tests.yaml | 4 +- .github/workflows/run-gas-profiler.yaml | 2 - .github/workflows/run-scenarios.yaml | 4 +- .github/workflows/run-semgrep.yaml | 2 - .github/workflows/run-unit-tests.yaml | 2 - MIGRATIONS.md | 16 +- README.md | 15 +- SCENARIO.md | 2 +- contracts/Comet.sol | 1378 ----------------- contracts/CometFactory.sol | 11 - contracts/Configurator.sol | 4 +- contracts/marketupdates/ConfiguratorOld.sol | 4 +- contracts/test/CometHarness.sol | 84 - contracts/test/CometHarnessInterface.sol | 16 - contracts/test/EvilToken.sol | 10 +- deployments/fuji/usdc/configuration.json | 43 - deployments/fuji/usdc/deploy.ts | 111 -- ...sorb_transfer_event_and_auto_collateral.ts | 58 - deployments/fuji/usdc/roots.json | 6 - deployments/hardhat/dai/deploy.ts | 2 +- deployments/relations.ts | 2 +- deployments/sepolia/usdc/configuration.json | 54 - deployments/sepolia/usdc/deploy.ts | 79 - deployments/sepolia/usdc/relations.ts | 91 -- deployments/sepolia/usdc/roots.json | 7 - deployments/sepolia/weth/configuration.json | 44 - deployments/sepolia/weth/deploy.ts | 147 -- .../1709094543_initialize_market.ts | 96 -- deployments/sepolia/weth/relations.ts | 13 - deployments/sepolia/weth/roots.json | 7 - .../marketupdates/helpers/ChainAddresses.sol | 3 - forge/test/Comet.t.sol | 6 +- .../MarketUpdateArbitrumDeploymentTest.t.sol | 2 +- .../test/MarketUpdateBaseDeploymentTest.t.sol | 2 +- forge/test/MarketUpdateDeploymentBaseTest.sol | 16 +- .../MarketUpdateMainnetDeploymentTest.t.sol | 2 +- .../MarketUpdateMantleDeploymentTest.t.sol | 2 +- .../MarketUpdateOptimismDeploymentTest.t.sol | 2 +- .../MarketUpdatePolygonDeploymentTest.t.sol | 2 +- .../MarketUpdateScrollDeploymentTest.t.sol | 2 +- forge/test/OnChainLiquidator.t.sol | 6 +- forge/test/PolygonLiquidator.t.sol | 6 +- foundry.toml | 1 - hardhat.config.ts | 55 - .../test/DeploymentManagerTest.ts | 18 - plugins/deployment_manager/test/ImportTest.ts | 50 +- .../test/RelationConfigTest.ts | 1 - plugins/import/etherscan.ts | 16 +- plugins/scenario/utils/hreForBase.ts | 2 - scenario/InterestRateScenario.ts | 17 +- scenario/context/CometContext.ts | 18 +- scenario/utils/index.ts | 2 +- scenario/utils/relayBaseMessage.ts | 2 +- scenario/utils/scenarioHelper.ts | 8 - scripts/exportNetworkConfigs.js | 1 - scripts/liquidation_bot/index.ts | 7 - src/deploy/Network.ts | 84 +- src/deploy/NetworkConfiguration.ts | 2 +- src/deploy/index.ts | 2 +- test/absorb-test.ts | 16 +- test/accrue-test.ts | 16 +- test/allow-test.ts | 12 +- test/approve-this-test.ts | 16 +- test/asset-info-test.ts | 19 +- test/balance-test.ts | 6 +- test/base-tracking-accrued-test.ts | 12 +- test/bulker-test.ts | 46 +- test/buy-collateral-test.ts | 24 +- test/comet-ext-test.ts | 16 +- test/configurator-test.ts | 102 +- test/constructor-test.ts | 21 +- test/erc20-test.ts | 32 +- test/helpers.ts | 123 +- test/interest-rate-test.ts | 6 +- test/is-borrow-collateralized-test.ts | 12 +- test/is-liquidatable-test.ts | 14 +- test/liquidation/liquidation-bot-script.ts | 2 +- test/liquidation/liquidation-bot-test.ts | 2 +- test/liquidation/makeLiquidatableProtocol.ts | 8 +- test/marketupdates/existing-flow-test.ts | 20 +- .../market-update-comet-proxy-admin-test.ts | 12 +- .../market-update-configurator-test.ts | 12 +- .../market-update-deployment-test.ts | 8 +- .../market-update-proposer-test.ts | 14 +- .../market-update-timelock-test.ts | 6 +- test/pause-guardian-test.ts | 18 +- test/price-feed-test.ts | 6 +- test/quote-collateral-test.ts | 10 +- test/reserves-test.ts | 6 +- test/rewards-test.ts | 120 +- test/sanity-test.ts | 2 +- test/supply-test.ts | 40 +- test/tracking-index-bounds-test.ts | 24 +- test/transfer-test.ts | 40 +- test/update-assets-in-test.ts | 12 +- test/withdraw-reserves-test.ts | 10 +- test/withdraw-test.ts | 48 +- 103 files changed, 579 insertions(+), 3019 deletions(-) delete mode 100644 contracts/Comet.sol delete mode 100644 contracts/CometFactory.sol delete mode 100644 contracts/test/CometHarness.sol delete mode 100644 contracts/test/CometHarnessInterface.sol delete mode 100644 deployments/fuji/usdc/configuration.json delete mode 100644 deployments/fuji/usdc/deploy.ts delete mode 100644 deployments/fuji/usdc/migrations/1665028496_absorb_transfer_event_and_auto_collateral.ts delete mode 100644 deployments/fuji/usdc/roots.json delete mode 100644 deployments/sepolia/usdc/configuration.json delete mode 100644 deployments/sepolia/usdc/deploy.ts delete mode 100644 deployments/sepolia/usdc/relations.ts delete mode 100644 deployments/sepolia/usdc/roots.json delete mode 100644 deployments/sepolia/weth/configuration.json delete mode 100644 deployments/sepolia/weth/deploy.ts delete mode 100644 deployments/sepolia/weth/migrations/1709094543_initialize_market.ts delete mode 100644 deployments/sepolia/weth/relations.ts delete mode 100644 deployments/sepolia/weth/roots.json diff --git a/.github/workflows/deploy-market.yaml b/.github/workflows/deploy-market.yaml index ccf04b85e..a9758642e 100644 --- a/.github/workflows/deploy-market.yaml +++ b/.github/workflows/deploy-market.yaml @@ -6,9 +6,7 @@ on: type: choice description: Network options: - - fuji - mainnet - - sepolia - polygon - arbitrum - base @@ -37,10 +35,8 @@ jobs: ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} - SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} - SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} @@ -61,7 +57,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"${RONIN_QUICKNODE_LINK}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"${MANTLE_QUICKNODE_LINK}\",\"optimism\":\"${OPTIMISM_QUICKNODE_LINK}\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"sepolia\":\"${SEPOLIA_QUICKNODE_LINK}\",\"polygon\":\"${POLYGON_QUICKNODE_LINK}\",\"arbitrum\":\"${ARBITRUM_QUICKNODE_LINK}\",\"base\":\"${BASE_QUICKNODE_LINK}\",\"scroll\":\"https://scroll.drpc.org\"}')[github.event.inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"${RONIN_QUICKNODE_LINK}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"${MANTLE_QUICKNODE_LINK}\",\"optimism\":\"${OPTIMISM_QUICKNODE_LINK}\",\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"polygon\":\"${POLYGON_QUICKNODE_LINK}\",\"arbitrum\":\"${ARBITRUM_QUICKNODE_LINK}\",\"base\":\"${BASE_QUICKNODE_LINK}\",\"scroll\":\"https://scroll.drpc.org\"}')[github.event.inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' @@ -70,7 +66,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ vars.GOV_NETWORK }}" - ethereum_url: "${{ fromJSON('{\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"sepolia\":\"${SEPOLIA_QUICKNODE_LINK}\"}')[vars.GOV_NETWORK] }}" + ethereum_url: "${{ fromJSON('{\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\"}')[vars.GOV_NETWORK] }}" port: 8685 if: github.event.inputs.eth_pk == '' && vars.GOV_NETWORK != '' && github.event.inputs.network != vars.GOV_NETWORK diff --git a/.github/workflows/enact-migration.yaml b/.github/workflows/enact-migration.yaml index b521a5289..9975d4781 100644 --- a/.github/workflows/enact-migration.yaml +++ b/.github/workflows/enact-migration.yaml @@ -6,9 +6,7 @@ on: type: choice description: Network options: - - fuji - mainnet - - sepolia - polygon - arbitrum - base @@ -59,10 +57,8 @@ jobs: ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} - SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} - SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} @@ -85,8 +81,6 @@ jobs: case ${{ github.event.inputs.network }} in polygon | arbitrum | base | optimism | mantle | scroll | linea | ronin | unichain) echo "GOV_NETWORK=mainnet" >> $GITHUB_ENV ;; - sepolia) - echo "GOV_NETWORK=sepolia" >> $GITHUB_ENV ;; *) echo "No governance network for selected network" ;; esac @@ -105,7 +99,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"${RONIN_QUICKNODE_LINK}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"${MANTLE_QUICKNODE_LINK}\",\"optimism\":\"${OPTIMISM_QUICKNODE_LINK}\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"sepolia\":\"${SEPOLIA_QUICKNODE_LINK}\",\"polygon\":\"${POLYGON_QUICKNODE_LINK}\",\"arbitrum\":\"${ARBITRUM_QUICKNODE_LINK}\",\"base\":\"${BASE_QUICKNODE_LINK}\",\"scroll\":\"https://scroll.drpc.org\"}')[github.event.inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"${RONIN_QUICKNODE_LINK}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"${MANTLE_QUICKNODE_LINK}\",\"optimism\":\"${OPTIMISM_QUICKNODE_LINK}\",\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"polygon\":\"${POLYGON_QUICKNODE_LINK}\",\"arbitrum\":\"${ARBITRUM_QUICKNODE_LINK}\",\"base\":\"${BASE_QUICKNODE_LINK}\",\"scroll\":\"https://scroll.drpc.org\"}')[github.event.inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' @@ -114,7 +108,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ vars.GOV_NETWORK }}" - ethereum_url: "${{ fromJSON('{\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"sepolia\":\"${SEPOLIA_QUICKNODE_LINK}\"}')[vars.GOV_NETWORK] }}" + ethereum_url: "${{ fromJSON('{\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\"}')[vars.GOV_NETWORK] }}" port: 8685 if: github.event.inputs.eth_pk == '' && vars.GOV_NETWORK != '' && github.event.inputs.network != vars.GOV_NETWORK diff --git a/.github/workflows/prepare-migration.yaml b/.github/workflows/prepare-migration.yaml index 2cac15e4c..088d643d0 100644 --- a/.github/workflows/prepare-migration.yaml +++ b/.github/workflows/prepare-migration.yaml @@ -6,9 +6,7 @@ on: type: choice description: Network options: - - fuji - mainnet - - sepolia - polygon - arbitrum - base @@ -40,10 +38,8 @@ jobs: ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} - SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} - SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} @@ -65,8 +61,6 @@ jobs: case ${{ github.event.inputs.network }} in polygon | arbitrum | base | optimism | mantle | scroll | linea | ronin | unichain) echo "GOV_NETWORK=mainnet" >> $GITHUB_ENV ;; - sepolia) - echo "GOV_NETWORK=sepolia" >> $GITHUB_ENV ;; *) echo "No governance network for selected network" ;; esac @@ -75,7 +69,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ inputs.network }}" - ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"${RONIN_QUICKNODE_LINK}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"${MANTLE_QUICKNODE_LINK}\",\"optimism\":\"${OPTIMISM_QUICKNODE_LINK}\",\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"sepolia\":\"${SEPOLIA_QUICKNODE_LINK}\",\"polygon\":\"${POLYGON_QUICKNODE_LINK}\",\"arbitrum\":\"${ARBITRUM_QUICKNODE_LINK}\",\"base\":\"${BASE_QUICKNODE_LINK}\",\"scroll\":\"https://scroll.drpc.org\"}')[github.event.inputs.network] }}" + ethereum_url: "${{ fromJSON('{\"linea\":\"${LINEA_QUICKNODE_LINK}\",\"ronin\":\"${RONIN_QUICKNODE_LINK}\",\"unichain\":\"${UNICHAIN_QUICKNODE_LINK}\",\"mantle\":\"${MANTLE_QUICKNODE_LINK}\",\"optimism\":\"${OPTIMISM_QUICKNODE_LINK}\",\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"polygon\":\"${POLYGON_QUICKNODE_LINK}\",\"arbitrum\":\"${ARBITRUM_QUICKNODE_LINK}\",\"base\":\"${BASE_QUICKNODE_LINK}\",\"scroll\":\"https://scroll.drpc.org\"}')[github.event.inputs.network] }}" port: 8585 if: github.event.inputs.eth_pk == '' @@ -84,7 +78,7 @@ jobs: with: wallet_connect_project_id: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} requested_network: "${{ vars.GOV_NETWORK }}" - ethereum_url: "${{ fromJSON('{\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\",\"sepolia\":\"${SEPOLIA_QUICKNODE_LINK}\"}')[vars.GOV_NETWORK] }}" + ethereum_url: "${{ fromJSON('{\"mainnet\":\"${MAINNET_QUICKNODE_LINK}\"}')[vars.GOV_NETWORK] }}" port: 8685 if: github.event.inputs.eth_pk == '' && vars.GOV_NETWORK != '' && github.event.inputs.network != vars.GOV_NETWORK diff --git a/.github/workflows/run-contract-linter.yaml b/.github/workflows/run-contract-linter.yaml index 432977561..7acd61cce 100644 --- a/.github/workflows/run-contract-linter.yaml +++ b/.github/workflows/run-contract-linter.yaml @@ -13,10 +13,8 @@ jobs: ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} - SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} - SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} diff --git a/.github/workflows/run-coverage.yaml b/.github/workflows/run-coverage.yaml index 06d00fead..e6e883174 100644 --- a/.github/workflows/run-coverage.yaml +++ b/.github/workflows/run-coverage.yaml @@ -15,10 +15,8 @@ jobs: ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} - SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} - SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} diff --git a/.github/workflows/run-eslint.yaml b/.github/workflows/run-eslint.yaml index 6a0a92224..a3cc60e00 100644 --- a/.github/workflows/run-eslint.yaml +++ b/.github/workflows/run-eslint.yaml @@ -13,10 +13,8 @@ jobs: ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} - SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} - SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} diff --git a/.github/workflows/run-forge-tests.yaml b/.github/workflows/run-forge-tests.yaml index 050840763..b75007ac6 100644 --- a/.github/workflows/run-forge-tests.yaml +++ b/.github/workflows/run-forge-tests.yaml @@ -30,7 +30,6 @@ jobs: _TENDERLY_KEY_RONIN: ${{ secrets._TENDERLY_KEY_RONIN }} ANKR_KEY: ${{ secrets.ANKR_KEY }} ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} - SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} @@ -43,7 +42,6 @@ jobs: SCROLL_RPC_URL: ${{ secrets.SCROLL_RPC_URL }} UNICHAIN_QUICKNODE_LINK: ${{ secrets.UNICHAIN_QUICKNODE_LINK }} LINEA_QUICKNODE_LINK: ${{ secrets.LINEA_QUICKNODE_LINK }} - SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} ARBITRUM_QUICKNODE_LINK: ${{ secrets.ARBITRUM_QUICKNODE_LINK }} POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} @@ -52,4 +50,4 @@ jobs: - name: Build Comet with older solc versions run: | - forge build --contracts contracts/Comet.sol --use solc:0.8.15 --via-ir --optimizer-runs 1 + forge build --contracts contracts/CometWithExtendedAssetList.sol --use solc:0.8.15 --via-ir --optimizer-runs 1 diff --git a/.github/workflows/run-gas-profiler.yaml b/.github/workflows/run-gas-profiler.yaml index 8096fa29c..4aacef1a8 100644 --- a/.github/workflows/run-gas-profiler.yaml +++ b/.github/workflows/run-gas-profiler.yaml @@ -14,10 +14,8 @@ jobs: ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} - SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} - SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} diff --git a/.github/workflows/run-scenarios.yaml b/.github/workflows/run-scenarios.yaml index bbb576eff..75c337ba1 100644 --- a/.github/workflows/run-scenarios.yaml +++ b/.github/workflows/run-scenarios.yaml @@ -12,10 +12,8 @@ env: ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} - SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} - SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} @@ -87,7 +85,7 @@ jobs: strategy: fail-fast: false matrix: - bases: [ development, mainnet, mainnet-weth, mainnet-wbtc, mainnet-usdt, mainnet-wsteth, mainnet-usds, sepolia-usdc, sepolia-weth, fuji, polygon, polygon-usdt, arbitrum-usdc.e, arbitrum-usdc, arbitrum-weth, arbitrum-usdt, base-usdbc, base-weth, base-usdc, base-aero, base-usds, optimism-usdc, optimism-usdt, optimism-weth, mantle-usde, linea-usdc, linea-weth, scroll-usdc, ronin-weth, ronin-wron, unichain-usdc, unichain-weth] + bases: [ development, mainnet, mainnet-weth, mainnet-wbtc, mainnet-usdt, mainnet-wsteth, mainnet-usds, polygon, polygon-usdt, arbitrum-usdc.e, arbitrum-usdc, arbitrum-weth, arbitrum-usdt, base-usdbc, base-weth, base-usdc, base-aero, base-usds, optimism-usdc, optimism-usdt, optimism-weth, mantle-usde, linea-usdc, linea-weth, scroll-usdc, ronin-weth, ronin-wron, unichain-usdc, unichain-weth] name: Run scenarios runs-on: ubuntu-latest steps: diff --git a/.github/workflows/run-semgrep.yaml b/.github/workflows/run-semgrep.yaml index 62301b2e4..077f45fa5 100644 --- a/.github/workflows/run-semgrep.yaml +++ b/.github/workflows/run-semgrep.yaml @@ -20,10 +20,8 @@ jobs: ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} - SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} - SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} diff --git a/.github/workflows/run-unit-tests.yaml b/.github/workflows/run-unit-tests.yaml index 012be4cc9..5c006b4dd 100644 --- a/.github/workflows/run-unit-tests.yaml +++ b/.github/workflows/run-unit-tests.yaml @@ -17,10 +17,8 @@ jobs: ETHERSCAN_KEY_FOR_ARBITRUM: ${{ secrets.ETHERSCAN_KEY_FOR_ARBITRUM }} ETHERSCAN_KEY_FOR_POLYGON: ${{ secrets.ETHERSCAN_KEY_FOR_POLYGON }} ETHERSCAN_KEY_FOR_LINEA: ${{ secrets.ETHERSCAN_KEY_FOR_LINEA }} - SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }} INFURA_KEY: ${{ secrets.INFURA_KEY }} MAINNET_QUICKNODE_LINK: ${{ secrets.MAINNET_QUICKNODE_LINK }} - SEPOLIA_QUICKNODE_LINK: ${{ secrets.SEPOLIA_QUICKNODE_LINK }} RONIN_QUICKNODE_LINK: ${{ secrets.RONIN_QUICKNODE_LINK }} POLYGON_QUICKNODE_LINK: ${{ secrets.POLYGON_QUICKNODE_LINK }} OPTIMISM_QUICKNODE_LINK: ${{ secrets.OPTIMISM_QUICKNODE_LINK }} diff --git a/MIGRATIONS.md b/MIGRATIONS.md index b4dc00289..8dfde78f3 100644 --- a/MIGRATIONS.md +++ b/MIGRATIONS.md @@ -7,10 +7,10 @@ Migrations are simple scripts which deploy or modify contracts. The goal of migr To create a new migration, run: ```sh -yarn hardhat gen:migration --network sepolia --deployment usdc my_migration +yarn hardhat gen:migration --network mainnet --deployment usdc my_migration ``` -This will create a new file, such as `deployments/sepolia/usdc/migrations/164443237_my_migration.ts` with a base migration script. There are currently two steps to a migration script, but this is likely to change soon: +This will create a new file, such as `deployments/mainnet/usdc/migrations/164443237_my_migration.ts` with a base migration script. There are currently two steps to a migration script, but this is likely to change soon: 1. Prepare: steps used to create artifacts, such as new on-chain contracts. The output from this step is stored (e.g. "NewCometImplementation: 0x...") 2. Enact: steps used to make these artifacts current, such as upgrading the proxy to the address from the previous step. @@ -20,31 +20,31 @@ This will create a new file, such as `deployments/sepolia/usdc/migrations/164443 You can run the preparation for a migration locally via: ```sh -yarn hardhat migrate --network sepolia --deployment usdc --prepare 164443237_my_migration +yarn hardhat migrate --network mainnet --deployment usdc --prepare 164443237_my_migration ``` or the enactment via: ```sh -yarn hardhat migrate --network sepolia --deployment usdc --enact 164443237_my_migration +yarn hardhat migrate --network mainnet --deployment usdc --enact 164443237_my_migration ``` or both preparation and enactment via: ```sh -yarn hardhat migrate --network sepolia --deployment usdc --prepare --enact 164443237_my_migration +yarn hardhat migrate --network mainnet --deployment usdc --prepare --enact 164443237_my_migration ``` Also, you can simulate either of the previous steps to see what effect they would have without actually modifying the on-chain state: ```sh -yarn hardhat migrate --network sepolia --deployment usdc --prepare --simulate 164443237_my_migration +yarn hardhat migrate --network mainnet --deployment usdc --prepare --simulate 164443237_my_migration ``` When simulating a migration, you can also impersonate an address to run the migration as. This can be helpful when trying to test a migration that makes a proposal, which requires an address with enough COMP: ```sh -yarn hardhat migrate --network sepolia --deployment usdc --prepare --simulate --impersonate ADDRESS_TO_IMPERSONATE 164443237_my_migration +yarn hardhat migrate --network mainnet --deployment usdc --prepare --simulate --impersonate ADDRESS_TO_IMPERSONATE 164443237_my_migration ``` ## Running a Migration in GitHub @@ -53,7 +53,7 @@ The preferred way to run a migration is in GitHub, via manual workflow dispatch. ## Migration Artifacts -After preparation, a migration stores some artifacts under `deployments/sepolia/usdc/artifacts/164443237_my_migration.json`. These will be loaded and can be referenced in the enact step of that migration. +After preparation, a migration stores some artifacts under `deployments/mainnet/usdc/artifacts/164443237_my_migration.json`. These will be loaded and can be referenced in the enact step of that migration. ## Testing Migrations diff --git a/README.md b/README.md index cb8b93978..67471bfa0 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,6 @@ INFURA_KEY= Optional env variables: ``` -SNOWTRACE_KEY= COINMARKETCAP_API_KEY= REPORT_GAS=true ETH_PK= # takes precedence over MNEMONIC @@ -56,25 +55,25 @@ An example deployment command looks like: ## Comet protocol contracts -**[Comet.sol](https://github.com/compound-finance/comet/blob/main/contracts/Comet.sol)** - Contract that inherits `CometMainInterface.sol` and is the implementation for most of Comet's core functionalities. A small set of functions that do not fit within this contract are implemented in `CometExt.sol` instead, which Comet `DELEGATECALL`s to for unrecognized function signatures. +**[CometWithExtendedAssetList.sol](https://github.com/compound-finance/comet/blob/main/contracts/CometWithExtendedAssetList.sol)** - Contract that inherits `CometMainInterface.sol` and is the implementation for most of Comet's core functionalities. A small set of functions that do not fit within this contract are implemented in `CometExt.sol` instead, which Comet `DELEGATECALL`s to for unrecognized function signatures. -**[CometExt.sol](https://github.com/compound-finance/comet/blob/main/contracts/CometExt.sol)** - Contract that inherits `CometExtInterface.sol` and is the implementation for extra functions that do not fit within `Comet.sol`, such as `approve`. +**[CometExt.sol](https://github.com/compound-finance/comet/blob/main/contracts/CometExt.sol)** - Contract that inherits `CometExtInterface.sol` and is the implementation for extra functions that do not fit within `CometWithExtendedAssetList.sol`, such as `approve`. -**[CometInterface.sol](https://github.com/compound-finance/comet/blob/main/contracts/CometInterface.sol)** - Abstract contract that inherits `CometMainInterface.sol` and `CometExtInterface.sol`. This interface contains all the functions and events for `Comet.sol` and `CometExt.sol` and is ERC-20 compatible. +**[CometInterface.sol](https://github.com/compound-finance/comet/blob/main/contracts/CometInterface.sol)** - Abstract contract that inherits `CometMainInterface.sol` and `CometExtInterface.sol`. This interface contains all the functions and events for `CometWithExtendedAssetList.sol` and `CometExt.sol` and is ERC-20 compatible. -**[CometMainInterface.sol](https://github.com/compound-finance/comet/blob/main/contracts/CometMainInterface.sol)** - Abstract contract that inherits `CometCore.sol` and contains all the functions and events for `Comet.sol`. +**[CometMainInterface.sol](https://github.com/compound-finance/comet/blob/main/contracts/CometMainInterface.sol)** - Abstract contract that inherits `CometCore.sol` and contains all the functions and events for `CometWithExtendedAssetList.sol`. **[CometExtInterface.sol](https://github.com/compound-finance/comet/blob/main/contracts/CometExtInterface.sol)** - Abstract contract that inherits `CometCore.sol` and contains all the functions and events for `CometExt.sol`. -**[CometCore.sol](https://github.com/compound-finance/comet/blob/main/contracts/CometCore.sol)** - Abstract contract that inherits `CometStorage.sol`, `CometConfiguration.sol`, and `CometMath.sol`. This contracts contains functions and constants that are shared between `Comet.sol` and `CometExt.sol`. +**[CometCore.sol](https://github.com/compound-finance/comet/blob/main/contracts/CometCore.sol)** - Abstract contract that inherits `CometStorage.sol`, `CometConfiguration.sol`, and `CometMath.sol`. This contracts contains functions and constants that are shared between `CometWithExtendedAssetList.sol` and `CometExt.sol`. **[CometStorage.sol](https://github.com/compound-finance/comet/blob/main/contracts/CometStorage.sol)** - Contract that defines the storage variables used for the Comet protocol. -**[CometConfiguration.sol](https://github.com/compound-finance/comet/blob/main/contracts/CometConfiguration.sol)** - Contract that defines the configuration structs passed into the constructors for `Comet.sol` and `CometExt.sol`. +**[CometConfiguration.sol](https://github.com/compound-finance/comet/blob/main/contracts/CometConfiguration.sol)** - Contract that defines the configuration structs passed into the constructors for `CometWithExtendedAssetList.sol` and `CometExt.sol`. **[CometMath.sol](https://github.com/compound-finance/comet/blob/main/contracts/CometMath.sol)** - Contract that defines math functions that are used throughout the Comet codebase. -**[CometFactory.sol](https://github.com/compound-finance/comet/blob/main/contracts/CometFactory.sol)** - Contract that inherits `CometConfiguration.sol` and is used to deploy new versions of `Comet.sol`. This contract will mainly be called by the Configurator during the governance upgrade process. +**[CometFactory.sol](https://github.com/compound-finance/comet/blob/main/contracts/CometFactory.sol)** - Contract that inherits `CometConfiguration.sol` and is used to deploy new versions of `CometWithExtendedAssetList.sol`. This contract will mainly be called by the Configurator during the governance upgrade process. ## Configurator contracts diff --git a/SCENARIO.md b/SCENARIO.md index da681cbfa..293995aac 100644 --- a/SCENARIO.md +++ b/SCENARIO.md @@ -8,7 +8,7 @@ Scenarios are high-level property and ad-hoc tests for the Comet protocol. To ru You can run scenarios against a given base as: -`npx hardhat scenario --bases development,sepolia,fuji` +`npx hardhat scenario --bases development,linea,mainnet` You can run spider persistently first if you wish: diff --git a/contracts/Comet.sol b/contracts/Comet.sol deleted file mode 100644 index e0f9bcf89..000000000 --- a/contracts/Comet.sol +++ /dev/null @@ -1,1378 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.15; - -import "./CometMainInterface.sol"; -import "./IERC20NonStandard.sol"; -import "./IPriceFeed.sol"; - -/** - * @title Compound's Comet Contract - * @notice An efficient monolithic money market protocol - * @author Compound - */ -contract Comet is CometMainInterface { - /** General configuration constants **/ - - /// @notice The admin of the protocol - address public override immutable governor; - - /// @notice The account which may trigger pauses - address public override immutable pauseGuardian; - - /// @notice The address of the base token contract - address public override immutable baseToken; - - /// @notice The address of the price feed for the base token - address public override immutable baseTokenPriceFeed; - - /// @notice The address of the extension contract delegate - address public override immutable extensionDelegate; - - /// @notice The point in the supply rates separating the low interest rate slope and the high interest rate slope (factor) - /// @dev uint64 - uint public override immutable supplyKink; - - /// @notice Per second supply interest rate slope applied when utilization is below kink (factor) - /// @dev uint64 - uint public override immutable supplyPerSecondInterestRateSlopeLow; - - /// @notice Per second supply interest rate slope applied when utilization is above kink (factor) - /// @dev uint64 - uint public override immutable supplyPerSecondInterestRateSlopeHigh; - - /// @notice Per second supply base interest rate (factor) - /// @dev uint64 - uint public override immutable supplyPerSecondInterestRateBase; - - /// @notice The point in the borrow rate separating the low interest rate slope and the high interest rate slope (factor) - /// @dev uint64 - uint public override immutable borrowKink; - - /// @notice Per second borrow interest rate slope applied when utilization is below kink (factor) - /// @dev uint64 - uint public override immutable borrowPerSecondInterestRateSlopeLow; - - /// @notice Per second borrow interest rate slope applied when utilization is above kink (factor) - /// @dev uint64 - uint public override immutable borrowPerSecondInterestRateSlopeHigh; - - /// @notice Per second borrow base interest rate (factor) - /// @dev uint64 - uint public override immutable borrowPerSecondInterestRateBase; - - /// @notice The fraction of the liquidation penalty that goes to buyers of collateral instead of the protocol - /// @dev uint64 - uint public override immutable storeFrontPriceFactor; - - /// @notice The scale for base token (must be less than 18 decimals) - /// @dev uint64 - uint public override immutable baseScale; - - /// @notice The scale for reward tracking - /// @dev uint64 - uint public override immutable trackingIndexScale; - - /// @notice The speed at which supply rewards are tracked (in trackingIndexScale) - /// @dev uint64 - uint public override immutable baseTrackingSupplySpeed; - - /// @notice The speed at which borrow rewards are tracked (in trackingIndexScale) - /// @dev uint64 - uint public override immutable baseTrackingBorrowSpeed; - - /// @notice The minimum amount of base principal wei for rewards to accrue - /// @dev This must be large enough so as to prevent division by base wei from overflowing the 64 bit indices - /// @dev uint104 - uint public override immutable baseMinForRewards; - - /// @notice The minimum base amount required to initiate a borrow - uint public override immutable baseBorrowMin; - - /// @notice The minimum base token reserves which must be held before collateral is hodled - uint public override immutable targetReserves; - - /// @notice The number of decimals for wrapped base token - uint8 public override immutable decimals; - - /// @notice The number of assets this contract actually supports - uint8 public override immutable numAssets; - - /// @notice Factor to divide by when accruing rewards in order to preserve 6 decimals (i.e. baseScale / 1e6) - uint internal immutable accrualDescaleFactor; - - /** Collateral asset configuration (packed) **/ - - uint256 internal immutable asset00_a; - uint256 internal immutable asset00_b; - uint256 internal immutable asset01_a; - uint256 internal immutable asset01_b; - uint256 internal immutable asset02_a; - uint256 internal immutable asset02_b; - uint256 internal immutable asset03_a; - uint256 internal immutable asset03_b; - uint256 internal immutable asset04_a; - uint256 internal immutable asset04_b; - uint256 internal immutable asset05_a; - uint256 internal immutable asset05_b; - uint256 internal immutable asset06_a; - uint256 internal immutable asset06_b; - uint256 internal immutable asset07_a; - uint256 internal immutable asset07_b; - uint256 internal immutable asset08_a; - uint256 internal immutable asset08_b; - uint256 internal immutable asset09_a; - uint256 internal immutable asset09_b; - uint256 internal immutable asset10_a; - uint256 internal immutable asset10_b; - uint256 internal immutable asset11_a; - uint256 internal immutable asset11_b; - - /** - * @notice Construct a new protocol instance - * @param config The mapping of initial/constant parameters - **/ - constructor(Configuration memory config) { - // Sanity checks - uint8 decimals_ = IERC20NonStandard(config.baseToken).decimals(); - if (decimals_ > MAX_BASE_DECIMALS) revert BadDecimals(); - if (config.storeFrontPriceFactor > FACTOR_SCALE) revert BadDiscount(); - if (config.assetConfigs.length > MAX_ASSETS) revert TooManyAssets(); - if (config.baseMinForRewards == 0) revert BadMinimum(); - if (IPriceFeed(config.baseTokenPriceFeed).decimals() != PRICE_FEED_DECIMALS) revert BadDecimals(); - - // Copy configuration - unchecked { - governor = config.governor; - pauseGuardian = config.pauseGuardian; - baseToken = config.baseToken; - baseTokenPriceFeed = config.baseTokenPriceFeed; - extensionDelegate = config.extensionDelegate; - storeFrontPriceFactor = config.storeFrontPriceFactor; - - decimals = decimals_; - baseScale = uint64(10 ** decimals_); - trackingIndexScale = config.trackingIndexScale; - if (baseScale < BASE_ACCRUAL_SCALE) revert BadDecimals(); - accrualDescaleFactor = baseScale / BASE_ACCRUAL_SCALE; - - baseMinForRewards = config.baseMinForRewards; - baseTrackingSupplySpeed = config.baseTrackingSupplySpeed; - baseTrackingBorrowSpeed = config.baseTrackingBorrowSpeed; - - baseBorrowMin = config.baseBorrowMin; - targetReserves = config.targetReserves; - } - - // Set interest rate model configs - unchecked { - supplyKink = config.supplyKink; - supplyPerSecondInterestRateSlopeLow = config.supplyPerYearInterestRateSlopeLow / SECONDS_PER_YEAR; - supplyPerSecondInterestRateSlopeHigh = config.supplyPerYearInterestRateSlopeHigh / SECONDS_PER_YEAR; - supplyPerSecondInterestRateBase = config.supplyPerYearInterestRateBase / SECONDS_PER_YEAR; - borrowKink = config.borrowKink; - borrowPerSecondInterestRateSlopeLow = config.borrowPerYearInterestRateSlopeLow / SECONDS_PER_YEAR; - borrowPerSecondInterestRateSlopeHigh = config.borrowPerYearInterestRateSlopeHigh / SECONDS_PER_YEAR; - borrowPerSecondInterestRateBase = config.borrowPerYearInterestRateBase / SECONDS_PER_YEAR; - } - - // Set asset info - numAssets = uint8(config.assetConfigs.length); - - (asset00_a, asset00_b) = getPackedAssetInternal(config.assetConfigs, 0); - (asset01_a, asset01_b) = getPackedAssetInternal(config.assetConfigs, 1); - (asset02_a, asset02_b) = getPackedAssetInternal(config.assetConfigs, 2); - (asset03_a, asset03_b) = getPackedAssetInternal(config.assetConfigs, 3); - (asset04_a, asset04_b) = getPackedAssetInternal(config.assetConfigs, 4); - (asset05_a, asset05_b) = getPackedAssetInternal(config.assetConfigs, 5); - (asset06_a, asset06_b) = getPackedAssetInternal(config.assetConfigs, 6); - (asset07_a, asset07_b) = getPackedAssetInternal(config.assetConfigs, 7); - (asset08_a, asset08_b) = getPackedAssetInternal(config.assetConfigs, 8); - (asset09_a, asset09_b) = getPackedAssetInternal(config.assetConfigs, 9); - (asset10_a, asset10_b) = getPackedAssetInternal(config.assetConfigs, 10); - (asset11_a, asset11_b) = getPackedAssetInternal(config.assetConfigs, 11); - } - - /** - * @dev Prevents marked functions from being reentered - * Note: this restrict contracts from calling comet functions in their hooks. - * Doing so will cause the transaction to revert. - */ - modifier nonReentrant() { - nonReentrantBefore(); - _; - nonReentrantAfter(); - } - - /** - * @dev Checks that the reentrancy flag is not set and then sets the flag - */ - function nonReentrantBefore() internal { - bytes32 slot = REENTRANCY_GUARD_FLAG_SLOT; - uint256 status; - assembly ("memory-safe") { - status := sload(slot) - } - - if (status == REENTRANCY_GUARD_ENTERED) revert ReentrantCallBlocked(); - assembly ("memory-safe") { - sstore(slot, REENTRANCY_GUARD_ENTERED) - } - } - - /** - * @dev Unsets the reentrancy flag - */ - function nonReentrantAfter() internal { - bytes32 slot = REENTRANCY_GUARD_FLAG_SLOT; - uint256 status; - assembly ("memory-safe") { - sstore(slot, REENTRANCY_GUARD_NOT_ENTERED) - } - } - - /** - * @notice Initialize storage for the contract - * @dev Can be used from constructor or proxy - */ - function initializeStorage() override external { - if (lastAccrualTime != 0) revert AlreadyInitialized(); - - // Initialize aggregates - lastAccrualTime = getNowInternal(); - baseSupplyIndex = BASE_INDEX_SCALE; - baseBorrowIndex = BASE_INDEX_SCALE; - - // Implicit initialization (not worth increasing contract size) - // trackingSupplyIndex = 0; - // trackingBorrowIndex = 0; - } - - /** - * @dev Checks and gets the packed asset info for storage - */ - function getPackedAssetInternal(AssetConfig[] memory assetConfigs, uint i) internal view returns (uint256, uint256) { - AssetConfig memory assetConfig; - if (i < assetConfigs.length) { - assembly { - assetConfig := mload(add(add(assetConfigs, 0x20), mul(i, 0x20))) - } - } else { - return (0, 0); - } - address asset = assetConfig.asset; - address priceFeed = assetConfig.priceFeed; - uint8 decimals_ = assetConfig.decimals; - - // Short-circuit if asset is nil - if (asset == address(0)) { - return (0, 0); - } - - // Sanity check price feed and asset decimals - if (IPriceFeed(priceFeed).decimals() != PRICE_FEED_DECIMALS) revert BadDecimals(); - if (IERC20NonStandard(asset).decimals() != decimals_) revert BadDecimals(); - - // Ensure collateral factors are within range - if (assetConfig.borrowCollateralFactor >= assetConfig.liquidateCollateralFactor) revert BorrowCFTooLarge(); - if (assetConfig.liquidateCollateralFactor > MAX_COLLATERAL_FACTOR) revert LiquidateCFTooLarge(); - - unchecked { - // Keep 4 decimals for each factor - uint64 descale = FACTOR_SCALE / 1e4; - uint16 borrowCollateralFactor = uint16(assetConfig.borrowCollateralFactor / descale); - uint16 liquidateCollateralFactor = uint16(assetConfig.liquidateCollateralFactor / descale); - uint16 liquidationFactor = uint16(assetConfig.liquidationFactor / descale); - - // Be nice and check descaled values are still within range - if (borrowCollateralFactor >= liquidateCollateralFactor) revert BorrowCFTooLarge(); - - // Keep whole units of asset for supply cap - uint64 supplyCap = uint64(assetConfig.supplyCap / (10 ** decimals_)); - - uint256 word_a = (uint160(asset) << 0 | - uint256(borrowCollateralFactor) << 160 | - uint256(liquidateCollateralFactor) << 176 | - uint256(liquidationFactor) << 192); - uint256 word_b = (uint160(priceFeed) << 0 | - uint256(decimals_) << 160 | - uint256(supplyCap) << 168); - - return (word_a, word_b); - } - } - - /** - * @notice Get the i-th asset info, according to the order they were passed in originally - * @param i The index of the asset info to get - * @return The asset info object - */ - function getAssetInfo(uint8 i) override public view returns (AssetInfo memory) { - if (i >= numAssets) revert BadAsset(); - - uint256 word_a; - uint256 word_b; - - if (i == 0) { - word_a = asset00_a; - word_b = asset00_b; - } else if (i == 1) { - word_a = asset01_a; - word_b = asset01_b; - } else if (i == 2) { - word_a = asset02_a; - word_b = asset02_b; - } else if (i == 3) { - word_a = asset03_a; - word_b = asset03_b; - } else if (i == 4) { - word_a = asset04_a; - word_b = asset04_b; - } else if (i == 5) { - word_a = asset05_a; - word_b = asset05_b; - } else if (i == 6) { - word_a = asset06_a; - word_b = asset06_b; - } else if (i == 7) { - word_a = asset07_a; - word_b = asset07_b; - } else if (i == 8) { - word_a = asset08_a; - word_b = asset08_b; - } else if (i == 9) { - word_a = asset09_a; - word_b = asset09_b; - } else if (i == 10) { - word_a = asset10_a; - word_b = asset10_b; - } else if (i == 11) { - word_a = asset11_a; - word_b = asset11_b; - } else { - revert Absurd(); - } - - address asset = address(uint160(word_a & type(uint160).max)); - uint64 rescale = FACTOR_SCALE / 1e4; - uint64 borrowCollateralFactor = uint64(((word_a >> 160) & type(uint16).max) * rescale); - uint64 liquidateCollateralFactor = uint64(((word_a >> 176) & type(uint16).max) * rescale); - uint64 liquidationFactor = uint64(((word_a >> 192) & type(uint16).max) * rescale); - - address priceFeed = address(uint160(word_b & type(uint160).max)); - uint8 decimals_ = uint8(((word_b >> 160) & type(uint8).max)); - uint64 scale = uint64(10 ** decimals_); - uint128 supplyCap = uint128(((word_b >> 168) & type(uint64).max) * scale); - - return AssetInfo({ - offset: i, - asset: asset, - priceFeed: priceFeed, - scale: scale, - borrowCollateralFactor: borrowCollateralFactor, - liquidateCollateralFactor: liquidateCollateralFactor, - liquidationFactor: liquidationFactor, - supplyCap: supplyCap - }); - } - - /** - * @dev Determine index of asset that matches given address - */ - function getAssetInfoByAddress(address asset) override public view returns (AssetInfo memory) { - for (uint8 i = 0; i < numAssets; ) { - AssetInfo memory assetInfo = getAssetInfo(i); - if (assetInfo.asset == asset) { - return assetInfo; - } - unchecked { i++; } - } - revert BadAsset(); - } - - /** - * @return The current timestamp - **/ - function getNowInternal() virtual internal view returns (uint40) { - if (block.timestamp >= 2**40) revert TimestampTooLarge(); - return uint40(block.timestamp); - } - - /** - * @dev Calculate accrued interest indices for base token supply and borrows - **/ - function accruedInterestIndices(uint timeElapsed) internal view returns (uint64, uint64) { - uint64 baseSupplyIndex_ = baseSupplyIndex; - uint64 baseBorrowIndex_ = baseBorrowIndex; - if (timeElapsed > 0) { - uint utilization = getUtilization(); - uint supplyRate = getSupplyRate(utilization); - uint borrowRate = getBorrowRate(utilization); - baseSupplyIndex_ += safe64(mulFactor(baseSupplyIndex_, supplyRate * timeElapsed)); - baseBorrowIndex_ += safe64(mulFactor(baseBorrowIndex_, borrowRate * timeElapsed)); - } - return (baseSupplyIndex_, baseBorrowIndex_); - } - - /** - * @dev Accrue interest (and rewards) in base token supply and borrows - **/ - function accrueInternal() internal { - uint40 now_ = getNowInternal(); - uint timeElapsed = uint256(now_ - lastAccrualTime); - if (timeElapsed > 0) { - (baseSupplyIndex, baseBorrowIndex) = accruedInterestIndices(timeElapsed); - if (totalSupplyBase >= baseMinForRewards) { - trackingSupplyIndex += safe64(divBaseWei(baseTrackingSupplySpeed * timeElapsed, totalSupplyBase)); - } - if (totalBorrowBase >= baseMinForRewards) { - trackingBorrowIndex += safe64(divBaseWei(baseTrackingBorrowSpeed * timeElapsed, totalBorrowBase)); - } - lastAccrualTime = now_; - } - } - - /** - * @notice Accrue interest and rewards for an account - **/ - function accrueAccount(address account) override external { - accrueInternal(); - - UserBasic memory basic = userBasic[account]; - updateBasePrincipal(account, basic, basic.principal); - } - - /** - * @dev Note: Does not accrue interest first - * @param utilization The utilization to check the supply rate for - * @return The per second supply rate at `utilization` - */ - function getSupplyRate(uint utilization) override public view returns (uint64) { - if (utilization <= supplyKink) { - // interestRateBase + interestRateSlopeLow * utilization - return safe64(supplyPerSecondInterestRateBase + mulFactor(supplyPerSecondInterestRateSlopeLow, utilization)); - } else { - // interestRateBase + interestRateSlopeLow * kink + interestRateSlopeHigh * (utilization - kink) - return safe64(supplyPerSecondInterestRateBase + mulFactor(supplyPerSecondInterestRateSlopeLow, supplyKink) + mulFactor(supplyPerSecondInterestRateSlopeHigh, (utilization - supplyKink))); - } - } - - /** - * @dev Note: Does not accrue interest first - * @param utilization The utilization to check the borrow rate for - * @return The per second borrow rate at `utilization` - */ - function getBorrowRate(uint utilization) override public view returns (uint64) { - if (utilization <= borrowKink) { - // interestRateBase + interestRateSlopeLow * utilization - return safe64(borrowPerSecondInterestRateBase + mulFactor(borrowPerSecondInterestRateSlopeLow, utilization)); - } else { - // interestRateBase + interestRateSlopeLow * kink + interestRateSlopeHigh * (utilization - kink) - return safe64(borrowPerSecondInterestRateBase + mulFactor(borrowPerSecondInterestRateSlopeLow, borrowKink) + mulFactor(borrowPerSecondInterestRateSlopeHigh, (utilization - borrowKink))); - } - } - - /** - * @dev Note: Does not accrue interest first - * @return The utilization rate of the base asset - */ - function getUtilization() override public view returns (uint) { - uint totalSupply_ = presentValueSupply(baseSupplyIndex, totalSupplyBase); - uint totalBorrow_ = presentValueBorrow(baseBorrowIndex, totalBorrowBase); - if (totalSupply_ == 0) { - return 0; - } else { - return totalBorrow_ * FACTOR_SCALE / totalSupply_; - } - } - - /** - * @notice Get the current price from a feed - * @param priceFeed The address of a price feed - * @return The price, scaled by `PRICE_SCALE` - */ - function getPrice(address priceFeed) override public view returns (uint256) { - (, int price, , , ) = IPriceFeed(priceFeed).latestRoundData(); - if (price <= 0) revert BadPrice(); - return uint256(price); - } - - /** - * @notice Gets the total balance of protocol collateral reserves for an asset - * @dev Note: Reverts if collateral reserves are somehow negative, which should not be possible - * @param asset The collateral asset - */ - function getCollateralReserves(address asset) override public view returns (uint) { - return IERC20NonStandard(asset).balanceOf(address(this)) - totalsCollateral[asset].totalSupplyAsset; - } - - /** - * @notice Gets the total amount of protocol reserves of the base asset - */ - function getReserves() override public view returns (int) { - (uint64 baseSupplyIndex_, uint64 baseBorrowIndex_) = accruedInterestIndices(getNowInternal() - lastAccrualTime); - uint balance = IERC20NonStandard(baseToken).balanceOf(address(this)); - uint totalSupply_ = presentValueSupply(baseSupplyIndex_, totalSupplyBase); - uint totalBorrow_ = presentValueBorrow(baseBorrowIndex_, totalBorrowBase); - return signed256(balance) - signed256(totalSupply_) + signed256(totalBorrow_); - } - - /** - * @notice Check whether an account has enough collateral to borrow - * @param account The address to check - * @return Whether the account is minimally collateralized enough to borrow - */ - function isBorrowCollateralized(address account) override public view returns (bool) { - int104 principal = userBasic[account].principal; - - if (principal >= 0) { - return true; - } - - uint16 assetsIn = userBasic[account].assetsIn; - int liquidity = signedMulPrice( - presentValue(principal), - getPrice(baseTokenPriceFeed), - uint64(baseScale) - ); - - for (uint8 i = 0; i < numAssets; ) { - if (isInAsset(assetsIn, i)) { - if (liquidity >= 0) { - return true; - } - - AssetInfo memory asset = getAssetInfo(i); - uint newAmount = mulPrice( - userCollateral[account][asset.asset].balance, - getPrice(asset.priceFeed), - asset.scale - ); - liquidity += signed256(mulFactor( - newAmount, - asset.borrowCollateralFactor - )); - } - unchecked { i++; } - } - - return liquidity >= 0; - } - - /** - * @notice Check whether an account has enough collateral to not be liquidated - * @param account The address to check - * @return Whether the account is minimally collateralized enough to not be liquidated - */ - function isLiquidatable(address account) override public view returns (bool) { - int104 principal = userBasic[account].principal; - - if (principal >= 0) { - return false; - } - - uint16 assetsIn = userBasic[account].assetsIn; - int liquidity = signedMulPrice( - presentValue(principal), - getPrice(baseTokenPriceFeed), - uint64(baseScale) - ); - - for (uint8 i = 0; i < numAssets; ) { - if (isInAsset(assetsIn, i)) { - if (liquidity >= 0) { - return false; - } - - AssetInfo memory asset = getAssetInfo(i); - uint newAmount = mulPrice( - userCollateral[account][asset.asset].balance, - getPrice(asset.priceFeed), - asset.scale - ); - liquidity += signed256(mulFactor( - newAmount, - asset.liquidateCollateralFactor - )); - } - unchecked { i++; } - } - - return liquidity < 0; - } - - /** - * @dev The change in principal broken into repay and supply amounts - */ - function repayAndSupplyAmount(int104 oldPrincipal, int104 newPrincipal) internal pure returns (uint104, uint104) { - // If the new principal is less than the old principal, then no amount has been repaid or supplied - if (newPrincipal < oldPrincipal) return (0, 0); - - if (newPrincipal <= 0) { - return (uint104(newPrincipal - oldPrincipal), 0); - } else if (oldPrincipal >= 0) { - return (0, uint104(newPrincipal - oldPrincipal)); - } else { - return (uint104(-oldPrincipal), uint104(newPrincipal)); - } - } - - /** - * @dev The change in principal broken into withdraw and borrow amounts - */ - function withdrawAndBorrowAmount(int104 oldPrincipal, int104 newPrincipal) internal pure returns (uint104, uint104) { - // If the new principal is greater than the old principal, then no amount has been withdrawn or borrowed - if (newPrincipal > oldPrincipal) return (0, 0); - - if (newPrincipal >= 0) { - return (uint104(oldPrincipal - newPrincipal), 0); - } else if (oldPrincipal <= 0) { - return (0, uint104(oldPrincipal - newPrincipal)); - } else { - return (uint104(oldPrincipal), uint104(-newPrincipal)); - } - } - - /** - * @notice Pauses different actions within Comet - * @param supplyPaused Boolean for pausing supply actions - * @param transferPaused Boolean for pausing transfer actions - * @param withdrawPaused Boolean for pausing withdraw actions - * @param absorbPaused Boolean for pausing absorb actions - * @param buyPaused Boolean for pausing buy actions - */ - function pause( - bool supplyPaused, - bool transferPaused, - bool withdrawPaused, - bool absorbPaused, - bool buyPaused - ) override external { - if (msg.sender != governor && msg.sender != pauseGuardian) revert Unauthorized(); - - pauseFlags = - uint8(0) | - (toUInt8(supplyPaused) << PAUSE_SUPPLY_OFFSET) | - (toUInt8(transferPaused) << PAUSE_TRANSFER_OFFSET) | - (toUInt8(withdrawPaused) << PAUSE_WITHDRAW_OFFSET) | - (toUInt8(absorbPaused) << PAUSE_ABSORB_OFFSET) | - (toUInt8(buyPaused) << PAUSE_BUY_OFFSET); - - emit PauseAction(supplyPaused, transferPaused, withdrawPaused, absorbPaused, buyPaused); - } - - /** - * @return Whether or not supply actions are paused - */ - function isSupplyPaused() override public view returns (bool) { - return toBool(pauseFlags & (uint8(1) << PAUSE_SUPPLY_OFFSET)); - } - - /** - * @return Whether or not transfer actions are paused - */ - function isTransferPaused() override public view returns (bool) { - return toBool(pauseFlags & (uint8(1) << PAUSE_TRANSFER_OFFSET)); - } - - /** - * @return Whether or not withdraw actions are paused - */ - function isWithdrawPaused() override public view returns (bool) { - return toBool(pauseFlags & (uint8(1) << PAUSE_WITHDRAW_OFFSET)); - } - - /** - * @return Whether or not absorb actions are paused - */ - function isAbsorbPaused() override public view returns (bool) { - return toBool(pauseFlags & (uint8(1) << PAUSE_ABSORB_OFFSET)); - } - - /** - * @return Whether or not buy actions are paused - */ - function isBuyPaused() override public view returns (bool) { - return toBool(pauseFlags & (uint8(1) << PAUSE_BUY_OFFSET)); - } - - /** - * @dev Multiply a number by a factor - */ - function mulFactor(uint n, uint factor) internal pure returns (uint) { - return n * factor / FACTOR_SCALE; - } - - /** - * @dev Divide a number by an amount of base - */ - function divBaseWei(uint n, uint baseWei) internal view returns (uint) { - return n * baseScale / baseWei; - } - - /** - * @dev Multiply a `fromScale` quantity by a price, returning a common price quantity - */ - function mulPrice(uint n, uint price, uint64 fromScale) internal pure returns (uint) { - return n * price / fromScale; - } - - /** - * @dev Multiply a signed `fromScale` quantity by a price, returning a common price quantity - */ - function signedMulPrice(int n, uint price, uint64 fromScale) internal pure returns (int) { - return n * signed256(price) / int256(uint256(fromScale)); - } - - /** - * @dev Divide a common price quantity by a price, returning a `toScale` quantity - */ - function divPrice(uint n, uint price, uint64 toScale) internal pure returns (uint) { - return n * toScale / price; - } - - /** - * @dev Whether user has a non-zero balance of an asset, given assetsIn flags - */ - function isInAsset(uint16 assetsIn, uint8 assetOffset) internal pure returns (bool) { - return (assetsIn & (uint16(1) << assetOffset) != 0); - } - - /** - * @dev Update assetsIn bit vector if user has entered or exited an asset - */ - function updateAssetsIn( - address account, - AssetInfo memory assetInfo, - uint128 initialUserBalance, - uint128 finalUserBalance - ) internal { - if (initialUserBalance == 0 && finalUserBalance != 0) { - // set bit for asset - userBasic[account].assetsIn |= (uint16(1) << assetInfo.offset); - } else if (initialUserBalance != 0 && finalUserBalance == 0) { - // clear bit for asset - userBasic[account].assetsIn &= ~(uint16(1) << assetInfo.offset); - } - } - - /** - * @dev Write updated principal to store and tracking participation - */ - function updateBasePrincipal(address account, UserBasic memory basic, int104 principalNew) internal { - int104 principal = basic.principal; - basic.principal = principalNew; - - if (principal >= 0) { - uint indexDelta = uint256(trackingSupplyIndex - basic.baseTrackingIndex); - basic.baseTrackingAccrued += safe64(uint104(principal) * indexDelta / trackingIndexScale / accrualDescaleFactor); - } else { - uint indexDelta = uint256(trackingBorrowIndex - basic.baseTrackingIndex); - basic.baseTrackingAccrued += safe64(uint104(-principal) * indexDelta / trackingIndexScale / accrualDescaleFactor); - } - - if (principalNew >= 0) { - basic.baseTrackingIndex = trackingSupplyIndex; - } else { - basic.baseTrackingIndex = trackingBorrowIndex; - } - - userBasic[account] = basic; - } - - /** - * @dev Safe ERC20 transfer in and returns the final amount transferred (taking into account any fees) - * @dev Note: Safely handles non-standard ERC-20 tokens that do not return a value. See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ - function doTransferIn(address asset, address from, uint amount) internal returns (uint) { - uint256 preTransferBalance = IERC20NonStandard(asset).balanceOf(address(this)); - IERC20NonStandard(asset).transferFrom(from, address(this), amount); - bool success; - assembly ("memory-safe") { - switch returndatasize() - case 0 { // This is a non-standard ERC-20 - success := not(0) // set success to true - } - case 32 { // This is a compliant ERC-20 - returndatacopy(0, 0, 32) - success := mload(0) // Set `success = returndata` of override external call - } - default { // This is an excessively non-compliant ERC-20, revert. - revert(0, 0) - } - } - if (!success) revert TransferInFailed(); - return IERC20NonStandard(asset).balanceOf(address(this)) - preTransferBalance; - } - - /** - * @dev Safe ERC20 transfer out - * @dev Note: Safely handles non-standard ERC-20 tokens that do not return a value. See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - */ - function doTransferOut(address asset, address to, uint amount) internal { - IERC20NonStandard(asset).transfer(to, amount); - bool success; - assembly ("memory-safe") { - switch returndatasize() - case 0 { // This is a non-standard ERC-20 - success := not(0) // set success to true - } - case 32 { // This is a compliant ERC-20 - returndatacopy(0, 0, 32) - success := mload(0) // Set `success = returndata` of override external call - } - default { // This is an excessively non-compliant ERC-20, revert. - revert(0, 0) - } - } - if (!success) revert TransferOutFailed(); - } - - /** - * @notice Supply an amount of asset to the protocol - * @param asset The asset to supply - * @param amount The quantity to supply - */ - function supply(address asset, uint amount) override external { - return supplyInternal(msg.sender, msg.sender, msg.sender, asset, amount); - } - - /** - * @notice Supply an amount of asset to dst - * @param dst The address which will hold the balance - * @param asset The asset to supply - * @param amount The quantity to supply - */ - function supplyTo(address dst, address asset, uint amount) override external { - return supplyInternal(msg.sender, msg.sender, dst, asset, amount); - } - - /** - * @notice Supply an amount of asset from `from` to dst, if allowed - * @param from The supplier address - * @param dst The address which will hold the balance - * @param asset The asset to supply - * @param amount The quantity to supply - */ - function supplyFrom(address from, address dst, address asset, uint amount) override external { - return supplyInternal(msg.sender, from, dst, asset, amount); - } - - /** - * @dev Supply either collateral or base asset, depending on the asset, if operator is allowed - * @dev Note: Specifying an `amount` of uint256.max will repay all of `dst`'s accrued base borrow balance - */ - function supplyInternal(address operator, address from, address dst, address asset, uint amount) internal nonReentrant { - if (isSupplyPaused()) revert Paused(); - if (!hasPermission(from, operator)) revert Unauthorized(); - - if (asset == baseToken) { - if (amount == type(uint256).max) { - amount = borrowBalanceOf(dst); - } - return supplyBase(from, dst, amount); - } else { - return supplyCollateral(from, dst, asset, safe128(amount)); - } - } - - /** - * @dev Supply an amount of base asset from `from` to dst - */ - function supplyBase(address from, address dst, uint256 amount) internal { - amount = doTransferIn(baseToken, from, amount); - - accrueInternal(); - - UserBasic memory dstUser = userBasic[dst]; - int104 dstPrincipal = dstUser.principal; - int256 dstBalance = presentValue(dstPrincipal) + signed256(amount); - int104 dstPrincipalNew = principalValue(dstBalance); - - (uint104 repayAmount, uint104 supplyAmount) = repayAndSupplyAmount(dstPrincipal, dstPrincipalNew); - - totalSupplyBase += supplyAmount; - totalBorrowBase -= repayAmount; - - updateBasePrincipal(dst, dstUser, dstPrincipalNew); - - emit Supply(from, dst, amount); - - if (supplyAmount > 0) { - emit Transfer(address(0), dst, presentValueSupply(baseSupplyIndex, supplyAmount)); - } - } - - /** - * @dev Supply an amount of collateral asset from `from` to dst - */ - function supplyCollateral(address from, address dst, address asset, uint128 amount) internal { - amount = safe128(doTransferIn(asset, from, amount)); - - AssetInfo memory assetInfo = getAssetInfoByAddress(asset); - TotalsCollateral memory totals = totalsCollateral[asset]; - totals.totalSupplyAsset += amount; - if (totals.totalSupplyAsset > assetInfo.supplyCap) revert SupplyCapExceeded(); - - uint128 dstCollateral = userCollateral[dst][asset].balance; - uint128 dstCollateralNew = dstCollateral + amount; - - totalsCollateral[asset] = totals; - userCollateral[dst][asset].balance = dstCollateralNew; - - updateAssetsIn(dst, assetInfo, dstCollateral, dstCollateralNew); - - emit SupplyCollateral(from, dst, asset, amount); - } - - /** - * @notice ERC20 transfer an amount of base token to dst - * @param dst The recipient address - * @param amount The quantity to transfer - * @return true - */ - function transfer(address dst, uint amount) override external returns (bool) { - transferInternal(msg.sender, msg.sender, dst, baseToken, amount); - return true; - } - - /** - * @notice ERC20 transfer an amount of base token from src to dst, if allowed - * @param src The sender address - * @param dst The recipient address - * @param amount The quantity to transfer - * @return true - */ - function transferFrom(address src, address dst, uint amount) override external returns (bool) { - transferInternal(msg.sender, src, dst, baseToken, amount); - return true; - } - - /** - * @notice Transfer an amount of asset to dst - * @param dst The recipient address - * @param asset The asset to transfer - * @param amount The quantity to transfer - */ - function transferAsset(address dst, address asset, uint amount) override external { - return transferInternal(msg.sender, msg.sender, dst, asset, amount); - } - - /** - * @notice Transfer an amount of asset from src to dst, if allowed - * @param src The sender address - * @param dst The recipient address - * @param asset The asset to transfer - * @param amount The quantity to transfer - */ - function transferAssetFrom(address src, address dst, address asset, uint amount) override external { - return transferInternal(msg.sender, src, dst, asset, amount); - } - - /** - * @dev Transfer either collateral or base asset, depending on the asset, if operator is allowed - * @dev Note: Specifying an `amount` of uint256.max will transfer all of `src`'s accrued base balance - */ - function transferInternal(address operator, address src, address dst, address asset, uint amount) internal nonReentrant { - if (isTransferPaused()) revert Paused(); - if (!hasPermission(src, operator)) revert Unauthorized(); - if (src == dst) revert NoSelfTransfer(); - - if (asset == baseToken) { - if (amount == type(uint256).max) { - amount = balanceOf(src); - } - return transferBase(src, dst, amount); - } else { - return transferCollateral(src, dst, asset, safe128(amount)); - } - } - - /** - * @dev Transfer an amount of base asset from src to dst, borrowing if possible/necessary - */ - function transferBase(address src, address dst, uint256 amount) internal { - accrueInternal(); - - UserBasic memory srcUser = userBasic[src]; - UserBasic memory dstUser = userBasic[dst]; - - int104 srcPrincipal = srcUser.principal; - int104 dstPrincipal = dstUser.principal; - int256 srcBalance = presentValue(srcPrincipal) - signed256(amount); - int256 dstBalance = presentValue(dstPrincipal) + signed256(amount); - int104 srcPrincipalNew = principalValue(srcBalance); - int104 dstPrincipalNew = principalValue(dstBalance); - - (uint104 withdrawAmount, uint104 borrowAmount) = withdrawAndBorrowAmount(srcPrincipal, srcPrincipalNew); - (uint104 repayAmount, uint104 supplyAmount) = repayAndSupplyAmount(dstPrincipal, dstPrincipalNew); - - // Note: Instead of `total += addAmount - subAmount` to avoid underflow errors. - totalSupplyBase = totalSupplyBase + supplyAmount - withdrawAmount; - totalBorrowBase = totalBorrowBase + borrowAmount - repayAmount; - - updateBasePrincipal(src, srcUser, srcPrincipalNew); - updateBasePrincipal(dst, dstUser, dstPrincipalNew); - - if (srcBalance < 0) { - if (uint256(-srcBalance) < baseBorrowMin) revert BorrowTooSmall(); - if (!isBorrowCollateralized(src)) revert NotCollateralized(); - } - - if (withdrawAmount > 0) { - emit Transfer(src, address(0), presentValueSupply(baseSupplyIndex, withdrawAmount)); - } - - if (supplyAmount > 0) { - emit Transfer(address(0), dst, presentValueSupply(baseSupplyIndex, supplyAmount)); - } - } - - /** - * @dev Transfer an amount of collateral asset from src to dst - */ - function transferCollateral(address src, address dst, address asset, uint128 amount) internal { - uint128 srcCollateral = userCollateral[src][asset].balance; - uint128 dstCollateral = userCollateral[dst][asset].balance; - uint128 srcCollateralNew = srcCollateral - amount; - uint128 dstCollateralNew = dstCollateral + amount; - - userCollateral[src][asset].balance = srcCollateralNew; - userCollateral[dst][asset].balance = dstCollateralNew; - - AssetInfo memory assetInfo = getAssetInfoByAddress(asset); - updateAssetsIn(src, assetInfo, srcCollateral, srcCollateralNew); - updateAssetsIn(dst, assetInfo, dstCollateral, dstCollateralNew); - - // Note: no accrue interest, BorrowCF < LiquidationCF covers small changes - if (!isBorrowCollateralized(src)) revert NotCollateralized(); - - emit TransferCollateral(src, dst, asset, amount); - } - - /** - * @notice Withdraw an amount of asset from the protocol - * @param asset The asset to withdraw - * @param amount The quantity to withdraw - */ - function withdraw(address asset, uint amount) override external { - return withdrawInternal(msg.sender, msg.sender, msg.sender, asset, amount); - } - - /** - * @notice Withdraw an amount of asset to `to` - * @param to The recipient address - * @param asset The asset to withdraw - * @param amount The quantity to withdraw - */ - function withdrawTo(address to, address asset, uint amount) override external { - return withdrawInternal(msg.sender, msg.sender, to, asset, amount); - } - - /** - * @notice Withdraw an amount of asset from src to `to`, if allowed - * @param src The sender address - * @param to The recipient address - * @param asset The asset to withdraw - * @param amount The quantity to withdraw - */ - function withdrawFrom(address src, address to, address asset, uint amount) override external { - return withdrawInternal(msg.sender, src, to, asset, amount); - } - - /** - * @dev Withdraw either collateral or base asset, depending on the asset, if operator is allowed - * @dev Note: Specifying an `amount` of uint256.max will withdraw all of `src`'s accrued base balance - */ - function withdrawInternal(address operator, address src, address to, address asset, uint amount) internal nonReentrant { - if (isWithdrawPaused()) revert Paused(); - if (!hasPermission(src, operator)) revert Unauthorized(); - - if (asset == baseToken) { - if (amount == type(uint256).max) { - amount = balanceOf(src); - } - return withdrawBase(src, to, amount); - } else { - return withdrawCollateral(src, to, asset, safe128(amount)); - } - } - - /** - * @dev Withdraw an amount of base asset from src to `to`, borrowing if possible/necessary - */ - function withdrawBase(address src, address to, uint256 amount) internal { - accrueInternal(); - - UserBasic memory srcUser = userBasic[src]; - int104 srcPrincipal = srcUser.principal; - int256 srcBalance = presentValue(srcPrincipal) - signed256(amount); - int104 srcPrincipalNew = principalValue(srcBalance); - - (uint104 withdrawAmount, uint104 borrowAmount) = withdrawAndBorrowAmount(srcPrincipal, srcPrincipalNew); - - totalSupplyBase -= withdrawAmount; - totalBorrowBase += borrowAmount; - - updateBasePrincipal(src, srcUser, srcPrincipalNew); - - if (srcBalance < 0) { - if (uint256(-srcBalance) < baseBorrowMin) revert BorrowTooSmall(); - if (!isBorrowCollateralized(src)) revert NotCollateralized(); - } - - doTransferOut(baseToken, to, amount); - - emit Withdraw(src, to, amount); - - if (withdrawAmount > 0) { - emit Transfer(src, address(0), presentValueSupply(baseSupplyIndex, withdrawAmount)); - } - } - - /** - * @dev Withdraw an amount of collateral asset from src to `to` - */ - function withdrawCollateral(address src, address to, address asset, uint128 amount) internal { - uint128 srcCollateral = userCollateral[src][asset].balance; - uint128 srcCollateralNew = srcCollateral - amount; - - totalsCollateral[asset].totalSupplyAsset -= amount; - userCollateral[src][asset].balance = srcCollateralNew; - - AssetInfo memory assetInfo = getAssetInfoByAddress(asset); - updateAssetsIn(src, assetInfo, srcCollateral, srcCollateralNew); - - // Note: no accrue interest, BorrowCF < LiquidationCF covers small changes - if (!isBorrowCollateralized(src)) revert NotCollateralized(); - - doTransferOut(asset, to, amount); - - emit WithdrawCollateral(src, to, asset, amount); - } - - /** - * @notice Absorb a list of underwater accounts onto the protocol balance sheet - * @param absorber The recipient of the incentive paid to the caller of absorb - * @param accounts The list of underwater accounts to absorb - */ - function absorb(address absorber, address[] calldata accounts) override external { - if (isAbsorbPaused()) revert Paused(); - - uint startGas = gasleft(); - accrueInternal(); - for (uint i = 0; i < accounts.length; ) { - absorbInternal(absorber, accounts[i]); - unchecked { i++; } - } - uint gasUsed = startGas - gasleft(); - - // Note: liquidator points are an imperfect tool for governance, - // to be used while evaluating strategies for incentivizing absorption. - // Using gas price instead of base fee would more accurately reflect spend, - // but is also subject to abuse if refunds were to be given automatically. - LiquidatorPoints memory points = liquidatorPoints[absorber]; - points.numAbsorbs++; - points.numAbsorbed += safe64(accounts.length); - points.approxSpend += safe128(gasUsed * block.basefee); - liquidatorPoints[absorber] = points; - } - - /** - * @dev Transfer user's collateral and debt to the protocol itself. - */ - function absorbInternal(address absorber, address account) internal { - if (!isLiquidatable(account)) revert NotLiquidatable(); - - UserBasic memory accountUser = userBasic[account]; - int104 oldPrincipal = accountUser.principal; - int256 oldBalance = presentValue(oldPrincipal); - uint16 assetsIn = accountUser.assetsIn; - - uint256 basePrice = getPrice(baseTokenPriceFeed); - uint256 deltaValue = 0; - - for (uint8 i = 0; i < numAssets; ) { - if (isInAsset(assetsIn, i)) { - AssetInfo memory assetInfo = getAssetInfo(i); - address asset = assetInfo.asset; - uint128 seizeAmount = userCollateral[account][asset].balance; - userCollateral[account][asset].balance = 0; - totalsCollateral[asset].totalSupplyAsset -= seizeAmount; - - uint256 value = mulPrice(seizeAmount, getPrice(assetInfo.priceFeed), assetInfo.scale); - deltaValue += mulFactor(value, assetInfo.liquidationFactor); - - emit AbsorbCollateral(absorber, account, asset, seizeAmount, value); - } - unchecked { i++; } - } - - uint256 deltaBalance = divPrice(deltaValue, basePrice, uint64(baseScale)); - int256 newBalance = oldBalance + signed256(deltaBalance); - // New balance will not be negative, all excess debt absorbed by reserves - if (newBalance < 0) { - newBalance = 0; - } - - int104 newPrincipal = principalValue(newBalance); - updateBasePrincipal(account, accountUser, newPrincipal); - - // reset assetsIn - userBasic[account].assetsIn = 0; - - (uint104 repayAmount, uint104 supplyAmount) = repayAndSupplyAmount(oldPrincipal, newPrincipal); - - // Reserves are decreased by increasing total supply and decreasing borrows - // the amount of debt repaid by reserves is `newBalance - oldBalance` - totalSupplyBase += supplyAmount; - totalBorrowBase -= repayAmount; - - uint256 basePaidOut = unsigned256(newBalance - oldBalance); - uint256 valueOfBasePaidOut = mulPrice(basePaidOut, basePrice, uint64(baseScale)); - emit AbsorbDebt(absorber, account, basePaidOut, valueOfBasePaidOut); - - if (newPrincipal > 0) { - emit Transfer(address(0), account, presentValueSupply(baseSupplyIndex, unsigned104(newPrincipal))); - } - } - - /** - * @notice Buy collateral from the protocol using base tokens, increasing protocol reserves - A minimum collateral amount should be specified to indicate the maximum slippage acceptable for the buyer. - * @param asset The asset to buy - * @param minAmount The minimum amount of collateral tokens that should be received by the buyer - * @param baseAmount The amount of base tokens used to buy the collateral - * @param recipient The recipient address - */ - function buyCollateral(address asset, uint minAmount, uint baseAmount, address recipient) override external nonReentrant { - if (isBuyPaused()) revert Paused(); - - int reserves = getReserves(); - if (reserves >= 0 && uint(reserves) >= targetReserves) revert NotForSale(); - - // Note: Re-entrancy can skip the reserves check above on a second buyCollateral call. - baseAmount = doTransferIn(baseToken, msg.sender, baseAmount); - - uint collateralAmount = quoteCollateral(asset, baseAmount); - if (collateralAmount < minAmount) revert TooMuchSlippage(); - if (collateralAmount > getCollateralReserves(asset)) revert InsufficientReserves(); - - // Note: Pre-transfer hook can re-enter buyCollateral with a stale collateral ERC20 balance. - // Assets should not be listed which allow re-entry from pre-transfer now, as too much collateral could be bought. - // This is also a problem if quoteCollateral derives its discount from the collateral ERC20 balance. - doTransferOut(asset, recipient, safe128(collateralAmount)); - - emit BuyCollateral(msg.sender, asset, baseAmount, collateralAmount); - } - - /** - * @notice Gets the quote for a collateral asset in exchange for an amount of base asset - * @param asset The collateral asset to get the quote for - * @param baseAmount The amount of the base asset to get the quote for - * @return The quote in terms of the collateral asset - */ - function quoteCollateral(address asset, uint baseAmount) override public view returns (uint) { - AssetInfo memory assetInfo = getAssetInfoByAddress(asset); - uint256 assetPrice = getPrice(assetInfo.priceFeed); - // Store front discount is derived from the collateral asset's liquidationFactor and storeFrontPriceFactor - // discount = storeFrontPriceFactor * (1e18 - liquidationFactor) - uint256 discountFactor = mulFactor(storeFrontPriceFactor, FACTOR_SCALE - assetInfo.liquidationFactor); - uint256 assetPriceDiscounted = mulFactor(assetPrice, FACTOR_SCALE - discountFactor); - uint256 basePrice = getPrice(baseTokenPriceFeed); - // # of collateral assets - // = (TotalValueOfBaseAmount / DiscountedPriceOfCollateralAsset) * assetScale - // = ((basePrice * baseAmount / baseScale) / assetPriceDiscounted) * assetScale - return basePrice * baseAmount * assetInfo.scale / assetPriceDiscounted / baseScale; - } - - /** - * @notice Withdraws base token reserves if called by the governor - * @param to An address of the receiver of withdrawn reserves - * @param amount The amount of reserves to be withdrawn from the protocol - */ - function withdrawReserves(address to, uint amount) override external { - if (msg.sender != governor) revert Unauthorized(); - - int reserves = getReserves(); - if (reserves < 0 || amount > unsigned256(reserves)) revert InsufficientReserves(); - - doTransferOut(baseToken, to, amount); - - emit WithdrawReserves(to, amount); - } - - /** - * @notice Sets Comet's ERC20 allowance of an asset for a manager - * @dev Only callable by governor - * @dev Note: Setting the `asset` as Comet's address will allow the manager - * to withdraw from Comet's Comet balance - * @dev Note: For USDT, if there is non-zero prior allowance, it must be reset to 0 first before setting a new value in proposal - * @param asset The asset that the manager will gain approval of - * @param manager The account which will be allowed or disallowed - * @param amount The amount of an asset to approve - */ - function approveThis(address manager, address asset, uint amount) override external { - if (msg.sender != governor) revert Unauthorized(); - - IERC20NonStandard(asset).approve(manager, amount); - } - - /** - * @notice Get the total number of tokens in circulation - * @dev Note: uses updated interest indices to calculate - * @return The supply of tokens - **/ - function totalSupply() override external view returns (uint256) { - (uint64 baseSupplyIndex_, ) = accruedInterestIndices(getNowInternal() - lastAccrualTime); - return presentValueSupply(baseSupplyIndex_, totalSupplyBase); - } - - /** - * @notice Get the total amount of debt - * @dev Note: uses updated interest indices to calculate - * @return The amount of debt - **/ - function totalBorrow() override external view returns (uint256) { - (, uint64 baseBorrowIndex_) = accruedInterestIndices(getNowInternal() - lastAccrualTime); - return presentValueBorrow(baseBorrowIndex_, totalBorrowBase); - } - - /** - * @notice Query the current positive base balance of an account or zero - * @dev Note: uses updated interest indices to calculate - * @param account The account whose balance to query - * @return The present day base balance magnitude of the account, if positive - */ - function balanceOf(address account) override public view returns (uint256) { - (uint64 baseSupplyIndex_, ) = accruedInterestIndices(getNowInternal() - lastAccrualTime); - int104 principal = userBasic[account].principal; - return principal > 0 ? presentValueSupply(baseSupplyIndex_, unsigned104(principal)) : 0; - } - - /** - * @notice Query the current negative base balance of an account or zero - * @dev Note: uses updated interest indices to calculate - * @param account The account whose balance to query - * @return The present day base balance magnitude of the account, if negative - */ - function borrowBalanceOf(address account) override public view returns (uint256) { - (, uint64 baseBorrowIndex_) = accruedInterestIndices(getNowInternal() - lastAccrualTime); - int104 principal = userBasic[account].principal; - return principal < 0 ? presentValueBorrow(baseBorrowIndex_, unsigned104(-principal)) : 0; - } - - /** - * @notice Fallback to calling the extension delegate for everything else - */ - fallback() external payable { - address delegate = extensionDelegate; - assembly { - calldatacopy(0, 0, calldatasize()) - let result := delegatecall(gas(), delegate, 0, calldatasize(), 0, 0) - returndatacopy(0, 0, returndatasize()) - switch result - case 0 { revert(0, returndatasize()) } - default { return(0, returndatasize()) } - } - } -} \ No newline at end of file diff --git a/contracts/CometFactory.sol b/contracts/CometFactory.sol deleted file mode 100644 index e9f409aad..000000000 --- a/contracts/CometFactory.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.15; - -import "./Comet.sol"; -import "./CometConfiguration.sol"; - -contract CometFactory is CometConfiguration { - function clone(Configuration calldata config) external returns (address) { - return address(new Comet(config)); - } -} \ No newline at end of file diff --git a/contracts/Configurator.sol b/contracts/Configurator.sol index 374a753fa..05c505d51 100644 --- a/contracts/Configurator.sol +++ b/contracts/Configurator.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; -import "./CometFactory.sol"; +import "./CometFactoryWithExtendedAssetList.sol"; import "./CometConfiguration.sol"; import "./ConfiguratorStorage.sol"; import "./marketupdates/MarketAdminPermissionCheckerInterface.sol"; @@ -320,7 +320,7 @@ contract Configurator is ConfiguratorStorage { * @dev Note: Callable by anyone */ function deploy(address cometProxy) external returns (address) { - address newComet = CometFactory(factory[cometProxy]).clone(configuratorParams[cometProxy]); + address newComet = CometFactoryWithExtendedAssetList(factory[cometProxy]).clone(configuratorParams[cometProxy]); emit CometDeployed(cometProxy, newComet); return newComet; } diff --git a/contracts/marketupdates/ConfiguratorOld.sol b/contracts/marketupdates/ConfiguratorOld.sol index 470603627..e93da1c9e 100644 --- a/contracts/marketupdates/ConfiguratorOld.sol +++ b/contracts/marketupdates/ConfiguratorOld.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; -import "./../CometFactory.sol"; +import "./../CometFactoryWithExtendedAssetList.sol"; import "./../CometConfiguration.sol"; import "./../ConfiguratorStorage.sol"; @@ -336,7 +336,7 @@ contract ConfiguratorOld is ConfiguratorStorage { * @dev Note: Callable by anyone */ function deploy(address cometProxy) external returns (address) { - address newComet = CometFactory(factory[cometProxy]).clone(configuratorParams[cometProxy]); + address newComet = CometFactoryWithExtendedAssetList(factory[cometProxy]).clone(configuratorParams[cometProxy]); emit CometDeployed(cometProxy, newComet); return newComet; } diff --git a/contracts/test/CometHarness.sol b/contracts/test/CometHarness.sol deleted file mode 100644 index 6efc9559b..000000000 --- a/contracts/test/CometHarness.sol +++ /dev/null @@ -1,84 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.15; - -import "../Comet.sol"; - -contract CometHarness is Comet { - uint public nowOverride; - - constructor(Configuration memory config) Comet(config) {} - - function getNowInternal() override internal view returns (uint40) { - return nowOverride > 0 ? uint40(nowOverride) : super.getNowInternal(); - } - - function getNow() public view returns (uint40) { - return getNowInternal(); - } - - function setNow(uint now_) external { - nowOverride = now_; - } - - function setTotalsBasic(TotalsBasic memory totals) external { - baseSupplyIndex = totals.baseSupplyIndex; - baseBorrowIndex = totals.baseBorrowIndex; - trackingSupplyIndex = totals.trackingSupplyIndex; - trackingBorrowIndex = totals.trackingBorrowIndex; - totalSupplyBase = totals.totalSupplyBase; - totalBorrowBase = totals.totalBorrowBase; - lastAccrualTime = totals.lastAccrualTime; - } - - function setTotalsCollateral(address asset, TotalsCollateral memory totals) external { - totalsCollateral[asset] = totals; - } - - function setBasePrincipal(address account, int104 principal) external { - userBasic[account].principal = principal; - } - - function setCollateralBalance(address account, address asset, uint128 balance) external { - uint128 oldBalance = userCollateral[account][asset].balance; - userCollateral[account][asset].balance = balance; - AssetInfo memory assetInfo = getAssetInfoByAddress(asset); - updateAssetsIn(account, assetInfo, oldBalance, balance); - } - - function updateAssetsInExternal( - address account, - address asset, - uint128 initialUserBalance, - uint128 finalUserBalance - ) external { - AssetInfo memory assetInfo = getAssetInfoByAddress(asset); - updateAssetsIn(account, assetInfo, initialUserBalance, finalUserBalance); - } - - function getAssetList(address account) external view returns (address[] memory result) { - uint16 assetsIn = userBasic[account].assetsIn; - - uint8 count = 0; - for (uint8 i = 0; i < numAssets; i++) { - if (isInAsset(assetsIn, i)) { - count++; - } - } - - result = new address[](count); - - uint j = 0; - for (uint8 i = 0; i < numAssets; i++) { - if (isInAsset(assetsIn, i)) { - result[j] = getAssetInfo(i).asset; - j++; - } - } - - return result; - } - - function accrue() external { - accrueInternal(); - } -} \ No newline at end of file diff --git a/contracts/test/CometHarnessInterface.sol b/contracts/test/CometHarnessInterface.sol deleted file mode 100644 index a25855c57..000000000 --- a/contracts/test/CometHarnessInterface.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.15; - -import "../CometInterface.sol"; - -abstract contract CometHarnessInterface is CometInterface { - function accrue() virtual external; - function getNow() virtual external view returns (uint40); - function setNow(uint now_) virtual external; - function setTotalsBasic(TotalsBasic memory totals) virtual external; - function setTotalsCollateral(address asset, TotalsCollateral memory totals) virtual external; - function setBasePrincipal(address account, int104 principal) virtual external; - function setCollateralBalance(address account, address asset, uint128 balance) virtual external; - function updateAssetsInExternal(address account, address asset, uint128 initialUserBalance, uint128 finalUserBalance) virtual external; - function getAssetList(address account) virtual external view returns (address[] memory); -} diff --git a/contracts/test/EvilToken.sol b/contracts/test/EvilToken.sol index 5bc7826af..8f9320e6a 100644 --- a/contracts/test/EvilToken.sol +++ b/contracts/test/EvilToken.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.15; import "./../ERC20.sol"; -import "./../Comet.sol"; +import "./../CometWithExtendedAssetList.sol"; import "./FaucetToken.sol"; /** @@ -74,27 +74,27 @@ contract EvilToken is FaucetToken { function performAttack(address src, address dst, uint256 amount) internal returns (bool) { ReentryAttack memory reentryAttack = attack; if (reentryAttack.attackType == AttackType.TRANSFER_FROM) { - Comet(payable(msg.sender)).transferFrom( + CometWithExtendedAssetList(payable(msg.sender)).transferFrom( reentryAttack.source, reentryAttack.destination, reentryAttack.amount ); } else if (reentryAttack.attackType == AttackType.WITHDRAW_FROM) { - Comet(payable(msg.sender)).withdrawFrom( + CometWithExtendedAssetList(payable(msg.sender)).withdrawFrom( reentryAttack.source, reentryAttack.destination, reentryAttack.asset, reentryAttack.amount ); } else if (reentryAttack.attackType == AttackType.SUPPLY_FROM) { - Comet(payable(msg.sender)).supplyFrom( + CometWithExtendedAssetList(payable(msg.sender)).supplyFrom( reentryAttack.source, reentryAttack.destination, reentryAttack.asset, reentryAttack.amount ); } else if (reentryAttack.attackType == AttackType.BUY_COLLATERAL) { - Comet(payable(msg.sender)).buyCollateral( + CometWithExtendedAssetList(payable(msg.sender)).buyCollateral( reentryAttack.asset, 0, reentryAttack.amount, diff --git a/deployments/fuji/usdc/configuration.json b/deployments/fuji/usdc/configuration.json deleted file mode 100644 index 29cd80c46..000000000 --- a/deployments/fuji/usdc/configuration.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "Compound USDC", - "symbol": "cUSDCv3", - "baseToken": "USDC", - "baseTokenPriceFeed": "0x7898AcCC83587C3C55116c5230C17a6Cd9C71bad", - "borrowMin": "1000e6", - "storeFrontPriceFactor": 0.5, - "targetReserves": "5000000e6", - "rates": { - "supplyKink": 0.8, - "supplySlopeLow": 0.0325, - "supplySlopeHigh": 0.4, - "supplyBase": 0, - "borrowKink": 0.8, - "borrowSlopeLow": 0.035, - "borrowSlopeHigh": 0.25, - "borrowBase": 0.015 - }, - "tracking": { - "indexScale": "1e15", - "baseSupplySpeed": "0.000011574074074074073e15", - "baseBorrowSpeed": "0.0011458333333333333e15", - "baseMinForRewards": "1000000e6" - }, - "assets": { - "WBTC.e": { - "priceFeed": "0x31CF013A08c6Ac228C94551d535d5BAfE19c602a", - "decimals": "8", - "borrowCF": 0.7, - "liquidateCF": 0.75, - "liquidationFactor": 0.93, - "supplyCap": "35000e8" - }, - "WAVAX": { - "priceFeed": "0x5498BB86BC934c8D34FDA08E81D444153d0D06aD", - "decimals": "18", - "borrowCF": 0.82, - "liquidateCF": 0.85, - "liquidationFactor": 0.93, - "supplyCap": "1000000e18" - } - } -} diff --git a/deployments/fuji/usdc/deploy.ts b/deployments/fuji/usdc/deploy.ts deleted file mode 100644 index 0dac217fe..000000000 --- a/deployments/fuji/usdc/deploy.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { Deployed, DeploymentManager } from '../../../plugins/deployment_manager/DeploymentManager'; -import { Fauceteer, ProxyAdmin } from '../../../build/types'; -import { DeploySpec, cloneGov, deployComet, exp, sameAddress, wait } from '../../../src/deploy'; - -const cloneNetwork = 'avalanche'; -const clone = { - usdcImpl: '0xa3fa3d254bf6af295b5b22cc6730b04144314890', - usdcProxy: '0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e', - wbtc: '0x50b7545627a5162f82a992c33b87adc75187b218', - wavax: '0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7', -}; - -export default async function deploy(deploymentManager: DeploymentManager, deploySpec: DeploySpec): Promise { - const deployed = await deployContracts(deploymentManager, deploySpec); - await mintTokens(deploymentManager); - return deployed; -} - -async function deployContracts(deploymentManager: DeploymentManager, deploySpec: DeploySpec): Promise { - const trace = deploymentManager.tracer(); - const ethers = deploymentManager.hre.ethers; - const signer = await deploymentManager.getSigner(); - - // Deploy governance contracts - const { fauceteer, governor, timelock } = await cloneGov(deploymentManager); - - const usdcProxyAdmin = await deploymentManager.deploy('USDC:admin', 'vendor/proxy/transparent/ProxyAdmin.sol', []); - const usdcImpl = await deploymentManager.clone('USDC:implementation', clone.usdcImpl, [], cloneNetwork); - const usdcProxy = await deploymentManager.clone('USDC', clone.usdcProxy, [usdcImpl.address], cloneNetwork); - const usdcProxyAdminSlot = '0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b'; - const USDC = usdcImpl.attach(usdcProxy.address); - - await deploymentManager.idempotent( - async () => !sameAddress(await ethers.provider.getStorageAt(usdcProxy.address, usdcProxyAdminSlot), usdcProxyAdmin.address), - async () => { - trace(`Changing admin of USDC proxy to ${usdcProxyAdmin.address}`); - trace(await wait(usdcProxy.connect(signer).changeAdmin(usdcProxyAdmin.address))); - - trace(`Initializing USDC`); - trace(await wait(USDC.connect(signer).initialize( - 'USD Coin', // name - 'USDC', // symbol - 'USD', // currency - 6, // decimals - signer.address, // Master Minter - signer.address, // Pauser - signer.address, // Blacklister - signer.address // Owner - ))); - } - ); - - const WBTC = await deploymentManager.clone('WBTC.e', clone.wbtc, [], cloneNetwork); - const WAVAX = await deploymentManager.clone('WAVAX', clone.wavax, [], cloneNetwork); - - // Deploy all Comet-related contracts - const deployed = await deployComet(deploymentManager, deploySpec); - - // TODO: Bulker for Avalanche - - return { ...deployed, fauceteer }; -} - -async function mintTokens(deploymentManager: DeploymentManager) { - const trace = deploymentManager.tracer(); - const signer = await deploymentManager.getSigner(); - const contracts = await deploymentManager.contracts(); - const timelock = contracts.get('timelock'); - const fauceteer = contracts.get('fauceteer'); - - trace(`Attempting to mint as ${signer.address}...`); - - const WAVAX = contracts.get('WAVAX'); - await deploymentManager.idempotent( - async () => (await WAVAX.balanceOf(signer.address)).lt(exp(0.01, 18)), - async () => { - trace(`Minting 0.01 WAVAX for signer (this is a precious resource!)`); - trace(await wait(WAVAX.connect(signer).deposit({ value: exp(0.01, 18) }))); - trace(`WAVAX.balanceOf(${signer.address}): ${await WAVAX.balanceOf(signer.address)}`); - } - ); - - // If we haven't spidered new contracts (which we could before minting, but its slow), - // then the proxy contract won't have the impl functions yet, so just do it explicitly - const usdcProxy = contracts.get('USDC'), usdcImpl = contracts.get('USDC:implementation'); - const USDC = usdcImpl.attach(usdcProxy.address); - await deploymentManager.idempotent( - async () => (await USDC.balanceOf(fauceteer.address)).eq(0), - async () => { - trace(`Minting 100M USDC to fauceteer`); - const amount = exp(100_000_000, await USDC.decimals()); - trace(await wait(USDC.connect(signer).configureMinter(signer.address, amount))); - trace(await wait(USDC.connect(signer).mint(fauceteer.address, amount))); - trace(`USDC.balanceOf(${fauceteer.address}): ${await USDC.balanceOf(fauceteer.address)}`); - } - ); - - const WBTC = contracts.get('WBTC.e'); - await deploymentManager.idempotent( - async () => (await WBTC.balanceOf(fauceteer.address)).eq(0), - async () => { - trace(`Minting 10000 WBTC to fauceteer`); - const amount = exp(10000, await WBTC.decimals()); - const feeAddress = '0x0000000000000000000000000000000000000000'; - const feeAmount = 0; - const originTxId = '0x0000000000000000000000000000000000000000000000000000000000000000'; - trace(await wait(WBTC.connect(signer).mint(fauceteer.address, amount, feeAddress, feeAmount, originTxId))); - trace(`WBTC.balanceOf(${fauceteer.address}): ${await WBTC.balanceOf(fauceteer.address)}`); - } - ); -} diff --git a/deployments/fuji/usdc/migrations/1665028496_absorb_transfer_event_and_auto_collateral.ts b/deployments/fuji/usdc/migrations/1665028496_absorb_transfer_event_and_auto_collateral.ts deleted file mode 100644 index c58d98206..000000000 --- a/deployments/fuji/usdc/migrations/1665028496_absorb_transfer_event_and_auto_collateral.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { DeploymentManager, migration } from '../../../../plugins/deployment_manager'; -import { calldata, exp, proposal } from '../../../../src/deploy'; - -import { expect } from 'chai'; - -export default migration('1665028496_absorb_transfer_event_and_auto_collateral', { - async prepare(deploymentManager: DeploymentManager) { - const cometFactory = await deploymentManager.deploy('cometFactory', 'CometFactory.sol', [], true); - return { newFactoryAddress: cometFactory.address }; - }, - - async enact(deploymentManager: DeploymentManager, { newFactoryAddress }) { - const trace = deploymentManager.tracer(); - const ethers = deploymentManager.hre.ethers; - - const { - governor, - comet, - configurator, - cometAdmin, - COMP, - } = await deploymentManager.getContracts(); - - const actions = [ - // 1. Set comet factory to newly deployed factory - { - contract: configurator, - signature: 'setFactory(address,address)', - args: [comet.address, newFactoryAddress], - }, - - // 2. Deploy and upgrade to a new version of Comet - { - contract: cometAdmin, - signature: 'deployAndUpgradeTo(address,address)', - args: [configurator.address, comet.address], - }, - ]; - const description = "# Liquidation Event Handling And Collateral Reserves\n"; - const txn = await deploymentManager.retry( - async () => governor.propose(...await proposal(actions, description)) - ); - trace(txn); - - const event = (await txn.wait()).events.find(event => event.event === 'ProposalCreated'); - const [proposalId] = event.args; - trace(`Created proposal ${proposalId}.`); - }, - - async enacted(deploymentManager: DeploymentManager): Promise { - return true; - }, - - async verify(deploymentManager: DeploymentManager) { - // 1. & 2. - // added a scenario to check for new Transfer event - } -}); diff --git a/deployments/fuji/usdc/roots.json b/deployments/fuji/usdc/roots.json deleted file mode 100644 index 6cbfba775..000000000 --- a/deployments/fuji/usdc/roots.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "comet": "0x59BF4753899C20EA152dEefc6f6A14B2a5CC3021", - "configurator": "0x8c083632099CBA949EA61A3044DB1B5A27818b20", - "rewards": "0x7CA364f9C4257FE2E22d503dD0E3f1c1Db41591d", - "fauceteer": "0x45D3465046B72D319ef0090b431678b160B1e628" -} \ No newline at end of file diff --git a/deployments/hardhat/dai/deploy.ts b/deployments/hardhat/dai/deploy.ts index 0d6bde034..bdc4548d7 100644 --- a/deployments/hardhat/dai/deploy.ts +++ b/deployments/hardhat/dai/deploy.ts @@ -63,7 +63,7 @@ export default async function deploy(deploymentManager: DeploymentManager, deplo const deployed = await deployComet(deploymentManager, deploySpec, { baseTokenPriceFeed: daiPriceFeed.address, assetConfigs: [assetConfig0, assetConfig1], - }, true); + }); const { rewards } = deployed; await deploymentManager.idempotent( diff --git a/deployments/relations.ts b/deployments/relations.ts index 0f5b038ea..6d1ea6384 100644 --- a/deployments/relations.ts +++ b/deployments/relations.ts @@ -119,7 +119,7 @@ const relationConfigMap: RelationConfigMap = { }, }, 'comet:implementation': { - artifact: 'contracts/Comet.sol:Comet', + artifact: 'contracts/CometWithExtendedAssetList.sol:CometWithExtendedAssetList', delegates: { field: async (comet) => comet.extensionDelegate(), }, diff --git a/deployments/sepolia/usdc/configuration.json b/deployments/sepolia/usdc/configuration.json deleted file mode 100644 index ba11cc45b..000000000 --- a/deployments/sepolia/usdc/configuration.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "name": "Compound USDC", - "symbol": "cUSDCv3", - "baseToken": "USDC", - "baseTokenAddress": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", - "baseTokenPriceFeed": "0xA2F78ab2355fe2f984D808B5CeE7FD0A93D5270E", - "pauseGuardian": "0x008a4C5448ac1Df676d6F39A0C6F13b21b189389", - "borrowMin": "1e0", - "storeFrontPriceFactor": 0.5, - "targetReserves": "5000000e6", - "rates": { - "supplyKink": 0.85, - "supplySlopeLow": 0.048, - "supplySlopeHigh": 1.6, - "supplyBase": 0, - "borrowKink": 0.85, - "borrowSlopeLow": 0.053, - "borrowSlopeHigh": 1.7, - "borrowBase": 0.015 - }, - "tracking": { - "indexScale": "1e15", - "baseSupplySpeed": "0.000011574074074074073e15", - "baseBorrowSpeed": "0.0011458333333333333e15", - "baseMinForRewards": "100e6" - }, - "rewardToken": "COMP", - "assets": { - "COMP": { - "priceFeed": "0x619db7F74C0061E2917D1D57f834D9D24C5529dA", - "decimals": "18", - "borrowCF": 0.65, - "liquidateCF": 0.7, - "liquidationFactor": 0.92, - "supplyCap": "500000e18" - }, - "WBTC": { - "priceFeed": "0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43", - "decimals": "8", - "borrowCF": 0.7, - "liquidateCF": 0.75, - "liquidationFactor": 0.93, - "supplyCap": "35000e8" - }, - "WETH": { - "priceFeed": "0x694AA1769357215DE4FAC081bf1f309aDC325306", - "decimals": "18", - "borrowCF": 0.82, - "liquidateCF": 0.85, - "liquidationFactor": 0.93, - "supplyCap": "1000000e18" - } - } -} \ No newline at end of file diff --git a/deployments/sepolia/usdc/deploy.ts b/deployments/sepolia/usdc/deploy.ts deleted file mode 100644 index c61cffd82..000000000 --- a/deployments/sepolia/usdc/deploy.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { Deployed, DeploymentManager } from '../../../plugins/deployment_manager'; -import { DeploySpec, cloneGov, deployComet, exp, sameAddress, wait } from '../../../src/deploy'; - -const clone = { - wbtc: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', - weth: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' -}; - -export default async function deploy(deploymentManager: DeploymentManager, deploySpec: DeploySpec): Promise { - const deployed = await deployContracts(deploymentManager, deploySpec); - await mintTokens(deploymentManager); - return deployed; -} - -async function deployContracts(deploymentManager: DeploymentManager, deploySpec: DeploySpec): Promise { - const trace = deploymentManager.tracer() - const signer = await deploymentManager.getSigner(); - - // Deploy governance contracts - const { COMP, fauceteer, timelock } = await cloneGov(deploymentManager); - - // Clone collateral assets from mainnet - const WBTC = await deploymentManager.clone('WBTC', clone.wbtc, []); - const WETH = await deploymentManager.clone('WETH', clone.weth, []); - - // Deploy all Comet-related contracts - const deployed = await deployComet(deploymentManager, deploySpec, {}, true); - const { rewards } = deployed; - - // Deploy Bulker - const bulker = await deploymentManager.deploy( - 'bulker', - 'bulkers/BaseBulker.sol', - [timelock.address, WETH.address] - ); - - await deploymentManager.idempotent( - async () => (await COMP.balanceOf(rewards.address)).eq(0), - async () => { - trace(`Sending some COMP to CometRewards`); - const amount = exp(1_000_000, 18); - trace(await wait(COMP.connect(signer).transfer(rewards.address, amount))); - trace(`COMP.balanceOf(${rewards.address}): ${await COMP.balanceOf(rewards.address)}`); - trace(`COMP.balanceOf(${signer.address}): ${await COMP.balanceOf(signer.address)}`); - } - ); - - return { ...deployed, fauceteer, bulker }; -} - -async function mintTokens(deploymentManager: DeploymentManager) { - const trace = deploymentManager.tracer(); - const signer = await deploymentManager.getSigner(); - const contracts = await deploymentManager.contracts(); - const fauceteer = contracts.get('fauceteer'); - - trace(`Attempting to mint as ${signer.address}...`); - - const WETH = contracts.get('WETH'); - await deploymentManager.idempotent( - async () => (await WETH.balanceOf(signer.address)).lt(exp(0.01, 18)), - async () => { - trace(`Minting 0.01 WETH for signer (this is a precious resource!)`); - trace(await wait(WETH.connect(signer).deposit({ value: exp(0.01, 18) }))); - trace(`WETH.balanceOf(${signer.address}): ${await WETH.balanceOf(signer.address)}`); - } - ); - - const WBTC = contracts.get('WBTC'); - await deploymentManager.idempotent( - async () => (await WBTC.balanceOf(fauceteer.address)).eq(0), - async () => { - trace(`Minting 20 WBTC to fauceteer`); - const amount = exp(20, await WBTC.decimals()); - trace(await wait(WBTC.connect(signer).mint(fauceteer.address, amount))); - trace(`WBTC.balanceOf(${fauceteer.address}): ${await WBTC.balanceOf(fauceteer.address)}`); - } - ); -} \ No newline at end of file diff --git a/deployments/sepolia/usdc/relations.ts b/deployments/sepolia/usdc/relations.ts deleted file mode 100644 index bfe55f023..000000000 --- a/deployments/sepolia/usdc/relations.ts +++ /dev/null @@ -1,91 +0,0 @@ -import baseRelationConfig from '../../relations'; - -export default { - ...baseRelationConfig, - // USDC / USD price feed - '0xa2f78ab2355fe2f984d808b5cee7fd0a93d5270e': { - artifact: 'contracts/IPriceFeed.sol:IPriceFeed' - }, - // WBTC / USD price feed - '0x1b44f3514812d835eb1bdb0acb33d3fa3351ee43': { - artifact: 'contracts/IPriceFeed.sol:IPriceFeed' - }, - // WETH / USD price feed - '0x694aa1769357215de4fac081bf1f309adc325306': { - artifact: 'contracts/IPriceFeed.sol:IPriceFeed' - }, - fxRoot: { - relations: { - stateSender: { - field: async fxRoot => fxRoot.stateSender() - } - } - }, - arbitrumInbox: { - delegates: { - field: { - slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' - } - }, - relations: { - arbitrumBridge: { - field: async inbox => inbox.bridge() - } - } - }, - arbitrumL1GatewayRouter: { - delegates: { - field: { - slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' - } - } - }, - baseL1CrossDomainMessenger: { - delegates: { - // Not great, but this address shouldn't change and is very difficult to grab on-chain (private methods) - field: async () => '0xa042e16781484716c1Ef448c919af7BCd9607467' - } - }, - baseL1StandardBridge: { - delegates: { - field: { - slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' - } - } - }, - lineaMessageService: { - artifact: 'contracts/bridges/linea/IMessageService.sol:IMessageService', - // delegates: { - // field: { - // slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' - // } - // } - }, - lineaL1TokenBridge: { - delegates: { - field: { - slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' - } - } - }, - lineaL1usdcBridge: { - delegates: { - field: { - slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' - } - } - }, - unichainSepoliaL1CrossDomainMessenger: { - delegates: { - field: async () => '0x61e0DA8FEC03C5e3252D742e78534CE24B82634e' - } - }, - unichainSepoliaL1StandardBridge: { - delegates: { - field: { - slot: - '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' - } - } - }, -}; diff --git a/deployments/sepolia/usdc/roots.json b/deployments/sepolia/usdc/roots.json deleted file mode 100644 index 2df1bdf56..000000000 --- a/deployments/sepolia/usdc/roots.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "comet": "0xAec1F48e02Cfb822Be958B68C7957156EB3F0b6e", - "configurator": "0xc28aD44975C614EaBe0Ed090207314549e1c6624", - "rewards": "0x8bF5b658bdF0388E8b482ED51B14aef58f90abfD", - "fauceteer": "0x68793eA49297eB75DFB4610B68e076D2A5c7646C", - "bulker": "0x157c001bb1F8b33743B14483Be111C961d8e11dE" -} \ No newline at end of file diff --git a/deployments/sepolia/weth/configuration.json b/deployments/sepolia/weth/configuration.json deleted file mode 100644 index 11f104aa9..000000000 --- a/deployments/sepolia/weth/configuration.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "name": "Compound WETH", - "symbol": "cWETHv3", - "baseToken": "WETH", - "baseTokenAddress": "0x2D5ee574e710219a521449679A4A7f2B43f046ad", - "borrowMin": "1e12", - "governor": "0x54a06047087927D9B0fb21c1cf0ebd792764dDB8", - "pauseGuardian": "0x008a4C5448ac1Df676d6F39A0C6F13b21b189389", - "storeFrontPriceFactor": 0.5, - "targetReserves": "5000e18", - "rates": { - "supplyKink": 0.9, - "supplySlopeLow": 0.01690681444, - "supplySlopeHigh": 0.6066567706, - "supplyBase": 0, - "borrowKink": 0.9, - "borrowSlopeLow": 0.05171500002, - "borrowSlopeHigh": 0.5171500339, - "borrowBase": 0.009945209674 - }, - "tracking": { - "indexScale": "1e15", - "baseSupplySpeed": "0.000011574074074074073e15", - "baseBorrowSpeed": "0e15", - "baseMinForRewards": "0.1e18" - }, - "assets": { - "cbETH": { - "decimals": "18", - "borrowCF": 0.90, - "liquidateCF": 0.93, - "liquidationFactor": 0.95, - "supplyCap": "9_000e18" - }, - "wstETH": { - "address": "0xB82381A3fBD3FaFA77B3a7bE693342618240067b", - "decimals": "18", - "borrowCF": 0.90, - "liquidateCF": 0.93, - "liquidationFactor": 0.95, - "supplyCap": "80_000e18" - } - } -} \ No newline at end of file diff --git a/deployments/sepolia/weth/deploy.ts b/deployments/sepolia/weth/deploy.ts deleted file mode 100644 index beabff24c..000000000 --- a/deployments/sepolia/weth/deploy.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { Deployed, DeploymentManager } from '../../../plugins/deployment_manager'; -import { debug, DeploySpec, deployComet, exp, sameAddress, wait } from '../../../src/deploy'; - -const clone = { - cbETHImpl: '0x31724cA0C982A31fbb5C57f4217AB585271fc9a5', - cbETHProxy: '0xBe9895146f7AF43049ca1c1AE358B0541Ea49704', -}; - -export default async function deploy(deploymentManager: DeploymentManager, deploySpec: DeploySpec): Promise { - const deployed = await deployContracts(deploymentManager, deploySpec); - await mintTokens(deploymentManager); - return deployed; -} - -async function deployContracts(deploymentManager: DeploymentManager, deploySpec: DeploySpec): Promise { - const ethers = deploymentManager.hre.ethers; - const signer = await deploymentManager.getSigner(); - - // Declare existing assets as aliases - const WETH = await deploymentManager.existing('WETH', '0x2D5ee574e710219a521449679A4A7f2B43f046ad', 'sepolia'); - const wstETH = await deploymentManager.existing('wstETH', '0xB82381A3fBD3FaFA77B3a7bE693342618240067b', 'sepolia'); - - // Import shared contracts from cUSDCv3 - const cometAdmin = await deploymentManager.fromDep('cometAdmin', 'sepolia', 'usdc'); - const cometFactory = await deploymentManager.fromDep('cometFactory', 'sepolia', 'usdc'); - const $configuratorImpl = await deploymentManager.fromDep('configurator:implementation', 'sepolia', 'usdc'); - const configurator = await deploymentManager.fromDep('configurator', 'sepolia', 'usdc'); - const rewards = await deploymentManager.fromDep('rewards', 'sepolia', 'usdc'); - const fauceteer = await deploymentManager.fromDep('fauceteer', 'sepolia', 'usdc'); - - // Clone cbETH - const cbETHProxyAdmin = await deploymentManager.deploy('cbETH:admin', 'vendor/proxy/transparent/ProxyAdmin.sol', []); - const cbETHImpl = await deploymentManager.clone('cbETH:implementation', clone.cbETHImpl, []); - const cbETHProxy = await deploymentManager.clone('cbETH', clone.cbETHProxy, [cbETHImpl.address]); - const cbETHProxyAdminSlot = '0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b'; - const cbETH = cbETHImpl.attach(cbETHProxy.address); - await deploymentManager.idempotent( - async () => !sameAddress(await ethers.provider.getStorageAt(cbETHProxy.address, cbETHProxyAdminSlot), cbETHProxyAdmin.address), - async () => { - debug(`Changing admin of cbETH proxy to ${cbETHProxyAdmin.address}`); - await wait(cbETHProxy.connect(signer).changeAdmin(cbETHProxyAdmin.address)); - - debug(`Initializing cbETH`); - await wait(cbETH.connect(signer).initialize( - 'Coinbase Wrapped Staked ETH', // name - 'cbETH', // symbol - '', // currency - 18, // decimals - signer.address, // Master Minter - signer.address, // Pauser - signer.address, // Blacklister - signer.address // Owner - )); - } - ); - - // Deploy stETH / ETH SimplePriceFeed - const stETHtoETHPriceFeed = await deploymentManager.deploy( - 'stETHToETH:simplePriceFeed', - 'test/SimplePriceFeed.sol', - [ - exp(0.98882408, 18), // Latest answer on mainnet at block 16170924 - 18 - ] - ); - - // Deploy cbETH / ETH SimplePriceFeed - const cbETHtoETHPriceFeed = await deploymentManager.deploy( - 'cbETHToETH:simplePriceFeed', - 'test/SimplePriceFeed.sol', - [ - exp(0.97, 18), - 18 - ] - ); - - // Deploy WstETHPriceFeed - const wstETHPriceFeed = await deploymentManager.deploy( - 'wstETH:priceFeed', - 'pricefeeds/WstETHPriceFeed.sol', - [ - stETHtoETHPriceFeed.address, // stETH / ETH price feed - wstETH.address, // wstETH - 8 // decimals - ] - ); - - // Deploy constant price feed for WETH - const wethConstantPriceFeed = await deploymentManager.deploy( - 'WETH:priceFeed', - 'pricefeeds/ConstantPriceFeed.sol', - [ - 8, // decimals - exp(1, 8) // constantPrice - ] - ); - - // Deploy scaling price feed for cbETH - const cbETHScalingPriceFeed = await deploymentManager.deploy( - 'cbETH:priceFeed', - 'pricefeeds/ScalingPriceFeed.sol', - [ - cbETHtoETHPriceFeed.address, // cbETH / ETH price feed - 8 // decimals - ] - ); - - // Deploy all Comet-related contracts - const deployed = await deployComet(deploymentManager, deploySpec, {}, true); - const { comet } = deployed; - - // Deploy Bulker - const bulker = await deploymentManager.deploy( - 'bulker', - 'bulkers/MainnetBulker.sol', - [ - await comet.governor(), // admin_ - WETH.address, // weth_ - wstETH.address // wsteth_ - ] - ); - - return { ...deployed, bulker, fauceteer }; -} - -async function mintTokens(deploymentManager: DeploymentManager) { - const signer = await deploymentManager.getSigner(); - const contracts = await deploymentManager.contracts(); - const fauceteer = contracts.get('fauceteer')!; - - debug(`Attempting to mint as ${signer.address}...`); - - // If we haven't spidered new contracts (which we could before minting, but its slow), - // then the proxy contract won't have the impl functions yet, so just do it explicitly - const cbETHProxy = contracts.get('cbETH')!, cbETHImpl = contracts.get('cbETH:implementation')!; - const cbETH = cbETHImpl.attach(cbETHProxy.address); - await deploymentManager.idempotent( - async () => (await cbETH.balanceOf(fauceteer.address)).eq(0), - async () => { - debug(`Minting 1M cbETH to fauceteer`); - const amount = exp(1_000_000, await cbETH.decimals()); - await wait(cbETH.connect(signer).configureMinter(signer.address, amount)); - await wait(cbETH.connect(signer).mint(fauceteer.address, amount)); - debug(`cbETH.balanceOf(${fauceteer.address}): ${await cbETH.balanceOf(fauceteer.address)}`); - } - ); -} diff --git a/deployments/sepolia/weth/migrations/1709094543_initialize_market.ts b/deployments/sepolia/weth/migrations/1709094543_initialize_market.ts deleted file mode 100644 index 99515b5f3..000000000 --- a/deployments/sepolia/weth/migrations/1709094543_initialize_market.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { DeploymentManager, migration } from '../../../../plugins/deployment_manager'; -import { exp, getConfigurationStruct, proposal } from '../../../../src/deploy'; - -import { expect } from 'chai'; - -const COMPAddress = '0xA6c8D1c55951e8AC44a0EaA959Be5Fd21cc07531'; - -export default migration('1709094543_initialize_market', { - prepare: async (deploymentManager: DeploymentManager) => { - return {}; - }, - - enact: async (deploymentManager: DeploymentManager) => { - const trace = deploymentManager.tracer(); - - // Import shared contracts from cUSDCv3 - const cometFactory = await deploymentManager.fromDep('cometFactory', 'sepolia', 'usdc'); - - const { - governor, - comet, - configurator, - cometAdmin, - rewards, - } = await deploymentManager.getContracts(); - - const configuration = await getConfigurationStruct(deploymentManager); - - const actions = [ - // 1. Set the factory in the Configurator - { - contract: configurator, - signature: 'setFactory(address,address)', - args: [comet.address, cometFactory.address], - }, - - // 2. Set the configuration in the Configurator - { - contract: configurator, - signature: 'setConfiguration(address,(address,address,address,address,address,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint104,uint104,uint104,(address,address,uint8,uint64,uint64,uint64,uint128)[]))', - args: [comet.address, configuration], - }, - - // 3. Deploy and upgrade to a new version of Comet - { - contract: cometAdmin, - signature: "deployAndUpgradeTo(address,address)", - args: [configurator.address, comet.address], - }, - - // 4. Set the rewards configuration to COMP - { - contract: rewards, - signature: "setRewardConfig(address,address)", - args: [comet.address, COMPAddress], - }, - ]; - const description = "# Initialize cWETHv3 on Sepolia" - const txn = await deploymentManager.retry( - async () => trace((await governor.propose(...await proposal(actions, description)))) - ); - - const event = txn.events.find(event => event.event === 'ProposalCreated'); - const [proposalId] = event.args; - - trace(`Created proposal ${proposalId}.`); - }, - - async enacted(deploymentManager: DeploymentManager): Promise { - return true; - }, - - async verify(deploymentManager: DeploymentManager) { - const { - comet, - rewards, - wstETH, - cbETH, - } = await deploymentManager.getContracts(); - // 2. & 3. - expect(await comet.baseTrackingSupplySpeed()).to.be.equal(exp(1 / 86400, 15, 18)); // ~ 1 COMP / day - expect(await comet.baseTrackingBorrowSpeed()).to.be.equal(0); - - const wstETHInfo = await comet.getAssetInfoByAddress(wstETH.address); - expect(wstETHInfo.supplyCap).to.be.equal(exp(80_000, 18)); // ~ $100M / $1225 - - const cbETHInfo = await comet.getAssetInfoByAddress(cbETH.address); - expect(cbETHInfo.supplyCap).to.be.equal(exp(9_000, 18)); // ~ $10M / $1091 - - // 4. - const config = await rewards.rewardConfig(comet.address); - expect(config.token).to.be.equal(COMPAddress); - expect(config.rescaleFactor).to.be.equal(1000000000000n); - expect(config.shouldUpscale).to.be.equal(true); - }, -}); \ No newline at end of file diff --git a/deployments/sepolia/weth/relations.ts b/deployments/sepolia/weth/relations.ts deleted file mode 100644 index 13f315c2a..000000000 --- a/deployments/sepolia/weth/relations.ts +++ /dev/null @@ -1,13 +0,0 @@ -import baseRelationConfig from '../../relations'; - -export default { - ...baseRelationConfig, - 'wstETH': { - artifact: 'contracts/bulkers/IWstETH.sol', - relations: { - stETH: { - field: async (wstETH) => wstETH.stETH() - } - } - }, -}; diff --git a/deployments/sepolia/weth/roots.json b/deployments/sepolia/weth/roots.json deleted file mode 100644 index 825b5a431..000000000 --- a/deployments/sepolia/weth/roots.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "comet": "0x2943ac1216979aD8dB76D9147F64E61adc126e96", - "configurator": "0xc28aD44975C614EaBe0Ed090207314549e1c6624", - "rewards": "0x8bF5b658bdF0388E8b482ED51B14aef58f90abfD", - "bulker": "0xaD0C044425D81a2E223f4CE699156900fead2Aaa", - "fauceteer": "0x68793eA49297eB75DFB4610B68e076D2A5c7646C" -} \ No newline at end of file diff --git a/forge/script/marketupdates/helpers/ChainAddresses.sol b/forge/script/marketupdates/helpers/ChainAddresses.sol index 31236a4ea..936f90f46 100644 --- a/forge/script/marketupdates/helpers/ChainAddresses.sol +++ b/forge/script/marketupdates/helpers/ChainAddresses.sol @@ -19,7 +19,6 @@ library ChainAddresses { BASE, SCROLL, OPTIMISM, - MAINNET_SEPOLIA, LINEA, RONIN, UNICHAIN, @@ -263,8 +262,6 @@ library ChainAddresses { return Chain.SCROLL; } else if(chainId == 10) { return Chain.OPTIMISM; - } else if(chainId == 11155111) { - return Chain.MAINNET_SEPOLIA; } else if(chainId == 5000) { return Chain.MANTLE; } else { diff --git a/forge/test/Comet.t.sol b/forge/test/Comet.t.sol index 9428a501c..63e702352 100644 --- a/forge/test/Comet.t.sol +++ b/forge/test/Comet.t.sol @@ -2,14 +2,14 @@ pragma solidity ^0.8.13; import "forge-std/Test.sol"; -import "../../contracts/Comet.sol"; +import "../../contracts/CometWithExtendedAssetList.sol"; import "../../contracts/CometConfiguration.sol"; import { CometExtAssetList } from "../../contracts/CometExtAssetList.sol"; import { AssetListFactory } from "../../contracts/AssetListFactory.sol"; contract CometTest is Test { - Comet public comet; + CometWithExtendedAssetList public comet; function setUp() public { // XXX @@ -40,6 +40,6 @@ contract CometTest is Test { 0, assets); vm.expectRevert(); - comet = new Comet(config); + comet = new CometWithExtendedAssetList(config); } } diff --git a/forge/test/MarketUpdateArbitrumDeploymentTest.t.sol b/forge/test/MarketUpdateArbitrumDeploymentTest.t.sol index 38d0f1c34..f6cd1cd59 100644 --- a/forge/test/MarketUpdateArbitrumDeploymentTest.t.sol +++ b/forge/test/MarketUpdateArbitrumDeploymentTest.t.sol @@ -1,7 +1,7 @@ pragma solidity 0.8.15; import {Test} from "forge-std/Test.sol"; -import "@comet-contracts/Comet.sol"; +import "@comet-contracts/CometWithExtendedAssetList.sol"; import "@comet-contracts/marketupdates/MarketUpdateProposer.sol"; import "../script/marketupdates/helpers/GovernanceHelper.sol"; diff --git a/forge/test/MarketUpdateBaseDeploymentTest.t.sol b/forge/test/MarketUpdateBaseDeploymentTest.t.sol index f9fdf1ec4..241da2a77 100644 --- a/forge/test/MarketUpdateBaseDeploymentTest.t.sol +++ b/forge/test/MarketUpdateBaseDeploymentTest.t.sol @@ -1,7 +1,7 @@ pragma solidity 0.8.15; import {Test} from "forge-std/Test.sol"; -import "@comet-contracts/Comet.sol"; +import "@comet-contracts/CometWithExtendedAssetList.sol"; import "@comet-contracts/marketupdates/MarketUpdateProposer.sol"; import "../script/marketupdates/helpers/GovernanceHelper.sol"; diff --git a/forge/test/MarketUpdateDeploymentBaseTest.sol b/forge/test/MarketUpdateDeploymentBaseTest.sol index bca55156f..9682b9d97 100644 --- a/forge/test/MarketUpdateDeploymentBaseTest.sol +++ b/forge/test/MarketUpdateDeploymentBaseTest.sol @@ -120,7 +120,7 @@ abstract contract MarketUpdateDeploymentBaseTest is Test { address configuratorProxy = chainAddresses.configuratorProxyAddress; address cometProxyAdminNew = deployedContracts.newCometProxyAdmin; address marketUpdateProposer = deployedContracts.marketUpdateProposer; - uint256 oldSupplyKinkBeforeGovernorUpdate = Comet(payable(cometProxy)).supplyKink(); + uint256 oldSupplyKinkBeforeGovernorUpdate = CometWithExtendedAssetList(payable(cometProxy)).supplyKink(); uint256 newSupplyKinkByGovernorTimelock = 300000000000000000; assertEq(MarketAdminPermissionChecker(deployedContracts.marketAdminPermissionChecker).marketAdmin(), deployedContracts.marketUpdateTimelock); @@ -149,11 +149,11 @@ abstract contract MarketUpdateDeploymentBaseTest is Test { GovernanceHelper.createProposalAndPass(vm, proposalRequest, description); // check the new kink value - uint256 newSupplyKinkAfterGovernorUpdate = Comet(payable(cometProxy)).supplyKink(); + uint256 newSupplyKinkAfterGovernorUpdate = CometWithExtendedAssetList(payable(cometProxy)).supplyKink(); assert(newSupplyKinkAfterGovernorUpdate == newSupplyKinkByGovernorTimelock); // Setting new Supply Kink using Market Admin - uint256 oldSupplyKinkBeforeMarketAdminUpdate = Comet(payable(cometProxy)).supplyKink(); + uint256 oldSupplyKinkBeforeMarketAdminUpdate = CometWithExtendedAssetList(payable(cometProxy)).supplyKink(); uint256 newSupplyKinkByMarketAdmin = 400000000000000000; assert(oldSupplyKinkBeforeMarketAdminUpdate != newSupplyKinkByMarketAdmin); @@ -163,7 +163,7 @@ abstract contract MarketUpdateDeploymentBaseTest is Test { description = string(abi.encodePacked("Proposal to update Supply Kink for ", marketName, " Market by Market Admin")); GovernanceHelper.createAndPassMarketUpdateProposal(vm, chainAddresses.marketAdmin, proposalRequest, description, marketUpdateProposer); - uint256 newSupplyKinkAfterMarketAdminUpdate = Comet(payable(cometProxy)).supplyKink(); + uint256 newSupplyKinkAfterMarketAdminUpdate = CometWithExtendedAssetList(payable(cometProxy)).supplyKink(); assert(newSupplyKinkAfterMarketAdminUpdate == newSupplyKinkByMarketAdmin); } @@ -181,7 +181,7 @@ abstract contract MarketUpdateDeploymentBaseTest is Test { address cometProxyAdminNew = deployedContracts.newCometProxyAdmin; address marketUpdateProposer = deployedContracts.marketUpdateProposer; - uint256 oldSupplyKinkBeforeGovernorUpdate = Comet(payable(cometProxy)).supplyKink(); + uint256 oldSupplyKinkBeforeGovernorUpdate = CometWithExtendedAssetList(payable(cometProxy)).supplyKink(); uint256 newSupplyKinkByGovernorTimelock = 300000000000000000; assert(oldSupplyKinkBeforeGovernorUpdate != newSupplyKinkByGovernorTimelock); @@ -210,11 +210,11 @@ abstract contract MarketUpdateDeploymentBaseTest is Test { BridgeHelper.simulateMessageAndExecuteProposal(vm, chain, MarketUpdateAddresses.GOVERNOR_BRAVO_TIMELOCK_ADDRESS, proposalRequest); // check the new kink value - uint256 newSupplyKinkAfterGovernorUpdate = Comet(payable(cometProxy)).supplyKink(); + uint256 newSupplyKinkAfterGovernorUpdate = CometWithExtendedAssetList(payable(cometProxy)).supplyKink(); assert(newSupplyKinkAfterGovernorUpdate == newSupplyKinkByGovernorTimelock); // Setting new Supply Kink using Market Admin - uint256 oldSupplyKinkBeforeMarketAdminUpdate = Comet(payable(cometProxy)).supplyKink(); + uint256 oldSupplyKinkBeforeMarketAdminUpdate = CometWithExtendedAssetList(payable(cometProxy)).supplyKink(); uint256 newSupplyKinkByMarketAdmin = 400000000000000000; assert(oldSupplyKinkBeforeMarketAdminUpdate != newSupplyKinkByMarketAdmin); @@ -224,7 +224,7 @@ abstract contract MarketUpdateDeploymentBaseTest is Test { description = string(abi.encodePacked("Proposal to update Supply Kink for ", marketName, " Market by Market Admin")); GovernanceHelper.createAndPassMarketUpdateProposalL2(vm, chainAddresses.marketAdmin, proposalRequest, description, marketUpdateProposer); - uint256 newSupplyKinkAfterMarketAdminUpdate = Comet(payable(cometProxy)).supplyKink(); + uint256 newSupplyKinkAfterMarketAdminUpdate = CometWithExtendedAssetList(payable(cometProxy)).supplyKink(); assert(newSupplyKinkAfterMarketAdminUpdate == newSupplyKinkByMarketAdmin); } } diff --git a/forge/test/MarketUpdateMainnetDeploymentTest.t.sol b/forge/test/MarketUpdateMainnetDeploymentTest.t.sol index 9daf536be..f4cb23052 100644 --- a/forge/test/MarketUpdateMainnetDeploymentTest.t.sol +++ b/forge/test/MarketUpdateMainnetDeploymentTest.t.sol @@ -1,7 +1,7 @@ pragma solidity 0.8.15; import {Test} from "forge-std/Test.sol"; -import "@comet-contracts/Comet.sol"; +import "@comet-contracts/CometWithExtendedAssetList.sol"; import "@comet-contracts/marketupdates/MarketUpdateProposer.sol"; import "../script/marketupdates/helpers/GovernanceHelper.sol"; diff --git a/forge/test/MarketUpdateMantleDeploymentTest.t.sol b/forge/test/MarketUpdateMantleDeploymentTest.t.sol index 844f905ed..ca0aefb78 100644 --- a/forge/test/MarketUpdateMantleDeploymentTest.t.sol +++ b/forge/test/MarketUpdateMantleDeploymentTest.t.sol @@ -1,7 +1,7 @@ pragma solidity 0.8.15; import {Test} from "forge-std/Test.sol"; -import "@comet-contracts/Comet.sol"; +import "@comet-contracts/CometWithExtendedAssetList.sol"; import "@comet-contracts/marketupdates/MarketUpdateProposer.sol"; import "../script/marketupdates/helpers/GovernanceHelper.sol"; diff --git a/forge/test/MarketUpdateOptimismDeploymentTest.t.sol b/forge/test/MarketUpdateOptimismDeploymentTest.t.sol index 26bf5e25b..4e13a3256 100644 --- a/forge/test/MarketUpdateOptimismDeploymentTest.t.sol +++ b/forge/test/MarketUpdateOptimismDeploymentTest.t.sol @@ -1,7 +1,7 @@ pragma solidity 0.8.15; import {Test} from "forge-std/Test.sol"; -import "@comet-contracts/Comet.sol"; +import "@comet-contracts/CometWithExtendedAssetList.sol"; import "@comet-contracts/marketupdates/MarketUpdateProposer.sol"; import "../script/marketupdates/helpers/GovernanceHelper.sol"; diff --git a/forge/test/MarketUpdatePolygonDeploymentTest.t.sol b/forge/test/MarketUpdatePolygonDeploymentTest.t.sol index 7337ded5b..9fb9044f6 100644 --- a/forge/test/MarketUpdatePolygonDeploymentTest.t.sol +++ b/forge/test/MarketUpdatePolygonDeploymentTest.t.sol @@ -1,7 +1,7 @@ pragma solidity 0.8.15; import {Test} from "forge-std/Test.sol"; -import "@comet-contracts/Comet.sol"; +import "@comet-contracts/CometWithExtendedAssetList.sol"; import "@comet-contracts/marketupdates/MarketUpdateProposer.sol"; import "../script/marketupdates/helpers/GovernanceHelper.sol"; diff --git a/forge/test/MarketUpdateScrollDeploymentTest.t.sol b/forge/test/MarketUpdateScrollDeploymentTest.t.sol index 5e185cfab..b8e7b40e5 100644 --- a/forge/test/MarketUpdateScrollDeploymentTest.t.sol +++ b/forge/test/MarketUpdateScrollDeploymentTest.t.sol @@ -1,7 +1,7 @@ pragma solidity 0.8.15; import {Test} from "forge-std/Test.sol"; -import "@comet-contracts/Comet.sol"; +import "@comet-contracts/CometWithExtendedAssetList.sol"; import "@comet-contracts/marketupdates/MarketUpdateProposer.sol"; import "../script/marketupdates/helpers/GovernanceHelper.sol"; diff --git a/forge/test/OnChainLiquidator.t.sol b/forge/test/OnChainLiquidator.t.sol index 6366705f6..0b9968b32 100644 --- a/forge/test/OnChainLiquidator.t.sol +++ b/forge/test/OnChainLiquidator.t.sol @@ -2,13 +2,13 @@ pragma solidity ^0.8.13; import "forge-std/Test.sol"; -import "../../contracts/Comet.sol"; +import "../../contracts/CometWithExtendedAssetList.sol"; import "../../contracts/CometConfiguration.sol"; import "../../contracts/liquidator/OnChainLiquidator.sol"; import "../../contracts/test/SimplePriceFeed.sol"; contract OnChainLiquidatorTest is Test { - Comet public comet; + CometWithExtendedAssetList public comet; OnChainLiquidator public liquidator; // contracts @@ -69,7 +69,7 @@ contract OnChainLiquidatorTest is Test { supplyCap: 0 }); - comet = new Comet(CometConfiguration.Configuration( + comet = new CometWithExtendedAssetList(CometConfiguration.Configuration( { governor: TIMELOCK, pauseGuardian: GNOSIS_SAFE, diff --git a/forge/test/PolygonLiquidator.t.sol b/forge/test/PolygonLiquidator.t.sol index d9ba16427..636f62fcc 100644 --- a/forge/test/PolygonLiquidator.t.sol +++ b/forge/test/PolygonLiquidator.t.sol @@ -2,13 +2,13 @@ pragma solidity ^0.8.13; import "forge-std/Test.sol"; -import "../../contracts/Comet.sol"; +import "../../contracts/CometWithExtendedAssetList.sol"; import "../../contracts/CometConfiguration.sol"; import "../../contracts/liquidator/OnChainLiquidator.sol"; import "../../contracts/test/SimplePriceFeed.sol"; contract PolygonLiquidatorTest is Test { - Comet public comet; + CometWithExtendedAssetList public comet; OnChainLiquidator public liquidator; // contracts @@ -84,7 +84,7 @@ contract PolygonLiquidatorTest is Test { supplyCap: 0 }); - comet = new Comet(CometConfiguration.Configuration( + comet = new CometWithExtendedAssetList(CometConfiguration.Configuration( { governor: TIMELOCK, pauseGuardian: GNOSIS_SAFE, diff --git a/foundry.toml b/foundry.toml index 3ea87d9cc..8fd39aa92 100644 --- a/foundry.toml +++ b/foundry.toml @@ -27,5 +27,4 @@ arbitrum = "${ARBITRUM_QUICKNODE_LINK}" optimism = "${OPTIMISM_QUICKNODE_LINK}" scroll = "${SCROLL_RPC_URL}" base = "${BASE_QUICKNODE_LINK}" -sepolia = "${SEPOLIA_RPC_URL}" mantle = "${MANTLE_QUICKNODE_LINK}" diff --git a/hardhat.config.ts b/hardhat.config.ts index b47fc5b71..a97d406b7 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -18,8 +18,6 @@ import './tasks/scenario/task.ts'; // Relation Config import relationConfigMap from './deployments/relations'; -import sepoliaUsdcRelationConfigMap from './deployments/sepolia/usdc/relations'; -import sepoliaWethRelationConfigMap from './deployments/sepolia/weth/relations'; import mainnetRelationConfigMap from './deployments/mainnet/usdc/relations'; import mainnetWethRelationConfigMap from './deployments/mainnet/weth/relations'; import mainnetUsdtRelationConfigMap from './deployments/mainnet/usdt/relations'; @@ -63,9 +61,7 @@ const { ETHERSCAN_KEY_FOR_ARBITRUM, ETHERSCAN_KEY_FOR_POLYGON, ETHERSCAN_KEY_FOR_LINEA, - SNOWTRACE_KEY, MAINNET_QUICKNODE_LINK, - SEPOLIA_QUICKNODE_LINK, RONIN_QUICKNODE_LINK, POLYGON_QUICKNODE_LINK, OPTIMISM_QUICKNODE_LINK, @@ -102,7 +98,6 @@ export function requireEnv(varName, msg?: string): string { // required environment variables [ 'ETHERSCAN_KEY', - 'SNOWTRACE_KEY', 'MAINNET_QUICKNODE_LINK', 'UNICHAIN_QUICKNODE_LINK', 'LINEA_QUICKNODE_LINK' @@ -136,11 +131,6 @@ export const networkConfigs: NetworkConfig[] = [ chainId: 1, url: `${MAINNET_QUICKNODE_LINK}`, }, - { - network: 'sepolia', - chainId: 11155111, - url: `${SEPOLIA_QUICKNODE_LINK}`, - }, { network: 'ronin', chainId: 2020, @@ -184,16 +174,6 @@ export const networkConfigs: NetworkConfig[] = [ chainId: 42161, url: `${ARBITRUM_QUICKNODE_LINK}`, }, - { - network: 'avalanche', - chainId: 43114, - url: 'https://api.avax.network/ext/bc/C/rpc', - }, - { - network: 'fuji', - chainId: 43113, - url: 'https://api.avax-test.network/ext/bc/C/rpc', - }, { network: 'scroll', chainId: 534352, @@ -244,18 +224,6 @@ const config: HardhatUserConfig = { }, networks: { - optimismSepolia: { - url: 'https://sepolia.optimism.io', - chainId: 11155420 - }, - arbitrumSepolia: { - url: 'https://arbitrum-sepolia.blockpi.network/v1/rpc/public', - chainId: 421614 - }, - mainnetSepolia: { - url: 'https://ethereum-sepolia.blockpi.network/v1/rpc/public', - chainId: 11155111 - }, hardhat: { chainId: 1337, loggingEnabled: !!process.env['LOGGING'], @@ -364,10 +332,6 @@ const config: HardhatUserConfig = { apiKey: { // Ethereum mainnet: ETHERSCAN_KEY, - sepolia: ETHERSCAN_KEY, - // Avalanche - avalanche: SNOWTRACE_KEY, - avalancheFujiTestnet: SNOWTRACE_KEY, // Polygon polygon: ETHERSCAN_KEY_FOR_POLYGON, // Arbitrum @@ -460,10 +424,6 @@ const config: HardhatUserConfig = { deploymentManager: { relationConfigMap, networks: { - sepolia: { - usdc: sepoliaUsdcRelationConfigMap, - weth: sepoliaWethRelationConfigMap - }, mainnet: { usdc: mainnetRelationConfigMap, weth: mainnetWethRelationConfigMap, @@ -553,21 +513,6 @@ const config: HardhatUserConfig = { network: 'hardhat', deployment: 'dai' }, - { - name: 'fuji', - network: 'fuji', - deployment: 'usdc' - }, - { - name: 'sepolia-usdc', - network: 'sepolia', - deployment: 'usdc' - }, - { - name: 'sepolia-weth', - network: 'sepolia', - deployment: 'weth' - }, { name: 'polygon', network: 'polygon', diff --git a/plugins/deployment_manager/test/DeploymentManagerTest.ts b/plugins/deployment_manager/test/DeploymentManagerTest.ts index e49d95a26..f47f6b4a7 100644 --- a/plugins/deployment_manager/test/DeploymentManagerTest.ts +++ b/plugins/deployment_manager/test/DeploymentManagerTest.ts @@ -10,7 +10,6 @@ import { import { getBuildFile } from '../ContractMap'; import { DeploymentManager } from '../DeploymentManager'; -import { fiatTokenBuildFile, mockImportSuccess } from './ImportTest'; import { Migration } from '../Migration'; import { expectedTemplate } from './MigrationTemplateTest'; import { buildToken, faucetTokenBuildFile, tokenArgs } from './DeployHelpers'; @@ -87,23 +86,6 @@ describe('DeploymentManager', () => { nock.disableNetConnect(); }); - describe('import', () => { - // Skipping since this test fails a lot due to limits - // and import is well-covered as everything else relies upon it - it.skip('should import succesfully', async () => { - mockImportSuccess('0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e'); - let deploymentManager = new DeploymentManager('avalanche', 'frax', hre, { - importRetries: 0, - writeCacheToDisk: true, - baseDir: tempDir(), - }); - let importResult = await deploymentManager.import( - '0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e', - ); - expect(importResult).to.eql(fiatTokenBuildFile); - }); - }); - describe('deploy', () => { it('should deploy succesfully', async () => { let deploymentManager = new DeploymentManager('test-network', 'test-deployment', hre, { diff --git a/plugins/deployment_manager/test/ImportTest.ts b/plugins/deployment_manager/test/ImportTest.ts index c6017dea5..1e78a4f8f 100644 --- a/plugins/deployment_manager/test/ImportTest.ts +++ b/plugins/deployment_manager/test/ImportTest.ts @@ -18,12 +18,12 @@ export const apiTestResult = { CompilerVersion: 'v0.6.12+commit.27d51765', OptimizationUsed: '1', Runs: '10000000', - ConstructorArguments: '0000000000000000000000007f2239511051b875ccf84dab02d5a307adcd51c2', + ConstructorArguments: '0000000000000000000000000882477e7895bdc5cea7cb1552ed914ab157fe56', EVMVersion: 'Default', Library: '', LicenseType: 'MIT', Proxy: '1', - Implementation: '0xa3fa3d254bf6af295b5b22cc6730b04144314890', + Implementation: '0x43506849d7c04f9138d1a2050bbf3a0c054402dd', SwarmSource: 'ipfs://6715e283f350a976c05fe8b17fc01929cb137086f941d36864b48c4269d883b2', }, ], @@ -33,12 +33,12 @@ export const fiatTokenBuildFile: BuildFile = { contract: 'FiatTokenProxy', contracts: { 'contracts/FiatTokenProxy.sol:FiatTokenProxy': { - network: 'avalanche', - address: '0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e', + network: 'mainnet', + address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', name: 'FiatTokenProxy', abi: '[{"inputs":[{"internalType":"address","name":"implementationContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"changeAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"}]', bin: '608060405234801561001057600080fd5b506040516108a93803806108a98339818101604052602081101561003357600080fd5b5051808061004081610051565b5061004a336100c3565b5050610123565b610064816100e760201b61042a1760201c565b61009f5760405162461bcd60e51b815260040180806020018281038252603b81526020018061086e603b913960400191505060405180910390fd5b7f7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c355565b7f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b55565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061011b57508115155b949350505050565b61073c806101326000396000f3fe60806040526004361061005a5760003560e01c80635c60da1b116100435780635c60da1b146101315780638f2839701461016f578063f851a440146101af5761005a565b80633659cfe6146100645780634f1ef286146100a4575b6100626101c4565b005b34801561007057600080fd5b506100626004803603602081101561008757600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166101de565b610062600480360360408110156100ba57600080fd5b73ffffffffffffffffffffffffffffffffffffffff82351691908101906040810160208201356401000000008111156100f257600080fd5b82018360208201111561010457600080fd5b8035906020019184600183028401116401000000008311171561012657600080fd5b509092509050610232565b34801561013d57600080fd5b50610146610309565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b34801561017b57600080fd5b506100626004803603602081101561019257600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610318565b3480156101bb57600080fd5b50610146610420565b6101cc610466565b6101dc6101d76104fa565b61051f565b565b6101e6610543565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156102275761022281610568565b61022f565b61022f6101c4565b50565b61023a610543565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156102fc5761027683610568565b60003073ffffffffffffffffffffffffffffffffffffffff16348484604051808383808284376040519201945060009350909150508083038185875af1925050503d80600081146102e3576040519150601f19603f3d011682016040523d82523d6000602084013e6102e8565b606091505b50509050806102f657600080fd5b50610304565b6103046101c4565b505050565b60006103136104fa565b905090565b610320610543565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156102275773ffffffffffffffffffffffffffffffffffffffff81166103bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260368152602001806106966036913960400191505060405180910390fd5b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103e8610543565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301528051918290030190a1610222816105bd565b6000610313610543565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061045e57508115155b949350505050565b61046e610543565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156104f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260328152602001806106646032913960400191505060405180910390fd5b6101dc6101dc565b7f7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c35490565b3660008037600080366000845af43d6000803e80801561053e573d6000f35b3d6000fd5b7f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b5490565b610571816105e1565b6040805173ffffffffffffffffffffffffffffffffffffffff8316815290517fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b9181900360200190a150565b7f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b55565b6105ea8161042a565b61063f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603b8152602001806106cc603b913960400191505060405180910390fd5b7f7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c35556fe43616e6e6f742063616c6c2066616c6c6261636b2066756e6374696f6e2066726f6d207468652070726f78792061646d696e43616e6e6f74206368616e6765207468652061646d696e206f6620612070726f787920746f20746865207a65726f206164647265737343616e6e6f742073657420612070726f787920696d706c656d656e746174696f6e20746f2061206e6f6e2d636f6e74726163742061646472657373a26469706673582212206715e283f350a976c05fe8b17fc01929cb137086f941d36864b48c4269d883b264736f6c634300060c003343616e6e6f742073657420612070726f787920696d706c656d656e746174696f6e20746f2061206e6f6e2d636f6e74726163742061646472657373', - constructorArgs: '0000000000000000000000007f2239511051b875ccf84dab02d5a307adcd51c2', + constructorArgs: '0000000000000000000000000882477e7895bdc5cea7cb1552ed914ab157fe56', metadata: '{"compiler":{"version":"v0.6.12+commit.27d51765"},"language":"Solidity","output":{"abi":"[{\\"inputs\\":[{\\"internalType\\":\\"address\\",\\"name\\":\\"implementationContract\\",\\"type\\":\\"address\\"}],\\"stateMutability\\":\\"nonpayable\\",\\"type\\":\\"constructor\\"},{\\"anonymous\\":false,\\"inputs\\":[{\\"indexed\\":false,\\"internalType\\":\\"address\\",\\"name\\":\\"previousAdmin\\",\\"type\\":\\"address\\"},{\\"indexed\\":false,\\"internalType\\":\\"address\\",\\"name\\":\\"newAdmin\\",\\"type\\":\\"address\\"}],\\"name\\":\\"AdminChanged\\",\\"type\\":\\"event\\"},{\\"anonymous\\":false,\\"inputs\\":[{\\"indexed\\":false,\\"internalType\\":\\"address\\",\\"name\\":\\"implementation\\",\\"type\\":\\"address\\"}],\\"name\\":\\"Upgraded\\",\\"type\\":\\"event\\"},{\\"stateMutability\\":\\"payable\\",\\"type\\":\\"fallback\\"},{\\"inputs\\":[],\\"name\\":\\"admin\\",\\"outputs\\":[{\\"internalType\\":\\"address\\",\\"name\\":\\"\\",\\"type\\":\\"address\\"}],\\"stateMutability\\":\\"view\\",\\"type\\":\\"function\\"},{\\"inputs\\":[{\\"internalType\\":\\"address\\",\\"name\\":\\"newAdmin\\",\\"type\\":\\"address\\"}],\\"name\\":\\"changeAdmin\\",\\"outputs\\":[],\\"stateMutability\\":\\"nonpayable\\",\\"type\\":\\"function\\"},{\\"inputs\\":[],\\"name\\":\\"implementation\\",\\"outputs\\":[{\\"internalType\\":\\"address\\",\\"name\\":\\"\\",\\"type\\":\\"address\\"}],\\"stateMutability\\":\\"view\\",\\"type\\":\\"function\\"},{\\"inputs\\":[{\\"internalType\\":\\"address\\",\\"name\\":\\"newImplementation\\",\\"type\\":\\"address\\"}],\\"name\\":\\"upgradeTo\\",\\"outputs\\":[],\\"stateMutability\\":\\"nonpayable\\",\\"type\\":\\"function\\"},{\\"inputs\\":[{\\"internalType\\":\\"address\\",\\"name\\":\\"newImplementation\\",\\"type\\":\\"address\\"},{\\"internalType\\":\\"bytes\\",\\"name\\":\\"data\\",\\"type\\":\\"bytes\\"}],\\"name\\":\\"upgradeToAndCall\\",\\"outputs\\":[],\\"stateMutability\\":\\"payable\\",\\"type\\":\\"function\\"}]"},"devdoc":{},"sources":{"contracts/FiatTokenProxy.sol":{"content":"/**\\r\\n * SPDX-License-Identifier: MIT\\r\\n *\\r\\n * Copyright (c) 2018 zOS Global Limited.\\r\\n *\\r\\n * Permission is hereby granted, free of charge, to any person obtaining a copy\\r\\n * of this software and associated documentation files (the \\"Software\\"), to deal\\r\\n * in the Software without restriction, including without limitation the rights\\r\\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\\r\\n * copies of the Software, and to permit persons to whom the Software is\\r\\n * furnished to do so, subject to the following conditions:\\r\\n *\\r\\n * The above copyright notice and this permission notice shall be included in\\r\\n * copies or substantial portions of the Software.\\r\\n *\\r\\n * THE SOFTWARE IS PROVIDED \\"AS IS\\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\\r\\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\\r\\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\\r\\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\\r\\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\\r\\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\\r\\n * SOFTWARE.\\r\\n */\\r\\n\\r\\n// File: contracts/upgradeability/Proxy.sol\\r\\n\\r\\npragma solidity 0.6.12;\\r\\n\\r\\n/**\\r\\n * @notice Implements delegation of calls to other contracts, with proper\\r\\n * forwarding of return values and bubbling of failures.\\r\\n * It defines a fallback function that delegates all calls to the address\\r\\n * returned by the abstract _implementation() internal function.\\r\\n * @dev Forked from https://github.com/zeppelinos/zos-lib/blob/8a16ef3ad17ec7430e3a9d2b5e3f39b8204f8c8d/contracts/upgradeability/Proxy.sol\\r\\n * Modifications:\\r\\n * 1. Reformat and conform to Solidity 0.6 syntax (5/13/20)\\r\\n */\\r\\nabstract contract Proxy {\\r\\n /**\\r\\n * @dev Fallback function.\\r\\n * Implemented entirely in `_fallback`.\\r\\n */\\r\\n fallback() external payable {\\r\\n _fallback();\\r\\n }\\r\\n\\r\\n /**\\r\\n * @return The Address of the implementation.\\r\\n */\\r\\n function _implementation() internal virtual view returns (address);\\r\\n\\r\\n /**\\r\\n * @dev Delegates execution to an implementation contract.\\r\\n * This is a low level function that doesn\'t return to its internal call site.\\r\\n * It will return to the external caller whatever the implementation returns.\\r\\n * @param implementation Address to delegate.\\r\\n */\\r\\n function _delegate(address implementation) internal {\\r\\n assembly {\\r\\n // Copy msg.data. We take full control of memory in this inline assembly\\r\\n // block because it will not return to Solidity code. We overwrite the\\r\\n // Solidity scratch pad at memory position 0.\\r\\n calldatacopy(0, 0, calldatasize())\\r\\n\\r\\n // Call the implementation.\\r\\n // out and outsize are 0 because we don\'t know the size yet.\\r\\n let result := delegatecall(\\r\\n gas(),\\r\\n implementation,\\r\\n 0,\\r\\n calldatasize(),\\r\\n 0,\\r\\n 0\\r\\n )\\r\\n\\r\\n // Copy the returned data.\\r\\n returndatacopy(0, 0, returndatasize())\\r\\n\\r\\n switch result\\r\\n // delegatecall returns 0 on error.\\r\\n case 0 {\\r\\n revert(0, returndatasize())\\r\\n }\\r\\n default {\\r\\n return(0, returndatasize())\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @dev Function that is run as the first thing in the fallback function.\\r\\n * Can be redefined in derived contracts to add functionality.\\r\\n * Redefinitions must call super._willFallback().\\r\\n */\\r\\n function _willFallback() internal virtual {}\\r\\n\\r\\n /**\\r\\n * @dev fallback implementation.\\r\\n * Extracted to enable manual triggering.\\r\\n */\\r\\n function _fallback() internal {\\r\\n _willFallback();\\r\\n _delegate(_implementation());\\r\\n }\\r\\n}\\r\\n\\r\\n// File: @openzeppelin/contracts/utils/Address.sol\\r\\n\\r\\npragma solidity ^0.6.2;\\r\\n\\r\\n/**\\r\\n * @dev Collection of functions related to the address type\\r\\n */\\r\\nlibrary Address {\\r\\n /**\\r\\n * @dev Returns true if `account` is a contract.\\r\\n *\\r\\n * [IMPORTANT]\\r\\n * ====\\r\\n * It is unsafe to assume that an address for which this function returns\\r\\n * false is an externally-owned account (EOA) and not a contract.\\r\\n *\\r\\n * Among others, `isContract` will return false for the following\\r\\n * types of addresses:\\r\\n *\\r\\n * - an externally-owned account\\r\\n * - a contract in construction\\r\\n * - an address where a contract will be created\\r\\n * - an address where a contract lived, but was destroyed\\r\\n * ====\\r\\n */\\r\\n function isContract(address account) internal view returns (bool) {\\r\\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\\r\\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\\r\\n // for accounts without code, i.e. `keccak256(\'\')`\\r\\n bytes32 codehash;\\r\\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\\r\\n // solhint-disable-next-line no-inline-assembly\\r\\n assembly { codehash := extcodehash(account) }\\r\\n return (codehash != accountHash && codehash != 0x0);\\r\\n }\\r\\n}\\r\\n\\r\\n// File: contracts/upgradeability/UpgradeabilityProxy.sol\\r\\n\\r\\npragma solidity 0.6.12;\\r\\n\\r\\n/**\\r\\n * @notice This contract implements a proxy that allows to change the\\r\\n * implementation address to which it will delegate.\\r\\n * Such a change is called an implementation upgrade.\\r\\n * @dev Forked from https://github.com/zeppelinos/zos-lib/blob/8a16ef3ad17ec7430e3a9d2b5e3f39b8204f8c8d/contracts/upgradeability/UpgradeabilityProxy.sol\\r\\n * Modifications:\\r\\n * 1. Reformat, conform to Solidity 0.6 syntax, and add error messages (5/13/20)\\r\\n * 2. Use Address utility library from the latest OpenZeppelin (5/13/20)\\r\\n */\\r\\ncontract UpgradeabilityProxy is Proxy {\\r\\n /**\\r\\n * @dev Emitted when the implementation is upgraded.\\r\\n * @param implementation Address of the new implementation.\\r\\n */\\r\\n event Upgraded(address implementation);\\r\\n\\r\\n /**\\r\\n * @dev Storage slot with the address of the current implementation.\\r\\n * This is the keccak-256 hash of \\"org.zeppelinos.proxy.implementation\\", and is\\r\\n * validated in the constructor.\\r\\n */\\r\\n bytes32\\r\\n private constant IMPLEMENTATION_SLOT = 0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3;\\r\\n\\r\\n /**\\r\\n * @dev Contract constructor.\\r\\n * @param implementationContract Address of the initial implementation.\\r\\n */\\r\\n constructor(address implementationContract) public {\\r\\n assert(\\r\\n IMPLEMENTATION_SLOT ==\\r\\n keccak256(\\"org.zeppelinos.proxy.implementation\\")\\r\\n );\\r\\n\\r\\n _setImplementation(implementationContract);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @dev Returns the current implementation.\\r\\n * @return impl Address of the current implementation\\r\\n */\\r\\n function _implementation() internal override view returns (address impl) {\\r\\n bytes32 slot = IMPLEMENTATION_SLOT;\\r\\n assembly {\\r\\n impl := sload(slot)\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @dev Upgrades the proxy to a new implementation.\\r\\n * @param newImplementation Address of the new implementation.\\r\\n */\\r\\n function _upgradeTo(address newImplementation) internal {\\r\\n _setImplementation(newImplementation);\\r\\n emit Upgraded(newImplementation);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @dev Sets the implementation address of the proxy.\\r\\n * @param newImplementation Address of the new implementation.\\r\\n */\\r\\n function _setImplementation(address newImplementation) private {\\r\\n require(\\r\\n Address.isContract(newImplementation),\\r\\n \\"Cannot set a proxy implementation to a non-contract address\\"\\r\\n );\\r\\n\\r\\n bytes32 slot = IMPLEMENTATION_SLOT;\\r\\n\\r\\n assembly {\\r\\n sstore(slot, newImplementation)\\r\\n }\\r\\n }\\r\\n}\\r\\n\\r\\n// File: contracts/upgradeability/AdminUpgradeabilityProxy.sol\\r\\n\\r\\npragma solidity 0.6.12;\\r\\n\\r\\n/**\\r\\n * @notice This contract combines an upgradeability proxy with an authorization\\r\\n * mechanism for administrative tasks.\\r\\n * @dev Forked from https://github.com/zeppelinos/zos-lib/blob/8a16ef3ad17ec7430e3a9d2b5e3f39b8204f8c8d/contracts/upgradeability/AdminUpgradeabilityProxy.sol\\r\\n * Modifications:\\r\\n * 1. Reformat, conform to Solidity 0.6 syntax, and add error messages (5/13/20)\\r\\n * 2. Remove ifAdmin modifier from admin() and implementation() (5/13/20)\\r\\n */\\r\\ncontract AdminUpgradeabilityProxy is UpgradeabilityProxy {\\r\\n /**\\r\\n * @dev Emitted when the administration has been transferred.\\r\\n * @param previousAdmin Address of the previous admin.\\r\\n * @param newAdmin Address of the new admin.\\r\\n */\\r\\n event AdminChanged(address previousAdmin, address newAdmin);\\r\\n\\r\\n /**\\r\\n * @dev Storage slot with the admin of the contract.\\r\\n * This is the keccak-256 hash of \\"org.zeppelinos.proxy.admin\\", and is\\r\\n * validated in the constructor.\\r\\n */\\r\\n bytes32\\r\\n private constant ADMIN_SLOT = 0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b;\\r\\n\\r\\n /**\\r\\n * @dev Modifier to check whether the `msg.sender` is the admin.\\r\\n * If it is, it will run the function. Otherwise, it will delegate the call\\r\\n * to the implementation.\\r\\n */\\r\\n modifier ifAdmin() {\\r\\n if (msg.sender == _admin()) {\\r\\n _;\\r\\n } else {\\r\\n _fallback();\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @dev Contract constructor.\\r\\n * It sets the `msg.sender` as the proxy administrator.\\r\\n * @param implementationContract address of the initial implementation.\\r\\n */\\r\\n constructor(address implementationContract)\\r\\n public\\r\\n UpgradeabilityProxy(implementationContract)\\r\\n {\\r\\n assert(ADMIN_SLOT == keccak256(\\"org.zeppelinos.proxy.admin\\"));\\r\\n\\r\\n _setAdmin(msg.sender);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @return The address of the proxy admin.\\r\\n */\\r\\n function admin() external view returns (address) {\\r\\n return _admin();\\r\\n }\\r\\n\\r\\n /**\\r\\n * @return The address of the implementation.\\r\\n */\\r\\n function implementation() external view returns (address) {\\r\\n return _implementation();\\r\\n }\\r\\n\\r\\n /**\\r\\n * @dev Changes the admin of the proxy.\\r\\n * Only the current admin can call this function.\\r\\n * @param newAdmin Address to transfer proxy administration to.\\r\\n */\\r\\n function changeAdmin(address newAdmin) external ifAdmin {\\r\\n require(\\r\\n newAdmin != address(0),\\r\\n \\"Cannot change the admin of a proxy to the zero address\\"\\r\\n );\\r\\n emit AdminChanged(_admin(), newAdmin);\\r\\n _setAdmin(newAdmin);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @dev Upgrade the backing implementation of the proxy.\\r\\n * Only the admin can call this function.\\r\\n * @param newImplementation Address of the new implementation.\\r\\n */\\r\\n function upgradeTo(address newImplementation) external ifAdmin {\\r\\n _upgradeTo(newImplementation);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @dev Upgrade the backing implementation of the proxy and call a function\\r\\n * on the new implementation.\\r\\n * This is useful to initialize the proxied contract.\\r\\n * @param newImplementation Address of the new implementation.\\r\\n * @param data Data to send as msg.data in the low level call.\\r\\n * It should include the signature and the parameters of the function to be\\r\\n * called, as described in\\r\\n * https://solidity.readthedocs.io/en/develop/abi-spec.html#function-selector-and-argument-encoding.\\r\\n */\\r\\n function upgradeToAndCall(address newImplementation, bytes calldata data)\\r\\n external\\r\\n payable\\r\\n ifAdmin\\r\\n {\\r\\n _upgradeTo(newImplementation);\\r\\n // prettier-ignore\\r\\n // solhint-disable-next-line avoid-low-level-calls\\r\\n (bool success,) = address(this).call{value: msg.value}(data);\\r\\n // solhint-disable-next-line reason-string\\r\\n require(success);\\r\\n }\\r\\n\\r\\n /**\\r\\n * @return adm The admin slot.\\r\\n */\\r\\n function _admin() internal view returns (address adm) {\\r\\n bytes32 slot = ADMIN_SLOT;\\r\\n\\r\\n assembly {\\r\\n adm := sload(slot)\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @dev Sets the address of the proxy admin.\\r\\n * @param newAdmin Address of the new proxy admin.\\r\\n */\\r\\n function _setAdmin(address newAdmin) internal {\\r\\n bytes32 slot = ADMIN_SLOT;\\r\\n\\r\\n assembly {\\r\\n sstore(slot, newAdmin)\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * @dev Only fall back when the sender is not the admin.\\r\\n */\\r\\n function _willFallback() internal override {\\r\\n require(\\r\\n msg.sender != _admin(),\\r\\n \\"Cannot call fallback function from the proxy admin\\"\\r\\n );\\r\\n super._willFallback();\\r\\n }\\r\\n}\\r\\n\\r\\n// File: contracts/FiatTokenProxy.sol\\r\\n\\r\\npragma solidity 0.6.12;\\r\\n\\r\\n/**\\r\\n * @title FiatTokenProxy\\r\\n * @dev This contract proxies FiatToken calls and enables FiatToken upgrades\\r\\n */\\r\\ncontract FiatTokenProxy is AdminUpgradeabilityProxy {\\r\\n constructor(address implementationContract)\\r\\n public\\r\\n AdminUpgradeabilityProxy(implementationContract)\\r\\n {}\\r\\n}","keccak256":""}},"settings":{"optimizer":{"enabled":true,"runs":10000000}},"version":1}', }, @@ -47,13 +47,21 @@ export const fiatTokenBuildFile: BuildFile = { }; export function mockImportSuccess(address: string) { - process.env.SNOWTRACE_KEY = 'AVA_KEY'; - nock('https://api.snowtrace.io/') - .get('/api') - .query({ module: 'contract', action: 'getsourcecode', address, apikey: 'AVA_KEY' }) + process.env.ETHERSCAN_KEY = 'ETHERSCAN_KEY'; + nock('https://api.etherscan.io') + .get('/v2/api') + .query((query) => { + return ( + query.chainid === '1' && + query.module === 'contract' && + query.action === 'getsourcecode' && + query.address === address && + typeof query.apikey === 'string' + ); + }) .reply(200, apiTestResult); - nock('https://snowtrace.io/') + nock('https://etherscan.io/') .get(`/address/${address}`) .reply( 200, @@ -67,10 +75,10 @@ describe('Import', () => { }); it('imports from Etherscan', async () => { - mockImportSuccess('0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e'); + mockImportSuccess('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'); let importResult = await importContract( - 'avalanche', - '0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e', + 'mainnet', + '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 0 ); expect(importResult).to.eql(fiatTokenBuildFile); @@ -78,24 +86,26 @@ describe('Import', () => { it('loads from cache', async () => { let cache = new Cache('test-network', 'test-deployment'); - await storeBuildFile(cache, 'avalanche', '0x0000000000000000000000000000000000000001', fiatTokenBuildFile); + await storeBuildFile(cache, 'mainnet', '0x0000000000000000000000000000000000000001', fiatTokenBuildFile); expect( - await fetchContract(cache, 'avalanche', '0x0000000000000000000000000000000000000001', 0) + await fetchContract(cache, 'mainnet', '0x0000000000000000000000000000000000000001', 0) ).to.equal(fiatTokenBuildFile); }); it('stores in cache', async () => { - mockImportSuccess('0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e'); + mockImportSuccess('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'); let cache = new Cache('test-network', 'test-deployment'); expect( await fetchAndCacheContract( cache, - 'avalanche', - '0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e', - 0 + 'mainnet', + '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', + 0, + 0, + true ) ).to.eql(fiatTokenBuildFile); - expect(await getBuildFile(cache, 'avalanche', '0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e')).to.eql( + expect(await getBuildFile(cache, 'mainnet', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48')).to.eql( fiatTokenBuildFile ); }); diff --git a/plugins/deployment_manager/test/RelationConfigTest.ts b/plugins/deployment_manager/test/RelationConfigTest.ts index 247f4e365..2832b9883 100644 --- a/plugins/deployment_manager/test/RelationConfigTest.ts +++ b/plugins/deployment_manager/test/RelationConfigTest.ts @@ -62,7 +62,6 @@ describe('RelationConfig', () => { }, }; - expect(await getRelationConfig(hre.config.deploymentManager, 'fuji', 'dai')).to.eql(testBaseRelations); expect(await getRelationConfig(hre.config.deploymentManager, 'test-network', 'test-deployment')).to.eql(testRelRelations); }); diff --git a/plugins/import/etherscan.ts b/plugins/import/etherscan.ts index a4506a419..95db477b7 100644 --- a/plugins/import/etherscan.ts +++ b/plugins/import/etherscan.ts @@ -15,30 +15,19 @@ export function getEtherscanApiUrl(network: string): string { throw new Error(`Unknown etherscan API host for network ${network}`); } - if (network === 'avalanche') { - return `https://api.snowtrace.io/api`; - } else if (network === 'fuji') { - return `https://api-testnet.snowtrace.io/api`; - } - return `https://api.etherscan.io/v2/api?chainid=${chainId}`; } export function getEtherscanUrl(network: string): string { let host = { - rinkeby: 'rinkeby.etherscan.io', - ropsten: 'ropsten.etherscan.io', - sepolia: 'sepolia.etherscan.io', mainnet: 'etherscan.io', - fuji: 'testnet.snowtrace.io', - avalanche: 'snowtrace.io', polygon: 'polygonscan.com', arbitrum: 'arbiscan.io', base: 'basescan.org', optimism: 'optimistic.etherscan.io', mantle: 'mantlescan.xyz', linea: 'lineascan.build', - 'ronin': 'explorer-kintsugi.roninchain.com/v2/2020', + ronin: 'explorer-kintsugi.roninchain.com/v2/2020', scroll: 'scrollscan.com' }[network]; @@ -52,10 +41,7 @@ export function getEtherscanUrl(network: string): string { export function getEtherscanApiKey(network: string, i?: number): string { // Primary key for each network const primaryKeys = { - sepolia: process.env.ETHERSCAN_KEY, mainnet: process.env.ETHERSCAN_KEY, - fuji: process.env.SNOWTRACE_KEY, - avalanche: process.env.SNOWTRACE_KEY, polygon: process.env.ETHERSCAN_KEY_FOR_POLYGON, arbitrum: process.env.ETHERSCAN_KEY_FOR_ARBITRUM, base: process.env.ETHERSCAN_KEY_FOR_BASE, diff --git a/plugins/scenario/utils/hreForBase.ts b/plugins/scenario/utils/hreForBase.ts index ee47241bf..b3d7d139d 100644 --- a/plugins/scenario/utils/hreForBase.ts +++ b/plugins/scenario/utils/hreForBase.ts @@ -73,8 +73,6 @@ function getBlockRollback(base: ForkSpec) { } else if (base.network === 'arbitrum') { return undefined; - } else if (base.network === 'sepolia') { - return undefined; } else if (base.network === 'unichain') { return 0; diff --git a/scenario/InterestRateScenario.ts b/scenario/InterestRateScenario.ts index 72256e908..740fae238 100644 --- a/scenario/InterestRateScenario.ts +++ b/scenario/InterestRateScenario.ts @@ -174,23 +174,8 @@ scenario( scenario.skip( 'Comet#interestRate > when utilization is 50%', { utilization: 0.5 }, - async ({ comet }, context) => { + async ({ comet }) => { const utilization = await comet.getUtilization(); expect(defactor(utilization)).to.be.approximately(0.5, 0.00001); - - // Note: this is dependent on the `deployments/fuji/configuration.json` variables - // TODO: Consider if there's a better way to test the live curve. - if (context.world.base.network === 'fuji') { - // (interestRateBase + interestRateSlopeLow * utilization) * utilization * (1 - reserveRate) - // utilization = 50% - // ( 1% + 2% * 50% ) * 50% * (100% - 10%) - // ( 1% + 1% ) * 50% * 90% -> 1% * 90% = 0.9% - expect(annualize(await comet.getSupplyRate(utilization))).to.be.approximately(0.009, 0.001); - - // interestRateBase + interestRateSlopeLow * utilization - // utilization = 50% - // ( 1% + 2% * 50% ) - expect(annualize(await comet.getBorrowRate(utilization))).to.be.approximately(0.02, 0.001); - } } ); diff --git a/scenario/context/CometContext.ts b/scenario/context/CometContext.ts index 107f53723..cac770e6a 100644 --- a/scenario/context/CometContext.ts +++ b/scenario/context/CometContext.ts @@ -1,4 +1,4 @@ -import { BigNumber, BigNumberish, Contract } from 'ethers'; +import { BigNumber, BigNumberish } from 'ethers'; import { Loader, World, debug } from '../../plugins/scenario'; import { Migration } from '../../plugins/deployment_manager'; import { @@ -153,23 +153,9 @@ export class CometContext { const currentComet = await this.getComet(); const admin = await world.impersonateAddress(await currentComet.governor(), { value: 20n ** 18n }); - const oldComet = new Contract(currentComet.address, - [ - 'function governor() view returns (address)', - 'function assetList() view returns (address)', - 'function assetListFactory() view returns (address)' - ], admin); const deploySpec = { cometMain: true, cometExt: true }; - let withAssetList = false; - try { - await oldComet.assetList(); - withAssetList = true; - } - catch (e) { - withAssetList = false; - } - const deployed = await deployComet(this.world.deploymentManager, deploySpec, configOverrides, withAssetList, admin); + const deployed = await deployComet(this.world.deploymentManager, deploySpec, configOverrides, admin); await this.world.deploymentManager.spider(deployed); await this.setAssets(); diff --git a/scenario/utils/index.ts b/scenario/utils/index.ts index f87084c87..c42e32f67 100644 --- a/scenario/utils/index.ts +++ b/scenario/utils/index.ts @@ -435,7 +435,7 @@ export async function fetchLogs( filter: EventFilter, fromBlock: number, toBlock: number, - BLOCK_SPAN = 2047 // NB: sadly max for fuji is LESS than 2048 + BLOCK_SPAN = 2047 ): Promise { if (toBlock - fromBlock > BLOCK_SPAN) { const midBlock = fromBlock + BLOCK_SPAN; diff --git a/scenario/utils/relayBaseMessage.ts b/scenario/utils/relayBaseMessage.ts index 1c6491a8e..bb3a3cac4 100644 --- a/scenario/utils/relayBaseMessage.ts +++ b/scenario/utils/relayBaseMessage.ts @@ -11,7 +11,7 @@ The Base relayer applies an offset to the message sender. applyL1ToL2Alias mimics the AddressAliasHelper.applyL1ToL2Alias fn that converts an L1 address to its offset, L2 equivalent. -https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000007#code +https://basescan.org/address/0x4200000000000000000000000000000000000007#code */ export default async function relayBaseMessage( diff --git a/scenario/utils/scenarioHelper.ts b/scenario/utils/scenarioHelper.ts index 2dd22e823..26381efc0 100644 --- a/scenario/utils/scenarioHelper.ts +++ b/scenario/utils/scenarioHelper.ts @@ -227,10 +227,6 @@ export function getConfigForScenario(ctx: CometContext, i?: number) { } } - if (ctx.world.base.network === 'sepolia' && ctx.world.base.deployment === 'usdc') { - config.bulkerAsset1 = 10; - } - if(ctx.world.base.network === 'mantle' && ctx.world.base.deployment === 'usde') { if(i == 2) { // FBTC config.supplyCollateral = 2; @@ -280,9 +276,5 @@ export function getConfigForScenario(ctx: CometContext, i?: number) { config.transferAsset1 = 500; } - if (ctx.world.base.network === 'fuji' && ctx.world.base.deployment === 'usdc') { - config.liquidationAsset = 100; - } - return config; } diff --git a/scripts/exportNetworkConfigs.js b/scripts/exportNetworkConfigs.js index 60d76183c..8cbdb78d4 100644 --- a/scripts/exportNetworkConfigs.js +++ b/scripts/exportNetworkConfigs.js @@ -44,7 +44,6 @@ const envVar = { OPTIMISM_QUICKNODE_LINK: getUrl('optimism'), SCROLL_RPC_URL: getUrl('scroll'), BASE_QUICKNODE_LINK: getUrl('base'), - SEPOLIA_RPC_URL: getUrl('sepolia'), MANTLE_QUICKNODE_LINK: getUrl('mantle'), }; diff --git a/scripts/liquidation_bot/index.ts b/scripts/liquidation_bot/index.ts index 6092e6c72..9b5f7ff38 100644 --- a/scripts/liquidation_bot/index.ts +++ b/scripts/liquidation_bot/index.ts @@ -66,13 +66,6 @@ async function main() { hre.ethers.provider, // a normal ethers.js provider, to perform gas estimations and nonce lookups authSigner, // ethers.js signer wallet, only for signing request payloads, not transactions ); - } else if (network === 'sepolia') { - flashbotsProvider = await FlashbotsBundleProvider.create( - hre.ethers.provider, // a normal ethers.js provider, to perform gas estimations and nonce lookups - authSigner, // ethers.js signer wallet, only for signing request payloads, not transactions - 'https://relay-sepolia.flashbots.net', - 'sepolia' - ); } else { throw new Error(`Unsupported network: ${network}`); } diff --git a/src/deploy/Network.ts b/src/deploy/Network.ts index f869e37ee..685ee22dd 100644 --- a/src/deploy/Network.ts +++ b/src/deploy/Network.ts @@ -83,7 +83,6 @@ export async function deployNetworkComet( deploymentManager: DeploymentManager, deploySpec: DeploySpec = { all: true }, configOverrides: ProtocolConfiguration = {}, - withAssetList = false, adminSigner?: SignerWithAddress, ): Promise { function maybeForce(flag?: boolean): boolean { @@ -133,47 +132,27 @@ export async function deployNetworkComet( name32: ethers.utils.formatBytes32String(name), symbol32: ethers.utils.formatBytes32String(symbol) }; - let cometExt; - - if(withAssetList) { - const assetListFactory = await deploymentManager.deploy( - 'assetListFactory', - 'AssetListFactory.sol', - [], - maybeForce() - ); - cometExt = await deploymentManager.deploy( - 'comet:implementation:implementation', - 'CometExtAssetList.sol', - [extConfiguration, assetListFactory.address], - maybeForce(deploySpec.cometExt) - ); - } else { - cometExt = await deploymentManager.deploy( - 'comet:implementation:implementation', - 'CometExt.sol', - [extConfiguration], - maybeForce(deploySpec.cometExt) - ); - } - let cometFactory; - if(withAssetList) { - cometFactory = await deploymentManager.deploy( - 'cometFactory', - 'CometFactoryWithExtendedAssetList.sol', - [], - maybeForce(deploySpec.cometMain) - ); - } - else { - cometFactory = await deploymentManager.deploy( - 'cometFactory', - 'CometFactory.sol', - [], - maybeForce(deploySpec.cometMain) - ); - } + const assetListFactory = await deploymentManager.deploy( + 'assetListFactory', + 'AssetListFactory.sol', + [], + maybeForce() + ); + const cometExt = await deploymentManager.deploy( + 'comet:implementation:implementation', + 'CometExtAssetList.sol', + [extConfiguration, assetListFactory.address], + maybeForce(deploySpec.cometExt) + ); + + + const cometFactory = await deploymentManager.deploy( + 'cometFactory', + 'CometFactoryWithExtendedAssetList.sol', + [], + maybeForce(deploySpec.cometMain) + ); const configuration = { governor, @@ -199,22 +178,13 @@ export async function deployNetworkComet( assetConfigs, }; - let tmpCometImpl; - if(withAssetList) { - tmpCometImpl = await deploymentManager.deploy( - 'comet:implementation', - 'CometWithExtendedAssetList.sol', - [configuration], - maybeForce() - ); - } else{ - tmpCometImpl = await deploymentManager.deploy( - 'comet:implementation', - 'Comet.sol', - [configuration], - maybeForce(), - ); - } + const tmpCometImpl = await deploymentManager.deploy( + 'comet:implementation', + 'CometWithExtendedAssetList.sol', + [configuration], + maybeForce() + ); + const cometProxy = await deploymentManager.deploy( 'comet', 'vendor/proxy/transparent/TransparentUpgradeableProxy.sol', diff --git a/src/deploy/NetworkConfiguration.ts b/src/deploy/NetworkConfiguration.ts index 41cec432a..116c0d815 100644 --- a/src/deploy/NetworkConfiguration.ts +++ b/src/deploy/NetworkConfiguration.ts @@ -1,4 +1,4 @@ -import { AssetConfigStruct } from '../../build/types/Comet'; +import { AssetConfigStruct } from '../../build/types/CometWithExtendedAssetList'; import { ConfigurationStruct } from '../../build/types/Configurator'; import { ProtocolConfiguration } from './index'; import { ContractMap } from '../../plugins/deployment_manager/ContractMap'; diff --git a/src/deploy/index.ts b/src/deploy/index.ts index 8d2ea4953..58c7bb9e3 100644 --- a/src/deploy/index.ts +++ b/src/deploy/index.ts @@ -1,4 +1,4 @@ -import { AssetConfigStruct } from '../../build/types/Comet'; +import { AssetConfigStruct } from '../../build/types/CometWithExtendedAssetList'; import { BigNumberish, Contract, PopulatedTransaction, utils } from 'ethers'; export { cloneGov, deployNetworkComet as deployComet, sameAddress } from './Network'; diff --git a/test/absorb-test.ts b/test/absorb-test.ts index 2ab6c1e80..2e52a9a9d 100644 --- a/test/absorb-test.ts +++ b/test/absorb-test.ts @@ -3,7 +3,7 @@ import { event, expect, exp, factor, defaultAssets, makeProtocol, mulPrice, port describe('absorb', function () { it('reverts if total borrows underflows', async () => { - const { comet, users: [absorber, underwater] } = await makeProtocol(); + const { cometWithExtendedAssetList : comet, users: [absorber, underwater] } = await makeProtocol(); const _f0 = await comet.setBasePrincipal(underwater.address, -100); await expect(comet.absorb(absorber.address, [underwater.address])).to.be.revertedWith('code 0x11 (Arithmetic operation underflowed or overflowed outside of an unchecked block)'); @@ -19,7 +19,7 @@ describe('absorb', function () { borrowInterestRateSlopeHigh: 0, }; const protocol = await makeProtocol(params); - const { comet, priceFeeds, users: [absorber, underwater] } = protocol; + const { cometWithExtendedAssetList : comet, priceFeeds, users: [absorber, underwater] } = protocol; await setTotalsBasic(comet, { totalBorrowBase: 100n }); @@ -87,7 +87,7 @@ describe('absorb', function () { borrowInterestRateSlopeHigh: 0, }; const protocol = await makeProtocol(params); - const { comet, priceFeeds, users: [absorber, underwater1, underwater2] } = protocol; + const { cometWithExtendedAssetList : comet, priceFeeds, users: [absorber, underwater1, underwater2] } = protocol; await setTotalsBasic(comet, { totalBorrowBase: 2000n }); @@ -167,7 +167,7 @@ describe('absorb', function () { borrowInterestRateSlopeHigh: 0, }; const protocol = await makeProtocol(params); - const { comet, tokens, priceFeeds, users: [absorber, underwater1, underwater2, underwater3] } = protocol; + const { cometWithExtendedAssetList : comet, tokens, priceFeeds, users: [absorber, underwater1, underwater2, underwater3] } = protocol; const { COMP, WBTC, WETH } = tokens; await setTotalsBasic(comet, { @@ -372,7 +372,7 @@ describe('absorb', function () { }) }; const protocol = await makeProtocol(params); - const { comet, tokens, users: [absorber, underwater], priceFeeds } = protocol; + const { cometWithExtendedAssetList : comet, tokens, users: [absorber, underwater], priceFeeds } = protocol; const { COMP, WBTC, WETH } = tokens; const finalDebt = 1n; @@ -483,7 +483,7 @@ describe('absorb', function () { }); it('reverts if an account is not underwater', async () => { - const { comet, users: [alice, bob] } = await makeProtocol(); + const { cometWithExtendedAssetList : comet, users: [alice, bob] } = await makeProtocol(); await expect(comet.absorb(alice.address, [bob.address])).to.be.revertedWith("custom error 'NotLiquidatable()'"); }); @@ -494,7 +494,7 @@ describe('absorb', function () { it('reverts if absorb is paused', async () => { const protocol = await makeProtocol(); - const { comet, pauseGuardian, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList : comet, pauseGuardian, users: [alice, bob] } = protocol; const cometAsB = comet.connect(bob); @@ -506,7 +506,7 @@ describe('absorb', function () { }); it('updates assetsIn for liquidated account', async () => { - const { comet, users: [absorber, underwater], tokens } = await makeProtocol(); + const { cometWithExtendedAssetList : comet, users: [absorber, underwater], tokens } = await makeProtocol(); const { COMP, WETH } = tokens; await bumpTotalsCollateral(comet, COMP, exp(1, 18)); diff --git a/test/accrue-test.ts b/test/accrue-test.ts index 19680a57b..997aa9499 100644 --- a/test/accrue-test.ts +++ b/test/accrue-test.ts @@ -28,7 +28,7 @@ describe('accrue', function () { baseTrackingBorrowSpeed: 777, start }; - const { comet } = await makeProtocol(params); + const { cometWithExtendedAssetList : comet } = await makeProtocol(params); const t0 = await comet.totalsBasic(); expect(t0.trackingSupplyIndex).to.be.equal(0); @@ -47,7 +47,7 @@ describe('accrue', function () { }); it('accrues correctly with no time elapsed', async () => { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList : comet } = await makeProtocol(); const now = Math.floor(Date.now() / 1000); const _f0 = await wait(comet.setNow(now)); // this freezes the timestamp for the entire test @@ -93,7 +93,7 @@ describe('accrue', function () { trackingIndexScale: exp(1, 15), start, }; - const { comet } = await makeProtocol(params); + const { cometWithExtendedAssetList : comet } = await makeProtocol(params); const t1 = await setTotalsBasic(comet, { totalSupplyBase: 11000n, @@ -129,7 +129,7 @@ describe('accrue', function () { trackingIndexScale: exp(1, 15), start, }; - const { comet } = await makeProtocol(params); + const { cometWithExtendedAssetList : comet } = await makeProtocol(params); const t0 = await comet.totalsBasic(); const t1 = await setTotalsBasic(comet, { @@ -168,7 +168,7 @@ describe('accrue', function () { baseMinForRewards: 12000, trackingIndexScale: exp(1, 15), }; - const { comet } = await makeProtocol(params); + const { cometWithExtendedAssetList : comet } = await makeProtocol(params); const t0 = await comet.totalsBasic(); const t1 = Object.assign({}, t0, { @@ -194,7 +194,7 @@ describe('accrue', function () { }); it('reverts on overflows', async () => { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList : comet } = await makeProtocol(); const t0 = await comet.totalsBasic(); const t1 = Object.assign({}, t0, { @@ -217,7 +217,7 @@ describe('accrue', function () { }); it('supports up to the maximum timestamp then breaks', async () => { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList : comet } = await makeProtocol(); await fastForward(100); const _a0 = await wait(comet.accrue()); @@ -230,7 +230,7 @@ describe('accrue', function () { describe('accrueAccount', function () { it('has no effect when called on an address with no protocol activity', async () => { - const { comet, users: [unusedAccount] } = await makeProtocol(); + const { cometWithExtendedAssetList : comet, users: [unusedAccount] } = await makeProtocol(); const userBasic0 = await comet.userBasic(unusedAccount.address); await comet.accrueAccount(unusedAccount.address); diff --git a/test/allow-test.ts b/test/allow-test.ts index da431c069..120f52932 100644 --- a/test/allow-test.ts +++ b/test/allow-test.ts @@ -2,7 +2,7 @@ import { ethers, event, expect, makeProtocol, wait } from './helpers'; describe('allow', function () { it('isAllowed defaults to false', async () => { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList : comet } = await makeProtocol(); const [_admin, user, manager] = await ethers.getSigners(); const userAddress = user.address; const managerAddress = manager.address; @@ -11,7 +11,7 @@ describe('allow', function () { }); it('allows a user to authorize a manager', async () => { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList : comet } = await makeProtocol(); const [_admin, user, manager] = await ethers.getSigners(); const userAddress = user.address; const managerAddress = manager.address; @@ -29,7 +29,7 @@ describe('allow', function () { }); it('allows a user to rescind authorization', async () => { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList : comet } = await makeProtocol(); const [_admin, user, manager] = await ethers.getSigners(); const userAddress = user.address; const managerAddress = manager.address; @@ -53,17 +53,17 @@ describe('allow', function () { describe('hasPermission', function () { it('is true for self', async () => { - const { comet, users: [alice] } = await makeProtocol(); + const { cometWithExtendedAssetList : comet, users: [alice] } = await makeProtocol(); expect(await comet.hasPermission(alice.address, alice.address)).to.be.true; }); it('is false by default for others', async () => { - const { comet, users: [alice, bob] } = await makeProtocol(); + const { cometWithExtendedAssetList : comet, users: [alice, bob] } = await makeProtocol(); expect(await comet.hasPermission(alice.address, bob.address)).to.be.false; }); it('is true when user is allowed', async () => { - const { comet, users: [alice, bob] } = await makeProtocol(); + const { cometWithExtendedAssetList : comet, users: [alice, bob] } = await makeProtocol(); await comet.connect(alice).allow(bob.address, true); expect(await comet.hasPermission(alice.address, bob.address)).to.be.true; }); diff --git a/test/approve-this-test.ts b/test/approve-this-test.ts index e0794636e..e05cf60ab 100644 --- a/test/approve-this-test.ts +++ b/test/approve-this-test.ts @@ -4,14 +4,14 @@ describe('approveThis', function () { describe('asset is Comet', function() { it('isAllowed defaults to false', async () => { const protocol = await makeProtocol(); - const { comet, governor } = protocol; + const { cometWithExtendedAssetList : comet, governor } = protocol; expect(await comet.isAllowed(comet.address, governor.address)).to.be.false; }); it('allows governor to authorize a manager', async () => { const protocol = await makeProtocol(); - const { comet, governor } = protocol; + const { cometWithExtendedAssetList : comet, governor } = protocol; await comet.connect(governor).approveThis(governor.address, comet.address, ethers.constants.MaxUint256); @@ -20,7 +20,7 @@ describe('approveThis', function () { it('allows governor to rescind authorization', async () => { const protocol = await makeProtocol(); - const { comet, governor, users: [ user ] } = protocol; + const { cometWithExtendedAssetList : comet, governor, users: [ user ] } = protocol; await comet.connect(governor).approveThis(user.address, comet.address, ethers.constants.MaxUint256); @@ -33,7 +33,7 @@ describe('approveThis', function () { it('reverts if not called by governor', async () => { const protocol = await makeProtocol(); - const { comet, users: [ user ] } = protocol; + const { cometWithExtendedAssetList : comet, users: [ user ] } = protocol; await expect(comet.connect(user).approveThis(user.address, comet.address, ethers.constants.MaxUint256)) .to.be.revertedWith("custom error 'Unauthorized()'"); @@ -43,7 +43,7 @@ describe('approveThis', function () { describe('asset is non-Comet ERC20', function() { it('isAllowed defaults to false', async () => { const protocol = await makeProtocol(); - const { comet, tokens, governor } = protocol; + const { cometWithExtendedAssetList : comet, tokens, governor } = protocol; const { COMP } = tokens; expect(await COMP.allowance(comet.address, governor.address)).to.be.equal(0); @@ -51,7 +51,7 @@ describe('approveThis', function () { it('allows governor to authorize a manager', async () => { const protocol = await makeProtocol(); - const { comet, tokens, governor } = protocol; + const { cometWithExtendedAssetList : comet, tokens, governor } = protocol; const { COMP } = tokens; const newAllowance = exp(50, 18); @@ -62,7 +62,7 @@ describe('approveThis', function () { it('allows governor to rescind authorization', async () => { const protocol = await makeProtocol(); - const { comet, tokens, governor, users: [ user ] } = protocol; + const { cometWithExtendedAssetList : comet, tokens, governor, users: [ user ] } = protocol; const { COMP } = tokens; await comet.connect(governor).approveThis(user.address, COMP.address, ethers.constants.MaxUint256); @@ -76,7 +76,7 @@ describe('approveThis', function () { it('reverts if not called by governor', async () => { const protocol = await makeProtocol(); - const { comet, tokens, users: [ user ] } = protocol; + const { cometWithExtendedAssetList : comet, tokens, users: [ user ] } = protocol; const { COMP } = tokens; await expect(comet.connect(user).approveThis(user.address, COMP.address, ethers.constants.MaxUint256)) diff --git a/test/asset-info-test.ts b/test/asset-info-test.ts index 228ab3667..8865c8064 100644 --- a/test/asset-info-test.ts +++ b/test/asset-info-test.ts @@ -3,12 +3,12 @@ import { ethers } from 'hardhat'; import { SimplePriceFeed__factory, FaucetToken__factory, - CometHarness__factory + CometHarnessExtendedAssetList__factory } from '../build/types'; describe('asset info', function () { it('initializes protocol', async () => { - const { comet, tokens } = await makeProtocol({ + const { cometWithExtendedAssetList : comet, tokens } = await makeProtocol({ assets: { USDC: {}, ASSET1: {}, @@ -20,7 +20,7 @@ describe('asset info', function () { const cometNumAssets = await comet.numAssets(); const cometMaxAssets = await comet.maxAssets(); - expect(cometMaxAssets).to.be.equal(15); + expect(cometMaxAssets).to.be.equal(24); expect(cometNumAssets).to.be.equal(3); const assetInfo00 = await comet.getAssetInfo(0); @@ -59,6 +59,15 @@ describe('asset info', function () { ASSET14: {}, ASSET15: {}, ASSET16: {}, + ASSET17: {}, + ASSET18: {}, + ASSET19: {}, + ASSET20: {}, + ASSET21: {}, + ASSET22: {}, + ASSET23: {}, + ASSET24: {}, + ASSET25: {}, }; const base = 'USDC'; const PriceFeedFactory = (await ethers.getContractFactory('SimplePriceFeed')) as SimplePriceFeed__factory; @@ -117,14 +126,14 @@ describe('asset info', function () { return acc; }, []), }; - const CometFactory = (await ethers.getContractFactory('CometHarness')) as CometHarness__factory; + const CometFactory = (await ethers.getContractFactory('CometHarnessExtendedAssetList')) as CometHarnessExtendedAssetList__factory; await expect( CometFactory.deploy(config) ).to.be.revertedWith("custom error 'TooManyAssets()'"); }); it('reverts if index is greater than numAssets', async () => { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList : comet } = await makeProtocol(); await expect(comet.getAssetInfo(3)).to.be.revertedWith("custom error 'BadAsset()'"); }); diff --git a/test/balance-test.ts b/test/balance-test.ts index c325d117b..f6d7aa2af 100644 --- a/test/balance-test.ts +++ b/test/balance-test.ts @@ -2,7 +2,7 @@ import { expect, makeProtocol, setTotalsBasic } from './helpers'; describe('totalBorrow', function () { it('has correct totalBorrow', async () => { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList : comet } = await makeProtocol(); await setTotalsBasic(comet, { baseBorrowIndex: 2e15, totalBorrowBase: 50e6, @@ -13,7 +13,7 @@ describe('totalBorrow', function () { describe('borrowBalanceOf', function () { it('returns borrow amount (when principal amount is negative)', async () => { - const { comet, users: [user] } = await makeProtocol(); + const { cometWithExtendedAssetList : comet, users: [user] } = await makeProtocol(); await setTotalsBasic(comet, { baseSupplyIndex: 2e15, baseBorrowIndex: 3e15, @@ -24,7 +24,7 @@ describe('borrowBalanceOf', function () { }); it('returns 0 when principal amount is positive', async () => { - const { comet, users: [user] } = await makeProtocol(); + const { cometWithExtendedAssetList : comet, users: [user] } = await makeProtocol(); await setTotalsBasic(comet, { baseSupplyIndex: 2e15, baseBorrowIndex: 3e15, diff --git a/test/base-tracking-accrued-test.ts b/test/base-tracking-accrued-test.ts index 0d2634e17..4bb7a8e52 100644 --- a/test/base-tracking-accrued-test.ts +++ b/test/base-tracking-accrued-test.ts @@ -5,7 +5,7 @@ describe('baseTrackingAccrued', function() { const start = (await getBlock()).timestamp + 100; const { - comet, tokens, users: [alice] + cometWithExtendedAssetList : comet, tokens, users: [alice] } = await makeProtocol({ base: 'USDC', trackingIndexScale: 1e15, @@ -43,7 +43,7 @@ describe('baseTrackingAccrued', function() { it('updates with precision up to 6 decimal places', async () => { const { - comet, tokens, users: [alice] + cometWithExtendedAssetList : comet, tokens, users: [alice] } = await makeProtocol({ base: 'USDC', trackingIndexScale: 1e15, @@ -74,7 +74,7 @@ describe('baseTrackingAccrued', function() { it('rounds down to zero for values below 6 decimal places', async () => { const { - comet, tokens, users: [alice] + cometWithExtendedAssetList : comet, tokens, users: [alice] } = await makeProtocol({ base: 'USDC', trackingIndexScale: 1e15, @@ -103,7 +103,7 @@ describe('baseTrackingAccrued', function() { it('acrrues at a greater number of decimals, but preserves 6', async () => { const { - comet, tokens, users: [alice] + cometWithExtendedAssetList : comet, tokens, users: [alice] } = await makeProtocol({ base: 'USDC', trackingIndexScale: 1e15, @@ -136,7 +136,7 @@ describe('baseTrackingAccrued', function() { it('accrues correctly when base token has more than 6 decimals', async () => { const { - comet, tokens, users: [alice] + cometWithExtendedAssetList : comet, tokens, users: [alice] } = await makeProtocol({ base: 'WETH', trackingIndexScale: 1e15, @@ -169,7 +169,7 @@ describe('baseTrackingAccrued', function() { const start = (await getBlock()).timestamp + 100; const { - comet, tokens, users: [alice] + cometWithExtendedAssetList : comet, tokens, users: [alice] } = await makeProtocol({ base: 'USDC', trackingIndexScale: 1e15, diff --git a/test/bulker-test.ts b/test/bulker-test.ts index cfd5a9318..23f6dc7d4 100644 --- a/test/bulker-test.ts +++ b/test/bulker-test.ts @@ -6,7 +6,7 @@ import { FaucetWETH__factory, NonStandardFaucetToken__factory } from '../build/t describe('bulker', function () { it('supply base asset', async () => { const protocol = await makeProtocol({}); - const { comet, tokens: { USDC, WETH }, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { USDC, WETH }, users: [alice] } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -27,7 +27,7 @@ describe('bulker', function () { it('supply collateral asset', async () => { const protocol = await makeProtocol({}); - const { comet, tokens: { COMP, WETH }, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { COMP, WETH }, users: [alice] } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -124,7 +124,7 @@ describe('bulker', function () { it('supply collateral asset to a different account', async () => { const protocol = await makeProtocol({}); - const { comet, tokens: { COMP, WETH }, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { COMP, WETH }, users: [alice, bob] } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -150,7 +150,7 @@ describe('bulker', function () { WETH: { factory: await ethers.getContractFactory('FaucetWETH') as FaucetWETH__factory } }) }); - const { comet, tokens: { WETH }, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { WETH }, users: [alice] } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -170,7 +170,7 @@ describe('bulker', function () { WETH: { factory: await ethers.getContractFactory('FaucetWETH') as FaucetWETH__factory } }) }); - const { comet, tokens: { WETH }, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { WETH }, users: [alice] } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -193,7 +193,7 @@ describe('bulker', function () { WETH: { factory: await ethers.getContractFactory('FaucetWETH') as FaucetWETH__factory } }) }); - const { comet, tokens: { WETH }, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { WETH }, users: [alice] } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -219,7 +219,7 @@ describe('bulker', function () { borrowInterestRateBase: 0, borrowInterestRateSlopeLow: 0, }); - const { comet, tokens: { USDC, WETH }, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { USDC, WETH }, users: [alice] } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -256,7 +256,7 @@ describe('bulker', function () { WETH: { factory: await ethers.getContractFactory('FaucetWETH') as FaucetWETH__factory } }) }); - const { comet, tokens: { WETH }, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { WETH }, users: [alice] } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -271,7 +271,7 @@ describe('bulker', function () { it('transfer base asset', async () => { const protocol = await makeProtocol({}); - const { comet, tokens: { USDC, WETH }, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { USDC, WETH }, users: [alice, bob] } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -291,7 +291,7 @@ describe('bulker', function () { it('transfer collateral asset', async () => { const protocol = await makeProtocol({}); - const { comet, tokens: { COMP, WETH }, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { COMP, WETH }, users: [alice, bob] } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -311,7 +311,7 @@ describe('bulker', function () { it('withdraw base asset', async () => { const protocol = await makeProtocol({}); - const { comet, tokens: { USDC, WETH }, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { USDC, WETH }, users: [alice] } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -337,7 +337,7 @@ describe('bulker', function () { it('withdraw collateral asset', async () => { const protocol = await makeProtocol({}); - const { comet, tokens: { COMP, WETH }, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { COMP, WETH }, users: [alice] } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -444,7 +444,7 @@ describe('bulker', function () { it('withdraw collateral asset to a different account', async () => { const protocol = await makeProtocol({}); - const { comet, tokens: { COMP, WETH }, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { COMP, WETH }, users: [alice, bob] } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -475,7 +475,7 @@ describe('bulker', function () { WETH: { factory: await ethers.getContractFactory('FaucetWETH') as FaucetWETH__factory } }) }); - const { comet, tokens: { WETH }, users: [alice], governor } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { WETH }, users: [alice], governor } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -509,7 +509,7 @@ describe('bulker', function () { WETH: { factory: await ethers.getContractFactory('FaucetWETH') as FaucetWETH__factory } }) }); - const { comet, tokens: { WETH }, users: [alice], governor } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { WETH }, users: [alice], governor } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -539,7 +539,7 @@ describe('bulker', function () { WETH: { factory: await ethers.getContractFactory('FaucetWETH') as FaucetWETH__factory } }) }); - const { comet, tokens: { WETH }, users: [alice], governor } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { WETH }, users: [alice], governor } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -567,7 +567,7 @@ describe('bulker', function () { baseMinForRewards: 10e6, }); const { - comet, + cometWithExtendedAssetList : comet, governor, tokens: { USDC, COMP, WETH }, users: [alice], @@ -597,7 +597,7 @@ describe('bulker', function () { it('reverts on supply asset if no permission granted to bulker', async () => { const protocol = await makeProtocol({}); - const { comet, tokens: { USDC, WETH }, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { USDC, WETH }, users: [alice] } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -608,7 +608,7 @@ describe('bulker', function () { it('reverts on transfer asset if no permission granted to bulker', async () => { const protocol = await makeProtocol({}); - const { comet, tokens: { COMP, WETH }, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { COMP, WETH }, users: [alice, bob] } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -619,7 +619,7 @@ describe('bulker', function () { it('reverts on withdraw asset if no permission granted to bulker', async () => { const protocol = await makeProtocol({}); - const { comet, tokens: { COMP, WETH }, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { COMP, WETH }, users: [alice] } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -634,7 +634,7 @@ describe('bulker', function () { WETH: { factory: await ethers.getContractFactory('FaucetWETH') as FaucetWETH__factory } }) }); - const { comet, tokens: { WETH }, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { WETH }, users: [alice] } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -789,7 +789,7 @@ describe('bulker', function () { describe('bulker multiple actions', function () { it('supply collateral + borrow base asset', async () => { const protocol = await makeProtocol({}); - const { comet, tokens: { USDC, COMP, WETH }, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { USDC, COMP, WETH }, users: [alice] } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; @@ -829,7 +829,7 @@ describe('bulker multiple actions', function () { WETH: { factory: await ethers.getContractFactory('FaucetWETH') as FaucetWETH__factory } }) }); - const { comet, tokens: { WETH }, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList : comet, tokens: { WETH }, users: [alice, bob] } = protocol; const bulkerInfo = await makeBulker({ weth: WETH.address }); const { bulker } = bulkerInfo; diff --git a/test/buy-collateral-test.ts b/test/buy-collateral-test.ts index b82ad10ab..203139e02 100644 --- a/test/buy-collateral-test.ts +++ b/test/buy-collateral-test.ts @@ -21,7 +21,7 @@ describe('buyCollateral', function () { }, } }); - const { comet, tokens, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens, users: [alice] } = protocol; const { USDC, COMP } = tokens; const cometAsA = comet.connect(alice); const baseAsA = USDC.connect(alice); @@ -90,7 +90,7 @@ describe('buyCollateral', function () { }, } }); - const { comet, tokens, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens, users: [alice] } = protocol; const { USDC, COMP } = tokens; const cometAsA = comet.connect(alice); const baseAsA = USDC.connect(alice); @@ -152,7 +152,7 @@ describe('buyCollateral', function () { }, } }); - const { comet, tokens, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens, users: [alice] } = protocol; const { USDC, COMP } = tokens; const cometAsA = comet.connect(alice); const baseAsA = USDC.connect(alice); @@ -200,7 +200,7 @@ describe('buyCollateral', function () { }, } }); - const { comet, tokens, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens, users: [alice] } = protocol; const { USDC, COMP } = tokens; const cometAsA = comet.connect(alice); const baseAsA = USDC.connect(alice); @@ -219,7 +219,7 @@ describe('buyCollateral', function () { it('reverts if reserves are above target reserves', async () => { const protocol = await makeProtocol({base: 'USDC', targetReserves: 0}); - const { comet, tokens, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens, users: [alice] } = protocol; const { USDC, COMP } = tokens; const cometAsA = comet.connect(alice); const baseAsA = USDC.connect(alice); @@ -257,7 +257,7 @@ describe('buyCollateral', function () { }, } }); - const { comet, tokens, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens, users: [alice] } = protocol; const { USDC, COMP } = tokens; const cometAsA = comet.connect(alice); const baseAsA = USDC.connect(alice); @@ -292,7 +292,7 @@ describe('buyCollateral', function () { }, } }); - const { comet, tokens, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens, users: [alice] } = protocol; const { USDC, COMP } = tokens; const cometAsA = comet.connect(alice); const baseAsA = USDC.connect(alice); @@ -312,7 +312,7 @@ describe('buyCollateral', function () { it('reverts if buy is paused', async () => { const protocol = await makeProtocol({base: 'USDC', targetReserves: 0}); - const { comet, tokens, pauseGuardian, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens, pauseGuardian, users: [alice] } = protocol; const { COMP } = tokens; const cometAsA = comet.connect(alice); @@ -345,7 +345,7 @@ describe('buyCollateral', function () { } }); - const { comet, tokens, users: [alice] } = protocol; + const { cometWithExtendedAssetList : comet, tokens, users: [alice] } = protocol; const { USDT, COMP } = tokens; // Set both COMP and USDT with 1% fees @@ -431,7 +431,7 @@ describe('buyCollateral', function () { targetReserves: 1 }); const { - comet: normalComet, + cometWithExtendedAssetList : normalComet, tokens: normalTokens, users: [normalAlice, normalBob, evilAlice, evilBob] // addresses are constant } = normalProtocol; @@ -450,7 +450,7 @@ describe('buyCollateral', function () { targetReserves: 1 }); const { - comet: evilComet, + cometWithExtendedAssetList : evilComet, tokens: evilTokens, } = evilProtocol; const { WETH: evilWETH, EVIL } = <{WETH: FaucetToken, EVIL: EvilToken}>evilTokens; @@ -588,7 +588,7 @@ describe('buyCollateral', function () { targetReserves: 1 }); const { - comet: evilComet, + cometWithExtendedAssetList : evilComet, tokens: evilTokens, users: [evilAlice, evilBob] } = evilProtocol; diff --git a/test/comet-ext-test.ts b/test/comet-ext-test.ts index d297bf22b..008f7e9f1 100644 --- a/test/comet-ext-test.ts +++ b/test/comet-ext-test.ts @@ -1,46 +1,46 @@ -import { CometHarnessInterface, FaucetToken, NonStandardFaucetFeeToken } from '../build/types'; +import { CometHarnessInterfaceExtendedAssetList, FaucetToken, NonStandardFaucetFeeToken } from '../build/types'; import { expect, exp, makeProtocol, setTotalsBasic } from './helpers'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; describe('CometExt', function () { - let comet: CometHarnessInterface; + let cometWithExtendedAssetList: CometHarnessInterfaceExtendedAssetList; let user: SignerWithAddress; let tokens: { [symbol: string]: FaucetToken | NonStandardFaucetFeeToken }; beforeEach(async () => { ({ - comet, + cometWithExtendedAssetList, users: [user], tokens, } = await makeProtocol()); // Set different indices - await setTotalsBasic(comet, { + await setTotalsBasic(cometWithExtendedAssetList, { baseSupplyIndex: 2e15, baseBorrowIndex: 3e15, }); }); it('returns factor scale', async () => { - const factorScale = await comet.factorScale(); + const factorScale = await cometWithExtendedAssetList.factorScale(); expect(factorScale).to.eq(exp(1, 18)); }); it('returns price scale', async () => { - const priceScale = await comet.priceScale(); + const priceScale = await cometWithExtendedAssetList.priceScale(); expect(priceScale).to.eq(exp(1, 8)); }); it('returns collateralBalance (in units of the collateral asset)', async () => { const { WETH } = tokens; - await comet.setCollateralBalance( + await cometWithExtendedAssetList.setCollateralBalance( user.address, WETH.address, exp(5, 18) ); - const collateralBalanceOf = await comet.collateralBalanceOf( + const collateralBalanceOf = await cometWithExtendedAssetList.collateralBalanceOf( user.address, WETH.address ); diff --git a/test/configurator-test.ts b/test/configurator-test.ts index 4de0532f9..af5282a53 100644 --- a/test/configurator-test.ts +++ b/test/configurator-test.ts @@ -1,11 +1,12 @@ import { annualize, defactor, defaultAssets, ethers, event, exp, expect, factor, makeConfigurator, Numeric, truncateDecimals, wait } from './helpers'; import { + CometExtAssetList__factory, CometModifiedFactory__factory, MarketAdminPermissionChecker__factory, SimplePriceFeed__factory, SimpleTimelock__factory } from '../build/types'; -import { AssetInfoStructOutput } from '../build/types/CometHarnessInterface'; +import { AssetInfoStructOutput } from '../build/types/CometHarnessInterfaceExtendedAssetList'; import { ConfigurationStructOutput } from '../build/types/Configurator'; import { BigNumber } from 'ethers'; @@ -73,13 +74,19 @@ function expectAssetConfigsToMatch( describe('configurator', function () { it('deploys Comet', async () => { - const { configurator, configuratorProxy, cometProxy } = await makeConfigurator(); + const { configurator, configuratorProxy, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); const configuratorAsProxy = configurator.attach(configuratorProxy.address); const txn = await wait(configuratorAsProxy.deploy(cometProxy.address)) as any; - const [, newCometAddress] = txn.receipt.events.find(event => event.event === 'CometDeployed').args; + const cometDeployedEvent = txn.receipt.events.find((receiptEvent) => receiptEvent.event === 'CometDeployed'); + const [, newCometAddress] = cometDeployedEvent.args; - expect(event(txn, 0)).to.be.deep.equal({ + expect({ + CometDeployed: { + cometProxy: cometDeployedEvent.args.cometProxy, + newComet: newCometAddress, + } + }).to.be.deep.equal({ CometDeployed: { cometProxy: cometProxy.address, newComet: newCometAddress, @@ -88,7 +95,7 @@ describe('configurator', function () { }); it('deploys Comet from ProxyAdmin', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); expect(await proxyAdmin.getProxyImplementation(cometProxy.address)).to.be.equal(comet.address); expect(await proxyAdmin.getProxyImplementation(configuratorProxy.address)).to.be.equal(configurator.address); @@ -100,7 +107,7 @@ describe('configurator', function () { }); it('reverts if deploy is called from non-governor', async () => { - const { configuratorProxy, proxyAdmin, cometProxy, users: [alice], governor } = await makeConfigurator(); + const { configuratorProxy, proxyAdmin, cometProxyWithExtendedAssetList: cometProxy, users: [alice], governor } = await makeConfigurator(); const MarketAdminPermissionCheckerFactory = (await ethers.getContractFactory( 'MarketAdminPermissionChecker' @@ -117,7 +124,7 @@ describe('configurator', function () { }); it('e2e governance actions from timelock', async () => { - const { governor, configurator, configuratorProxy, proxyAdmin, cometProxy, users: [alice] } = await makeConfigurator(); + const { governor, configurator, configuratorProxy, proxyAdmin, cometProxyWithExtendedAssetList: cometProxy, users: [alice] } = await makeConfigurator(); const TimelockFactory = (await ethers.getContractFactory( 'SimpleTimelock' @@ -206,7 +213,7 @@ describe('configurator', function () { }); it('sets Configuration for a Comet proxy with an existing configuration', async () => { - const { configurator, configuratorProxy, cometProxy } = await makeConfigurator({ + const { configurator, configuratorProxy, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator({ assets: { USDC: { initial: 1e6, decimals: 6 }, } @@ -230,7 +237,7 @@ describe('configurator', function () { }); it('reverts when setting Configuration and changing baseToken for a Comet proxy with an existing configuration', async () => { - const { configurator, configuratorProxy, cometProxy, tokens } = await makeConfigurator(); + const { configurator, configuratorProxy, cometProxyWithExtendedAssetList: cometProxy, tokens } = await makeConfigurator(); const { COMP } = tokens; const configuratorAsProxy = configurator.attach(configuratorProxy.address); @@ -243,7 +250,7 @@ describe('configurator', function () { }); it('reverts when setting Configuration and changing trackingIndexScale for a Comet proxy with an existing configuration', async () => { - const { configurator, configuratorProxy, cometProxy } = await makeConfigurator(); + const { configurator, configuratorProxy, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); const configuratorAsProxy = configurator.attach(configuratorProxy.address); const oldConfiguration = await configuratorAsProxy.getConfiguration(cometProxy.address); @@ -255,7 +262,7 @@ describe('configurator', function () { }); it('reverts when setting bad Configuration for a Comet proxy with an existing configuration', async () => { - const { configurator, configuratorProxy, cometProxy } = await makeConfigurator(); + const { configurator, configuratorProxy, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); const configuratorAsProxy = configurator.attach(configuratorProxy.address); const oldConfiguration = await configuratorAsProxy.getConfiguration(cometProxy.address); @@ -267,7 +274,7 @@ describe('configurator', function () { }); it('sets governor and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy, users: [alice] } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy, users: [alice] } = await makeConfigurator(); const cometAsProxy = comet.attach(cometProxy.address); const configuratorAsProxy = configurator.attach(configuratorProxy.address); @@ -291,7 +298,7 @@ describe('configurator', function () { }); it('sets pauseGuardian and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy, users: [alice] } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy, users: [alice] } = await makeConfigurator(); const cometAsProxy = comet.attach(cometProxy.address); const configuratorAsProxy = configurator.attach(configuratorProxy.address); @@ -315,7 +322,7 @@ describe('configurator', function () { }); it('sets baseTokenPriceFeed and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); const cometAsProxy = comet.attach(cometProxy.address); const configuratorAsProxy = configurator.attach(configuratorProxy.address); @@ -344,14 +351,31 @@ describe('configurator', function () { }); it('sets extensionDelegate and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy } = await makeConfigurator(); + const { + configurator, + configuratorProxy, + proxyAdmin, + assetListFactory, + cometWithExtendedAssetList: comet, + cometProxyWithExtendedAssetList: cometProxy, + } = await makeConfigurator(); const cometAsProxy = comet.attach(cometProxy.address); const configuratorAsProxy = configurator.attach(configuratorProxy.address); expect((await configuratorAsProxy.getConfiguration(cometProxy.address)).extensionDelegate).to.be.equal(await comet.extensionDelegate()); + const CometExtAssetListFactory = (await ethers.getContractFactory('CometExtAssetList')) as CometExtAssetList__factory; + const newExtensionDelegateContract = await CometExtAssetListFactory.deploy( + { + name32: ethers.utils.formatBytes32String('Test Comet'), + symbol32: ethers.utils.formatBytes32String('tCOMET') + }, + assetListFactory.address + ); + await newExtensionDelegateContract.deployed(); + const oldExt = await comet.extensionDelegate(); - const newExt = ethers.constants.AddressZero; + const newExt = newExtensionDelegateContract.address; const txn = await wait(configuratorAsProxy.setExtensionDelegate(cometProxy.address, newExt)); await wait(proxyAdmin.deployAndUpgradeTo(configuratorProxy.address, cometProxy.address)); @@ -368,7 +392,7 @@ describe('configurator', function () { }); it('sets supplyKink and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); const cometAsProxy = comet.attach(cometProxy.address); const configuratorAsProxy = configurator.attach(configuratorProxy.address); @@ -392,7 +416,7 @@ describe('configurator', function () { }); it('sets supplyPerYearInterestRateSlopeLow and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); const cometAsProxy = comet.attach(cometProxy.address); const configuratorAsProxy = configurator.attach(configuratorProxy.address); @@ -418,7 +442,7 @@ describe('configurator', function () { }); it('sets supplyPerYearInterestRateSlopeHigh and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); const cometAsProxy = comet.attach(cometProxy.address); const configuratorAsProxy = configurator.attach(configuratorProxy.address); @@ -444,7 +468,7 @@ describe('configurator', function () { }); it('sets supplyPerYearInterestRateBase and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); const cometAsProxy = comet.attach(cometProxy.address); const configuratorAsProxy = configurator.attach(configuratorProxy.address); @@ -470,7 +494,7 @@ describe('configurator', function () { }); it('sets borrowKink and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); const cometAsProxy = comet.attach(cometProxy.address); const configuratorAsProxy = configurator.attach(configuratorProxy.address); @@ -494,7 +518,7 @@ describe('configurator', function () { }); it('sets borrowPerYearInterestRateSlopeLow and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); const cometAsProxy = comet.attach(cometProxy.address); const configuratorAsProxy = configurator.attach(configuratorProxy.address); @@ -520,7 +544,7 @@ describe('configurator', function () { }); it('sets borrowPerYearInterestRateSlopeHigh and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); const cometAsProxy = comet.attach(cometProxy.address); const configuratorAsProxy = configurator.attach(configuratorProxy.address); @@ -546,7 +570,7 @@ describe('configurator', function () { }); it('sets borrowPerYearInterestRateBase and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); const cometAsProxy = comet.attach(cometProxy.address); const configuratorAsProxy = configurator.attach(configuratorProxy.address); @@ -572,7 +596,7 @@ describe('configurator', function () { }); it('sets storeFrontPriceFactor and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy } = await makeConfigurator({ + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator({ assets: { USDC: { decimals: 6, }, COMP: { @@ -605,7 +629,7 @@ describe('configurator', function () { }); it('sets baseTrackingSupplySpeed and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); const cometAsProxy = comet.attach(cometProxy.address); const configuratorAsProxy = configurator.attach(configuratorProxy.address); @@ -629,7 +653,7 @@ describe('configurator', function () { }); it('sets baseTrackingBorrowSpeed and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); const cometAsProxy = comet.attach(cometProxy.address); const configuratorAsProxy = configurator.attach(configuratorProxy.address); @@ -653,7 +677,7 @@ describe('configurator', function () { }); it('sets baseMinForRewards and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); const cometAsProxy = comet.attach(cometProxy.address); const configuratorAsProxy = configurator.attach(configuratorProxy.address); @@ -677,7 +701,7 @@ describe('configurator', function () { }); it('sets baseBorrowMin and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); const cometAsProxy = comet.attach(cometProxy.address); const configuratorAsProxy = configurator.attach(configuratorProxy.address); @@ -701,7 +725,7 @@ describe('configurator', function () { }); it('sets targetReserves and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); const cometAsProxy = comet.attach(cometProxy.address); const configuratorAsProxy = configurator.attach(configuratorProxy.address); @@ -725,7 +749,7 @@ describe('configurator', function () { }); it('adds asset and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy, unsupportedToken } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy, unsupportedToken } = await makeConfigurator(); const cometAsProxy = comet.attach(cometProxy.address); const configuratorAsProxy = configurator.attach(configuratorProxy.address); @@ -756,7 +780,7 @@ describe('configurator', function () { }); it('updates asset and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy, tokens } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy, tokens } = await makeConfigurator(); const { COMP } = tokens; const cometAsProxy = comet.attach(cometProxy.address); @@ -798,7 +822,7 @@ describe('configurator', function () { }); it('updates asset priceFeed and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy, tokens, priceFeeds } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy, tokens, priceFeeds } = await makeConfigurator(); const { COMP } = tokens; const cometAsProxy = comet.attach(cometProxy.address); @@ -825,7 +849,7 @@ describe('configurator', function () { }); it('updates asset borrowCollateralFactor and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy, tokens } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy, tokens } = await makeConfigurator(); const { COMP } = tokens; const cometAsProxy = comet.attach(cometProxy.address); @@ -852,7 +876,7 @@ describe('configurator', function () { }); it('updates asset liquidateCollateralFactor and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy, tokens } = await makeConfigurator({ + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy, tokens } = await makeConfigurator({ assets: defaultAssets({}, { COMP: { borrowCF: exp(0.5, 18) } }) @@ -883,7 +907,7 @@ describe('configurator', function () { }); it('updates asset liquidationFactor and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy, tokens } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy, tokens } = await makeConfigurator(); const { COMP } = tokens; const cometAsProxy = comet.attach(cometProxy.address); @@ -910,7 +934,7 @@ describe('configurator', function () { }); it('updates asset supplyCap and deploys Comet with new configuration', async () => { - const { configurator, configuratorProxy, proxyAdmin, comet, cometProxy, tokens } = await makeConfigurator(); + const { configurator, configuratorProxy, proxyAdmin, cometWithExtendedAssetList: comet, cometProxyWithExtendedAssetList: cometProxy, tokens } = await makeConfigurator(); const { COMP } = tokens; const cometAsProxy = comet.attach(cometProxy.address); @@ -937,7 +961,7 @@ describe('configurator', function () { }); it('reverts if updating a non-existent asset', async () => { - const { configurator, configuratorProxy, cometProxy } = await makeConfigurator(); + const { configurator, configuratorProxy, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); const configuratorAsProxy = configurator.attach(configuratorProxy.address); @@ -947,7 +971,7 @@ describe('configurator', function () { }); it('reverts if setter is called from non-governor', async () => { - const { configuratorProxy, configurator, cometProxy, users: [alice] } = await makeConfigurator(); + const { configuratorProxy, configurator, cometProxyWithExtendedAssetList: cometProxy, users: [alice] } = await makeConfigurator(); const configuratorAsProxy = configurator.attach(configuratorProxy.address); await expect( diff --git a/test/constructor-test.ts b/test/constructor-test.ts index 3adfc8d89..616e87547 100644 --- a/test/constructor-test.ts +++ b/test/constructor-test.ts @@ -1,14 +1,15 @@ import { ethers, exp, expect, makeProtocol, ONE } from './helpers'; import { - CometExt__factory, - CometHarness__factory, + AssetListFactory__factory, + CometExtAssetList__factory, + CometHarnessExtendedAssetList__factory, FaucetToken__factory, SimplePriceFeed__factory, } from '../build/types'; describe('constructor', function () { it('sets the baseBorrowMin', async function () { - const { comet } = await makeProtocol({ + const { cometWithExtendedAssetList: comet } = await makeProtocol({ baseBorrowMin: exp(100, 6) }); expect(await comet.baseBorrowMin()).to.eq(exp(100, 6)); @@ -18,11 +19,15 @@ describe('constructor', function () { const [governor, pauseGuardian] = await ethers.getSigners(); // extension delegate - const CometExtFactory = (await ethers.getContractFactory('CometExt')) as CometExt__factory; + const AssetListFactory = (await ethers.getContractFactory('AssetListFactory')) as AssetListFactory__factory; + const assetListFactory = await AssetListFactory.deploy(); + await assetListFactory.deployed(); + + const CometExtFactory = (await ethers.getContractFactory('CometExtAssetList')) as CometExtAssetList__factory; const extensionDelegate = await CometExtFactory.deploy({ name32: ethers.utils.formatBytes32String('Compound Comet'), symbol32: ethers.utils.formatBytes32String('📈BASE') - }); + }, assetListFactory.address); await extensionDelegate.deployed(); // tokens @@ -51,7 +56,7 @@ describe('constructor', function () { priceFeeds[asset] = priceFeed; } - const CometFactory = (await ethers.getContractFactory('CometHarness')) as CometHarness__factory; + const CometFactory = (await ethers.getContractFactory('CometHarnessExtendedAssetList')) as CometHarnessExtendedAssetList__factory; await expect(CometFactory.deploy({ governor: governor.address, pauseGuardian: pauseGuardian.address, @@ -138,7 +143,7 @@ describe('constructor', function () { }); it('reverts if initializeStorage is called after initialization', async () => { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList: comet } = await makeProtocol(); await expect( comet.initializeStorage() ).to.be.revertedWith("custom error 'AlreadyInitialized()'"); @@ -147,7 +152,7 @@ describe('constructor', function () { it('is not possible to create a perSecondInterestRateSlopeLow above FACTOR_SCALE', async () => { const uint64Max = BigInt(2 ** 64) - 1n; - const { comet } = await makeProtocol({ + const { cometWithExtendedAssetList: comet } = await makeProtocol({ supplyInterestRateSlopeLow: uint64Max, borrowInterestRateSlopeLow: uint64Max }); diff --git a/test/erc20-test.ts b/test/erc20-test.ts index ca7d57aba..78e819c7c 100644 --- a/test/erc20-test.ts +++ b/test/erc20-test.ts @@ -2,25 +2,25 @@ import { baseBalanceOf, ethers, event, expect, makeProtocol, setTotalsBasic, wai describe('erc20', function () { it('has correct name', async () => { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList: comet } = await makeProtocol(); expect(await comet.name()).to.be.equal('Compound Comet'); }); it('has correct symbol', async () => { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList: comet } = await makeProtocol(); expect(await comet.symbol()).to.be.equal('📈BASE'); }); it('has correct decimals', async () => { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList: comet } = await makeProtocol(); expect(await comet.decimals()).to.be.equal(6); }); it('has correct totalSupply', async () => { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList: comet } = await makeProtocol(); await setTotalsBasic(comet, { baseSupplyIndex: 2e15, @@ -35,7 +35,7 @@ describe('erc20', function () { describe('balanceOf', function () { it('returns presentValue of principal (when principal is positive)', async () => { const { - comet, + cometWithExtendedAssetList: comet, users: [user], } = await makeProtocol(); @@ -52,7 +52,7 @@ describe('erc20', function () { it('returns 0 (when principal amount is negative)', async () => { const { - comet, + cometWithExtendedAssetList: comet, users: [user], } = await makeProtocol(); @@ -65,7 +65,7 @@ describe('erc20', function () { it('performs ERC20 transfer of base', async () => { const { - comet, + cometWithExtendedAssetList: comet, users: [alice, bob], } = await makeProtocol(); @@ -99,7 +99,7 @@ describe('erc20', function () { describe('transferFrom', function() { it('performs ERC20 transferFrom when user transfers their own funds', async () => { const { - comet, + cometWithExtendedAssetList: comet, users: [alice, bob], } = await makeProtocol(); @@ -116,7 +116,7 @@ describe('erc20', function () { it('reverts ERC20 transferFrom without approval', async () => { const { - comet, + cometWithExtendedAssetList: comet, users: [alice, bob], } = await makeProtocol(); @@ -129,7 +129,7 @@ describe('erc20', function () { it('performs ERC20 transferFrom of base with approval', async () => { const { - comet, + cometWithExtendedAssetList: comet, users: [alice, bob], } = await makeProtocol(); @@ -152,7 +152,7 @@ describe('erc20', function () { it('reverts ERC20 transferFrom with revoked approval', async () => { const { - comet, + cometWithExtendedAssetList: comet, users: [alice, bob], } = await makeProtocol(); @@ -181,7 +181,7 @@ describe('erc20', function () { describe('approve', function() { it('sets isAllowed=true when user approves address for uint256 max', async () => { const { - comet, + cometWithExtendedAssetList: comet, users: [user, spender] } = await makeProtocol(); @@ -201,7 +201,7 @@ describe('erc20', function () { it('sets isAllowed=false when user passes 0', async () => { const { - comet, + cometWithExtendedAssetList: comet, users: [user, spender] } = await makeProtocol(); @@ -220,7 +220,7 @@ describe('erc20', function () { it('reverts when user approves for value that is not 0 or uint256.max', async () => { const { - comet, + cometWithExtendedAssetList: comet, users: [user, spender] } = await makeProtocol(); @@ -233,7 +233,7 @@ describe('erc20', function () { describe('allowance', function() { it('returns unint256.max when spender has permission for user', async () => { const { - comet, + cometWithExtendedAssetList: comet, users: [user, spender] } = await makeProtocol(); @@ -246,7 +246,7 @@ describe('erc20', function () { it('returns 0 when spender does not have permission for user', async () => { const { - comet, + cometWithExtendedAssetList: comet, users: [user, spender] } = await makeProtocol(); diff --git a/test/helpers.ts b/test/helpers.ts index 53fcda4a4..3679cd22b 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -6,12 +6,9 @@ import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; import { BaseBulker, BaseBulker__factory, - CometExt, - CometExt__factory, CometExtAssetList, CometExtAssetList__factory, - CometHarness__factory, - CometHarnessInterface as Comet, + CometHarnessInterfaceExtendedAssetList as Comet, CometRewards, CometRewards__factory, EvilToken__factory, @@ -26,13 +23,11 @@ import { ConfiguratorProxy__factory, CometProxyAdmin, CometProxyAdmin__factory, - CometFactory, - CometFactory__factory, CometFactoryWithExtendedAssetList, CometFactoryWithExtendedAssetList__factory, Configurator, Configurator__factory, - CometHarnessInterface, + CometHarnessInterfaceExtendedAssetList, CometInterface, NonStandardFaucetFeeToken, NonStandardFaucetFeeToken__factory, @@ -44,7 +39,7 @@ import { } from '../build/types'; import { BigNumber } from 'ethers'; import { TransactionReceipt, TransactionResponse } from '@ethersproject/abstract-provider'; -import { TotalsBasicStructOutput, TotalsCollateralStructOutput } from '../build/types/CometHarness'; +import { TotalsBasicStructOutput, TotalsCollateralStructOutput } from '../build/types/CometHarnessExtendedAssetList'; export { Comet, ethers, expect, hre }; @@ -77,7 +72,7 @@ export type ProtocolOpts = { symbol?: string; governor?: SignerWithAddress; pauseGuardian?: SignerWithAddress; - extensionDelegate?: CometExt; + extensionDelegateAssetList?: CometExtAssetList; base?: string; reward?: string; supplyKink?: Numeric; @@ -103,12 +98,10 @@ export type Protocol = { opts: ProtocolOpts; governor: SignerWithAddress; pauseGuardian: SignerWithAddress; - extensionDelegate: CometExt; extensionDelegateAssetList: CometExtAssetList; users: SignerWithAddress[]; base: string; reward: string; - comet: Comet; cometWithExtendedAssetList: CometWithExtendedAssetList; assetListFactory: AssetListFactory; tokens: { @@ -124,9 +117,7 @@ export type ConfiguratorAndProtocol = { configurator: Configurator; configuratorProxy: ConfiguratorProxy; proxyAdmin: CometProxyAdmin; - cometFactory: CometFactory; cometFactoryWithExtendedAssetList: CometFactoryWithExtendedAssetList; - cometProxy: TransparentUpgradeableProxy; cometProxyWithExtendedAssetList: TransparentUpgradeableProxy; } & Protocol; @@ -294,18 +285,17 @@ export async function makeProtocol(opts: ProtocolOpts = {}): Promise { const assetListFactory = await AssetListFactory.deploy(); await assetListFactory.deployed(); - let extensionDelegate = opts.extensionDelegate; - if (extensionDelegate === undefined) { - const CometExtFactory = (await ethers.getContractFactory('CometExt')) as CometExt__factory; - extensionDelegate = await CometExtFactory.deploy({ name32, symbol32 }); - await extensionDelegate.deployed(); + let extensionDelegateAssetList = opts.extensionDelegateAssetList; + if (extensionDelegateAssetList === undefined) { + const CometExtFactory = (await ethers.getContractFactory('CometExtAssetList')) as CometExtAssetList__factory; + extensionDelegateAssetList = await CometExtFactory.deploy({ name32, symbol32 }, assetListFactory.address); + await extensionDelegateAssetList.deployed(); } - const CometFactory = (await ethers.getContractFactory('CometHarness')) as CometHarness__factory; const config = { governor: governor.address, pauseGuardian: pauseGuardian.address, - extensionDelegate: extensionDelegate.address, + extensionDelegate: extensionDelegateAssetList.address, baseToken: tokens[base].address, baseTokenPriceFeed: priceFeeds[base].address, supplyKink, @@ -338,9 +328,6 @@ export async function makeProtocol(opts: ProtocolOpts = {}): Promise { return acc; }, []), }; - const comet = await CometFactory.deploy(config); - await comet.deployed(); - config.assetConfigs = Object.entries(assets).reduce((acc, [symbol, config], _i) => { if (symbol != base) { acc.push({ @@ -355,39 +342,28 @@ export async function makeProtocol(opts: ProtocolOpts = {}): Promise { } return acc; }, []); - let extensionDelegateAssetList = opts.extensionDelegate; - if (extensionDelegateAssetList === undefined) { - const CometExtFactory = (await ethers.getContractFactory('CometExtAssetList')) as CometExtAssetList__factory; - extensionDelegateAssetList = await CometExtFactory.deploy({ name32, symbol32 }, assetListFactory.address); - await extensionDelegateAssetList.deployed(); - } - config.extensionDelegate = extensionDelegateAssetList.address; const CometFactoryWithExtendedAssetList = (await ethers.getContractFactory('CometHarnessExtendedAssetList')) as CometHarnessExtendedAssetList__factory; const cometWithExtendedAssetList = await CometFactoryWithExtendedAssetList.deploy(config); await cometWithExtendedAssetList.deployed(); if (opts.start) await ethers.provider.send('evm_setNextBlockTimestamp', [opts.start]); - await comet.initializeStorage(); - await cometWithExtendedAssetList.initializeStorage(); const baseTokenBalance = opts.baseTokenBalance; if (baseTokenBalance) { const baseToken = tokens[base]; - await wait(baseToken.allocateTo(comet.address, baseTokenBalance)); + await wait(baseToken.allocateTo(cometWithExtendedAssetList.address, baseTokenBalance)); } return { opts, governor, pauseGuardian, - extensionDelegate, extensionDelegateAssetList: extensionDelegateAssetList as CometExtAssetList, users, base, reward, - comet: await ethers.getContractAt('CometHarnessInterface', comet.address) as Comet, cometWithExtendedAssetList: await ethers.getContractAt('CometHarnessInterfaceExtendedAssetList', cometWithExtendedAssetList.address) as CometWithExtendedAssetList, assetListFactory: assetListFactory, tokens, @@ -398,10 +374,10 @@ export async function makeProtocol(opts: ProtocolOpts = {}): Promise { export async function getConfigurationForConfigurator( opts: ProtocolOpts, - comet: CometHarnessInterface, + cometWithExtendedAssetList: CometHarnessInterfaceExtendedAssetList, governor: SignerWithAddress, pauseGuardian: SignerWithAddress, - extensionDelegate: CometExt, + extensionDelegateAssetList: CometExtAssetList, tokens: { [p: string]: FaucetToken | NonStandardFaucetFeeToken; }, @@ -419,19 +395,15 @@ export async function getConfigurationForConfigurator( const borrowPerYearInterestRateBase = dfn(opts.borrowInterestRateBase, exp(0.005, 18)); const borrowPerYearInterestRateSlopeLow = dfn(opts.borrowInterestRateSlopeLow, exp(0.1, 18)); const borrowPerYearInterestRateSlopeHigh = dfn(opts.borrowInterestRateSlopeHigh, exp(3, 18)); - const storeFrontPriceFactor = await comet.storeFrontPriceFactor(); - const trackingIndexScale = await comet.trackingIndexScale(); - const baseTrackingSupplySpeed = await comet.baseTrackingSupplySpeed(); - const baseTrackingBorrowSpeed = await comet.baseTrackingBorrowSpeed(); - const baseMinForRewards = await comet.baseMinForRewards(); - const baseBorrowMin = await comet.baseBorrowMin(); - const targetReserves = await comet.targetReserves(); + const storeFrontPriceFactor = await cometWithExtendedAssetList.storeFrontPriceFactor(); + const trackingIndexScale = await cometWithExtendedAssetList.trackingIndexScale(); + const baseTrackingSupplySpeed = await cometWithExtendedAssetList.baseTrackingSupplySpeed(); + const baseTrackingBorrowSpeed = await cometWithExtendedAssetList.baseTrackingBorrowSpeed(); + const baseMinForRewards = await cometWithExtendedAssetList.baseMinForRewards(); + const baseBorrowMin = await cometWithExtendedAssetList.baseBorrowMin(); + const targetReserves = await cometWithExtendedAssetList.targetReserves(); // Deploy CometFactory - const CometFactoryFactory = (await ethers.getContractFactory('CometFactory')) as CometFactory__factory; - const cometFactory = await CometFactoryFactory.deploy(); - await cometFactory.deployed(); - const CometFactoryWithExtendedAssetListFactory = (await ethers.getContractFactory('CometFactoryWithExtendedAssetList')) as CometFactoryWithExtendedAssetList__factory; const cometFactoryWithExtendedAssetList = await CometFactoryWithExtendedAssetListFactory.deploy(); await cometFactoryWithExtendedAssetList.deployed(); @@ -443,7 +415,7 @@ export async function getConfigurationForConfigurator( const configuration = { governor: governor.address, pauseGuardian: pauseGuardian.address, - extensionDelegate: extensionDelegate.address, + extensionDelegate: extensionDelegateAssetList.address, baseToken: tokens[base].address, baseTokenPriceFeed: priceFeeds[base].address, supplyKink, @@ -484,13 +456,11 @@ export async function makeConfigurator(opts: ProtocolOpts = {}): Promise { bulker }; } -export async function bumpTotalsCollateral(comet: CometHarnessInterface, token: FaucetToken | NonStandardFaucetFeeToken, delta: bigint): Promise { - const t0 = await comet.totalsCollateral(token.address); +export async function bumpTotalsCollateral(cometWithExtendedAssetList: CometHarnessInterfaceExtendedAssetList, token: FaucetToken | NonStandardFaucetFeeToken, delta: bigint): Promise { + const t0 = await cometWithExtendedAssetList.totalsCollateral(token.address); const t1 = Object.assign({}, t0, { totalSupplyAsset: t0.totalSupplyAsset.toBigInt() + delta }); - await token.allocateTo(comet.address, delta); - await wait(comet.setTotalsCollateral(token.address, t1)); + await token.allocateTo(cometWithExtendedAssetList.address, delta); + await wait(cometWithExtendedAssetList.setTotalsCollateral(token.address, t1)); return t1; } -export async function setTotalsBasic(comet: CometHarnessInterface, overrides = {}): Promise { - const t0 = await comet.totalsBasic(); +export async function setTotalsBasic(cometWithExtendedAssetList: CometHarnessInterfaceExtendedAssetList, overrides = {}): Promise { + const t0 = await cometWithExtendedAssetList.totalsBasic(); const t1 = Object.assign({}, t0, overrides); - await wait(comet.setTotalsBasic(t1)); + await wait(cometWithExtendedAssetList.setTotalsBasic(t1)); return t1; } @@ -695,25 +654,25 @@ type TotalsAndReserves = { }; } -export async function portfolio({ comet, base, tokens }, account): Promise { - const internal = { [base]: await baseBalanceOf(comet, account) }; +export async function portfolio({ cometWithExtendedAssetList, base, tokens }, account): Promise { + const internal = { [base]: await baseBalanceOf(cometWithExtendedAssetList, account) }; const external = { [base]: BigInt(await tokens[base].balanceOf(account)) }; for (const symbol in tokens) { if (symbol != base) { - internal[symbol] = BigInt(await comet.collateralBalanceOf(account, tokens[symbol].address)); + internal[symbol] = BigInt(await cometWithExtendedAssetList.collateralBalanceOf(account, tokens[symbol].address)); external[symbol] = BigInt(await tokens[symbol].balanceOf(account)); } } return { internal, external }; } -export async function totalsAndReserves({ comet, base, tokens }): Promise { - const totals = { [base]: BigInt((await comet.totalsBasic()).totalSupplyBase) }; - const reserves = { [base]: BigInt(await comet.getReserves()) }; +export async function totalsAndReserves({ cometWithExtendedAssetList, base, tokens }): Promise { + const totals = { [base]: BigInt((await cometWithExtendedAssetList.totalsBasic()).totalSupplyBase) }; + const reserves = { [base]: BigInt(await cometWithExtendedAssetList.getReserves()) }; for (const symbol in tokens) { if (symbol != base) { - totals[symbol] = BigInt((await comet.totalsCollateral(tokens[symbol].address)).totalSupplyAsset); - reserves[symbol] = BigInt(await comet.getCollateralReserves(tokens[symbol].address)); + totals[symbol] = BigInt((await cometWithExtendedAssetList.totalsCollateral(tokens[symbol].address)).totalSupplyAsset); + reserves[symbol] = BigInt(await cometWithExtendedAssetList.getCollateralReserves(tokens[symbol].address)); } } return { totals, reserves }; diff --git a/test/interest-rate-test.ts b/test/interest-rate-test.ts index 214c046cc..672c72694 100644 --- a/test/interest-rate-test.ts +++ b/test/interest-rate-test.ts @@ -25,7 +25,7 @@ const interestRateParams = { describe('interest rates', function () { it('when below kink utilization', async () => { - const { comet } = await makeProtocol(interestRateParams); + const { cometWithExtendedAssetList: comet } = await makeProtocol(interestRateParams); // 10% utilization const totals = { @@ -56,7 +56,7 @@ describe('interest rates', function () { }); it('when above kink utilization', async () => { - const { comet } = await makeProtocol(interestRateParams); + const { cometWithExtendedAssetList: comet } = await makeProtocol(interestRateParams); // 90% utilization const totals = { @@ -87,7 +87,7 @@ describe('interest rates', function () { }); it('when 0 utilization', async () => { - const { comet } = await makeProtocol(interestRateParams); + const { cometWithExtendedAssetList: comet } = await makeProtocol(interestRateParams); // 0% utilization const totals = { diff --git a/test/is-borrow-collateralized-test.ts b/test/is-borrow-collateralized-test.ts index 9b44da0bd..44f36f8a2 100644 --- a/test/is-borrow-collateralized-test.ts +++ b/test/is-borrow-collateralized-test.ts @@ -4,7 +4,7 @@ describe('isBorrowCollateralized', function () { it('defaults to true', async () => { const protocol = await makeProtocol({ base: 'USDC' }); const { - comet, + cometWithExtendedAssetList: comet, users: [alice], } = protocol; @@ -13,7 +13,7 @@ describe('isBorrowCollateralized', function () { it('is true when user is owed principal', async () => { const { - comet, + cometWithExtendedAssetList: comet, users: [alice], } = await makeProtocol({ base: 'USDC' }); await comet.setBasePrincipal(alice.address, 1_000_000); @@ -23,7 +23,7 @@ describe('isBorrowCollateralized', function () { it('is false when user owes principal', async () => { const { - comet, + cometWithExtendedAssetList: comet, users: [alice], } = await makeProtocol({ base: 'USDC' }); @@ -34,7 +34,7 @@ describe('isBorrowCollateralized', function () { it('is true when value of collateral is greater than principal owed', async () => { const { - comet, + cometWithExtendedAssetList: comet, tokens, users: [alice], } = await makeProtocol({ @@ -59,7 +59,7 @@ describe('isBorrowCollateralized', function () { it('takes borrow collateral factor into account when valuing collateral', async () => { const { - comet, + cometWithExtendedAssetList: comet, tokens, users: [alice], } = await makeProtocol({ @@ -86,7 +86,7 @@ describe('isBorrowCollateralized', function () { it('changes when the underlying asset price changes', async () => { const { - comet, + cometWithExtendedAssetList: comet, tokens, users: [alice], priceFeeds, diff --git a/test/is-liquidatable-test.ts b/test/is-liquidatable-test.ts index 2984910d9..2b621317b 100644 --- a/test/is-liquidatable-test.ts +++ b/test/is-liquidatable-test.ts @@ -14,7 +14,7 @@ describe('isLiquidatable', function () { it('defaults to false', async () => { const protocol = await makeProtocol(); const { - comet, + cometWithExtendedAssetList: comet, users: [alice], } = protocol; @@ -23,7 +23,7 @@ describe('isLiquidatable', function () { it('is false when user is owed principal', async () => { const { - comet, + cometWithExtendedAssetList: comet, users: [alice], } = await makeProtocol(); await comet.setBasePrincipal(alice.address, 1_000_000); @@ -33,7 +33,7 @@ describe('isLiquidatable', function () { it('is true when user owes principal', async () => { const { - comet, + cometWithExtendedAssetList: comet, users: [alice], } = await makeProtocol(); await comet.setBasePrincipal(alice.address, -1_000_000); @@ -43,7 +43,7 @@ describe('isLiquidatable', function () { it('is false when collateral can cover the borrowed principal', async () => { const { - comet, + cometWithExtendedAssetList: comet, tokens, users: [alice], } = await makeProtocol({ @@ -68,7 +68,7 @@ describe('isLiquidatable', function () { it('is true when the collateral cannot cover the borrowed principal', async () => { const { - comet, + cometWithExtendedAssetList: comet, tokens, users: [alice], } = await makeProtocol({ @@ -93,7 +93,7 @@ describe('isLiquidatable', function () { it('takes liquidateCollateralFactor into account when comparing principal to collateral', async () => { const { - comet, + cometWithExtendedAssetList: comet, tokens, users: [alice], } = await makeProtocol({ @@ -120,7 +120,7 @@ describe('isLiquidatable', function () { it('changes when the underlying asset price changes', async () => { const { - comet, + cometWithExtendedAssetList: comet, tokens, users: [alice], priceFeeds, diff --git a/test/liquidation/liquidation-bot-script.ts b/test/liquidation/liquidation-bot-script.ts index 34822d6eb..9243fd2af 100644 --- a/test/liquidation/liquidation-bot-script.ts +++ b/test/liquidation/liquidation-bot-script.ts @@ -2,7 +2,7 @@ import { expect, exp } from '../helpers'; import { arbitragePurchaseableCollateral, getAssets, hasPurchaseableCollateral, liquidateUnderwaterBorrowers } from '../../scripts/liquidation_bot/liquidateUnderwaterBorrowers'; import { forkMainnet, makeProtocol, makeLiquidatableProtocol, resetHardhatNetwork } from './makeLiquidatableProtocol'; -describe('Liquidation Bot', function () { +describe.skip('Liquidation Bot', function () { before(forkMainnet); after(resetHardhatNetwork); diff --git a/test/liquidation/liquidation-bot-test.ts b/test/liquidation/liquidation-bot-test.ts index 7586e6dbd..24bfbce77 100644 --- a/test/liquidation/liquidation-bot-test.ts +++ b/test/liquidation/liquidation-bot-test.ts @@ -3,7 +3,7 @@ import { ethers } from 'hardhat'; import { Exchange, forkMainnet, makeLiquidatableProtocol, resetHardhatNetwork } from './makeLiquidatableProtocol'; import { DAI, SUSHISWAP_ROUTER, UNISWAP_ROUTER } from './addresses'; -describe('Liquidator', function () { +describe.skip('Liquidator', function () { before(forkMainnet); after(resetHardhatNetwork); diff --git a/test/liquidation/makeLiquidatableProtocol.ts b/test/liquidation/makeLiquidatableProtocol.ts index 9561a58cb..c90511ab9 100644 --- a/test/liquidation/makeLiquidatableProtocol.ts +++ b/test/liquidation/makeLiquidatableProtocol.ts @@ -3,8 +3,8 @@ import { exp, setTotalsBasic } from '../helpers'; import { HttpNetworkConfig } from 'hardhat/types/config'; import { CometExt__factory, - CometHarness__factory, - CometHarnessInterface, + CometHarnessExtendedAssetList__factory, + CometHarnessInterfaceExtendedAssetList, OnChainLiquidator__factory } from '../../build/types'; import { @@ -58,7 +58,7 @@ export async function makeProtocol() { const extensionDelegate = await CometExtFactory.deploy({ name32, symbol32 }); await extensionDelegate.deployed(); - const CometFactory = (await ethers.getContractFactory('CometHarness')) as CometHarness__factory; + const CometFactory = (await ethers.getContractFactory('CometHarnessExtendedAssetList')) as CometHarnessExtendedAssetList__factory; const config = { governor: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', pauseGuardian: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', @@ -131,7 +131,7 @@ export async function makeProtocol() { const comet = await CometFactory.deploy(config); await comet.deployed(); - const cometHarnessInterface = await ethers.getContractAt('CometHarnessInterface', comet.address) as CometHarnessInterface; + const cometHarnessInterface = await ethers.getContractAt('CometHarnessInterfaceExtendedAssetList', comet.address) as CometHarnessInterfaceExtendedAssetList; const [signer,, recipient] = await ethers.getSigners(); diff --git a/test/marketupdates/existing-flow-test.ts b/test/marketupdates/existing-flow-test.ts index acce947bf..5907b2b5b 100644 --- a/test/marketupdates/existing-flow-test.ts +++ b/test/marketupdates/existing-flow-test.ts @@ -14,7 +14,7 @@ describe('configurator', function() { const { configurator, configuratorProxy, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, users: [alice] } = await makeConfigurator({ governor: signer @@ -55,7 +55,7 @@ describe('configurator', function() { const { configurator, configuratorProxy, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, users: [alice] } = await makeConfigurator({ governor: signer }); @@ -86,7 +86,7 @@ describe('configurator', function() { governor, configurator, configuratorProxy, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, users: [alice] } = await makeConfigurator({ governor: signer }); @@ -114,7 +114,7 @@ describe('configurator', function() { const { configuratorProxy, proxyAdmin, - cometProxy + cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator({ governor: signer }); let deployAndUpgradeToCalldata = ethers.utils.defaultAbiCoder.encode( @@ -166,7 +166,7 @@ describe('configurator', function() { const { configuratorProxy, proxyAdmin, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, users: [alice] } = await makeConfigurator({ governor: signer }); @@ -192,8 +192,8 @@ describe('configurator', function() { configurator, configuratorProxy, proxyAdmin, - comet, - cometProxy, + cometWithExtendedAssetList: comet, + cometProxyWithExtendedAssetList: cometProxy, users: [alice] } = await makeConfigurator(); @@ -233,7 +233,7 @@ describe('configurator', function() { const { configuratorProxy, proxyAdmin, - comet, + cometWithExtendedAssetList: comet, users: [_alice, bob] } = await makeConfigurator(); @@ -269,8 +269,8 @@ describe('configurator', function() { governor, configuratorProxy, proxyAdmin, - cometProxy, - comet, + cometProxyWithExtendedAssetList: cometProxy, + cometWithExtendedAssetList: comet, users: [_alice] } = await makeConfigurator({ governor: signer }); const GovernorFactory = (await ethers.getContractFactory( diff --git a/test/marketupdates/market-update-comet-proxy-admin-test.ts b/test/marketupdates/market-update-comet-proxy-admin-test.ts index fa55d4b17..dc5401a26 100644 --- a/test/marketupdates/market-update-comet-proxy-admin-test.ts +++ b/test/marketupdates/market-update-comet-proxy-admin-test.ts @@ -70,7 +70,7 @@ describe('CometProxyAdmin', function() { const { configuratorProxy, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, proxyAdmin, } = await makeConfigurator({ governor: governorTimelockSigner, @@ -141,7 +141,7 @@ describe('CometProxyAdmin', function() { const { configuratorProxy, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, proxyAdmin, } = await makeConfigurator({ governor: governorTimelockSigner, @@ -219,7 +219,7 @@ describe('CometProxyAdmin', function() { const { configuratorProxy, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, proxyAdmin, users: [alice], } = await makeConfigurator({ @@ -241,7 +241,7 @@ describe('CometProxyAdmin', function() { const { configuratorProxy, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, proxyAdmin, users: [alice], } = await makeConfigurator({ @@ -270,7 +270,7 @@ describe('CometProxyAdmin', function() { const { configuratorProxy, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, proxyAdmin, } = await makeConfigurator({ governor: governorTimelockSigner, @@ -299,7 +299,7 @@ describe('CometProxyAdmin', function() { const { configuratorProxy, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, proxyAdmin, } = await makeConfigurator({ governor: governorTimelockSigner, diff --git a/test/marketupdates/market-update-configurator-test.ts b/test/marketupdates/market-update-configurator-test.ts index 5a850d7fe..44edaf3f6 100644 --- a/test/marketupdates/market-update-configurator-test.ts +++ b/test/marketupdates/market-update-configurator-test.ts @@ -41,7 +41,7 @@ describe('Configurator', function() { const { configurator, configuratorProxy, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, } = await makeConfigurator({ governor: governorTimelockSigner, marketAdminPermissionCheckerContract: marketAdminPermissionCheckerContract @@ -115,7 +115,7 @@ describe('Configurator', function() { const { configurator, configuratorProxy, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, users: [alice], } = await makeConfigurator({ governor: governorTimelockSigner, @@ -146,7 +146,7 @@ describe('Configurator', function() { const { configurator, configuratorProxy, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, } = await makeConfigurator({ governor: governorTimelockSigner, marketAdminPermissionCheckerContract: marketAdminPermissionCheckerContract @@ -182,7 +182,7 @@ describe('Configurator', function() { const { configurator, configuratorProxy, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, } = await makeConfigurator({ governor: governorTimelockSigner, }); @@ -230,7 +230,7 @@ describe('Configurator', function() { const { configurator, configuratorProxy, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, users: [alice], } = await makeConfigurator({ governor: governorTimelockSigner, @@ -260,7 +260,7 @@ describe('Configurator', function() { const { configurator, configuratorProxy, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, } = await makeConfigurator({ governor: governorTimelockSigner, marketAdminPermissionCheckerContract: marketAdminPermissionCheckerContract diff --git a/test/marketupdates/market-update-deployment-test.ts b/test/marketupdates/market-update-deployment-test.ts index 0602ce70d..2adb9ebbf 100644 --- a/test/marketupdates/market-update-deployment-test.ts +++ b/test/marketupdates/market-update-deployment-test.ts @@ -5,7 +5,7 @@ import { advanceTimeAndMineBlock, } from './market-updates-helper'; import { - CometFactory__factory, + CometFactoryWithExtendedAssetList__factory, CometProxyAdmin__factory, CometProxyAdminOld__factory, Configurator__factory, @@ -356,9 +356,9 @@ describe('MarketUpdateDeployment', function() { const { governor, pauseGuardian, - extensionDelegate, + extensionDelegateAssetList: extensionDelegate, base, - comet, + cometWithExtendedAssetList: comet, tokens, priceFeeds, } = await makeProtocol({ @@ -388,7 +388,7 @@ describe('MarketUpdateDeployment', function() { // Derive the rest of the Configurator configuration values // Deploy CometFactory - const CometFactoryFactory = (await ethers.getContractFactory('CometFactory')) as CometFactory__factory; + const CometFactoryFactory = (await ethers.getContractFactory('CometFactoryWithExtendedAssetList')) as CometFactoryWithExtendedAssetList__factory; const cometFactory = await CometFactoryFactory.deploy(); await cometFactory.deployed(); diff --git a/test/marketupdates/market-update-proposer-test.ts b/test/marketupdates/market-update-proposer-test.ts index 16b9ca00d..5dacc8676 100644 --- a/test/marketupdates/market-update-proposer-test.ts +++ b/test/marketupdates/market-update-proposer-test.ts @@ -86,7 +86,7 @@ describe('MarketUpdateProposer', function() { const { configuratorProxy, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, users: [alice], } = await makeConfigurator(); @@ -143,7 +143,7 @@ describe('MarketUpdateProposer', function() { marketUpdateMultiSig, } = await makeMarketAdmin(); - const { configuratorProxy, cometProxy } = await makeConfigurator(); + const { configuratorProxy, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); let setSupplyKinkCalldata = ethers.utils.defaultAbiCoder.encode( ['address', 'uint64'], @@ -183,7 +183,7 @@ describe('MarketUpdateProposer', function() { marketUpdateMultiSig, } = await makeMarketAdmin(); - const { configuratorProxy, cometProxy } = await makeConfigurator(); + const { configuratorProxy, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); let setSupplyKinkCalldata = ethers.utils.defaultAbiCoder.encode( ['address', 'uint64'], @@ -228,7 +228,7 @@ describe('MarketUpdateProposer', function() { marketUpdateMultiSig, } = await makeMarketAdmin(); - const { configuratorProxy, cometProxy } = await makeConfigurator(); + const { configuratorProxy, cometProxyWithExtendedAssetList: cometProxy } = await makeConfigurator(); let setSupplyKinkCalldata = ethers.utils.defaultAbiCoder.encode( ['address', 'uint64'], @@ -468,7 +468,7 @@ describe('MarketUpdateProposer', function() { marketUpdateProposalGuardianSigner, } = await makeMarketAdmin(); - const { configuratorProxy, cometProxy, users: [alice] } = await makeConfigurator(); + const { configuratorProxy, cometProxyWithExtendedAssetList: cometProxy, users: [alice] } = await makeConfigurator(); expect(await marketUpdateProposerContract.marketAdmin()).to.be.equal( marketUpdateMultiSig.address @@ -546,7 +546,7 @@ describe('MarketUpdateProposer', function() { const { configuratorProxy, configurator, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, users: [bob], } = await makeConfigurator( { governor: governorTimelockSigner, marketAdminPermissionCheckerContract: marketAdminPermissionCheckerContract } @@ -623,7 +623,7 @@ describe('MarketUpdateProposer', function() { marketUpdateProposalGuardianSigner, } = await makeMarketAdmin(); - const { configuratorProxy, cometProxy, users: [bob] } = await makeConfigurator(); + const { configuratorProxy, cometProxyWithExtendedAssetList: cometProxy, users: [bob] } = await makeConfigurator(); expect(await marketUpdateProposerContract.marketAdmin()).to.be.equal( marketUpdateMultiSig.address diff --git a/test/marketupdates/market-update-timelock-test.ts b/test/marketupdates/market-update-timelock-test.ts index 31a96a49f..b677ab20b 100644 --- a/test/marketupdates/market-update-timelock-test.ts +++ b/test/marketupdates/market-update-timelock-test.ts @@ -46,7 +46,7 @@ describe('MarketUpdateTimelock', function() { const { configuratorProxy, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, users: [bob], } = await makeConfigurator(); @@ -123,7 +123,7 @@ describe('MarketUpdateTimelock', function() { const { configuratorProxy, configurator, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, users: [bob], } = await makeConfigurator(); @@ -255,7 +255,7 @@ describe('MarketUpdateTimelock', function() { const { configuratorProxy, configurator, - cometProxy, + cometProxyWithExtendedAssetList: cometProxy, users: [bob], } = await makeConfigurator(); diff --git a/test/pause-guardian-test.ts b/test/pause-guardian-test.ts index 6119b7349..fb0cf41cc 100644 --- a/test/pause-guardian-test.ts +++ b/test/pause-guardian-test.ts @@ -2,7 +2,7 @@ import { Comet, expect, event, makeProtocol, wait } from './helpers'; describe('Pause Guardian', function () { it('Should pause supply', async function () { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList: comet } = await makeProtocol(); await assertNoActionsArePaused(comet); const txn = await wait(comet.pause(true, false, false, false, false)); @@ -24,7 +24,7 @@ describe('Pause Guardian', function () { }); it('Should pause transfer', async function () { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList: comet } = await makeProtocol(); await assertNoActionsArePaused(comet); const txn = await wait(comet.pause(false, true, false, false, false)); @@ -46,7 +46,7 @@ describe('Pause Guardian', function () { }); it('Should pause withdraw', async function () { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList: comet } = await makeProtocol(); await assertNoActionsArePaused(comet); const txn = await wait(comet.pause(false, false, true, false, false)); @@ -68,7 +68,7 @@ describe('Pause Guardian', function () { }); it('Should pause absorb', async function () { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList: comet } = await makeProtocol(); await assertNoActionsArePaused(comet); const txn = await wait(comet.pause(false, false, false, true, false)); @@ -90,7 +90,7 @@ describe('Pause Guardian', function () { }); it('Should pause buy', async function () { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList: comet } = await makeProtocol(); await assertNoActionsArePaused(comet); const txn = await wait(comet.pause(false, false, false, false, true)); @@ -112,7 +112,7 @@ describe('Pause Guardian', function () { }); it('Should unpause', async function () { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList: comet } = await makeProtocol(); await assertNoActionsArePaused(comet); const txn1 = await wait(comet.pause(true, true, true, true, true)); @@ -143,7 +143,7 @@ describe('Pause Guardian', function () { }); it('Should pause when called by governor', async function () { - const { comet, governor } = await makeProtocol(); + const { cometWithExtendedAssetList: comet, governor } = await makeProtocol(); await assertNoActionsArePaused(comet); await comet.connect(governor).pause(true, true, true, true, true); @@ -152,7 +152,7 @@ describe('Pause Guardian', function () { }); it('Should pause when called by pause guardian', async function () { - const { comet, pauseGuardian } = await makeProtocol(); + const { cometWithExtendedAssetList: comet, pauseGuardian } = await makeProtocol(); await assertNoActionsArePaused(comet); await comet.connect(pauseGuardian).pause(true, true, true, true, true); @@ -161,7 +161,7 @@ describe('Pause Guardian', function () { }); it('Should revert if not called by governor or pause guardian', async function () { - const { comet, users } = await makeProtocol(); + const { cometWithExtendedAssetList: comet, users } = await makeProtocol(); await expect( comet.connect(users[0]).pause(true, true, true, true, true) ).to.be.revertedWith("custom error 'Unauthorized()'"); diff --git a/test/price-feed-test.ts b/test/price-feed-test.ts index 7fd263024..68678bbcb 100644 --- a/test/price-feed-test.ts +++ b/test/price-feed-test.ts @@ -2,7 +2,7 @@ import { expect, makeProtocol } from './helpers'; describe('getPrice', function () { it('returns price data for assets, with 8 decimals', async () => { - const { comet, priceFeeds } = await makeProtocol({ + const { cometWithExtendedAssetList: comet, priceFeeds } = await makeProtocol({ assets: { USDC: {}, COMP: { @@ -19,7 +19,7 @@ describe('getPrice', function () { }); it('reverts if given a bad priceFeed address', async () => { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList: comet } = await makeProtocol(); // COMP on mainnet (not a legit price feed address) const invalidPriceFeedAddress = '0xc00e94cb662c3520282e6f5717214004a7f26888'; @@ -28,7 +28,7 @@ describe('getPrice', function () { }); it('reverts if price feed returns negative value', async () => { - const { comet, priceFeeds } = await makeProtocol({ + const { cometWithExtendedAssetList: comet, priceFeeds } = await makeProtocol({ assets: { USDC: {}, COMP: { diff --git a/test/quote-collateral-test.ts b/test/quote-collateral-test.ts index ea0e367da..f6c73e0bb 100644 --- a/test/quote-collateral-test.ts +++ b/test/quote-collateral-test.ts @@ -20,7 +20,7 @@ describe('quoteCollateral', function () { }, } }); - const { comet, tokens } = protocol; + const { cometWithExtendedAssetList: comet, tokens } = protocol; const { COMP } = tokens; const baseAmount = exp(200, 6); @@ -55,7 +55,7 @@ describe('quoteCollateral', function () { }, } }); - const { comet, tokens } = protocol; + const { cometWithExtendedAssetList: comet, tokens } = protocol; const { COMP } = tokens; const baseAmount = 0n; @@ -83,7 +83,7 @@ describe('quoteCollateral', function () { }, } }); - const { comet, tokens } = protocol; + const { cometWithExtendedAssetList: comet, tokens } = protocol; const { COMP } = tokens; const baseAmount = exp(200, 6); @@ -121,7 +121,7 @@ describe('quoteCollateral', function () { }, } }); - const { comet, tokens } = protocol; + const { cometWithExtendedAssetList: comet, tokens } = protocol; const { COMP } = tokens; const baseAmount = exp(810, 6); @@ -152,7 +152,7 @@ describe('quoteCollateral', function () { }, } }); - const { comet, tokens } = protocol; + const { cometWithExtendedAssetList: comet, tokens } = protocol; const { COMP } = tokens; const baseAmount = exp(1e15, 6); // 1 quadrillion USDC diff --git a/test/reserves-test.ts b/test/reserves-test.ts index eeac0311d..e92f322f5 100644 --- a/test/reserves-test.ts +++ b/test/reserves-test.ts @@ -3,7 +3,7 @@ import { expect, makeProtocol, setTotalsBasic } from './helpers'; describe('getReserves', function () { it('calculates 0 reserves', async () => { const protocol = await makeProtocol({base: 'USDC'}); - const { comet, tokens } = protocol; + const { cometWithExtendedAssetList: comet, tokens } = protocol; const { USDC } = tokens; await USDC.allocateTo(comet.address, 100); @@ -21,7 +21,7 @@ describe('getReserves', function () { it('calculates positive reserves', async () => { const protocol = await makeProtocol({base: 'USDC'}); - const { comet, tokens } = protocol; + const { cometWithExtendedAssetList: comet, tokens } = protocol; const { USDC } = tokens; await USDC.allocateTo(comet.address, 100); @@ -39,7 +39,7 @@ describe('getReserves', function () { it('calculates negative reserves', async () => { const protocol = await makeProtocol({base: 'USDC'}); - const { comet } = protocol; + const { cometWithExtendedAssetList: comet } = protocol; // Protocol holds no USDC diff --git a/test/rewards-test.ts b/test/rewards-test.ts index ec8b7b483..f6f259268 100644 --- a/test/rewards-test.ts +++ b/test/rewards-test.ts @@ -5,7 +5,7 @@ describe('CometRewards', () => { describe('claim + supply', () => { it('can construct and claim rewards for owner with upscale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice], @@ -41,7 +41,7 @@ describe('CometRewards', () => { it('can construct and claim rewards for owner with downscale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice], @@ -79,7 +79,7 @@ describe('CometRewards', () => { it('can construct and claim rewards for owner with same scale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice], @@ -117,7 +117,7 @@ describe('CometRewards', () => { it('does not overpay when claiming more than once', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice], @@ -144,7 +144,7 @@ describe('CometRewards', () => { it('fails if comet instance is already configured', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP }, } = await makeProtocol({ @@ -159,7 +159,7 @@ describe('CometRewards', () => { it('fails if comet instance is not configured', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, users: [alice], } = await makeProtocol(); @@ -174,7 +174,7 @@ describe('CometRewards', () => { it('fails if not enough rewards in the pool to transfer', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice], @@ -200,7 +200,7 @@ describe('CometRewards', () => { describe('claimTo + borrow', () => { it('can construct and claim rewards to target with upscale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP, WBTC }, users: [alice, bob], @@ -242,7 +242,7 @@ describe('CometRewards', () => { it('can construct and claim rewards to target with downscale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP, WBTC }, users: [alice, bob], @@ -277,7 +277,7 @@ describe('CometRewards', () => { it('can construct and claim rewards to target with same scale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP, WBTC }, users: [alice, bob], @@ -312,7 +312,7 @@ describe('CometRewards', () => { it('does not allow claiming more than once', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP, WBTC }, users: [alice, bob], @@ -345,7 +345,7 @@ describe('CometRewards', () => { it('fails if comet instance is not configured', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, users: [alice, bob], } = await makeProtocol(); @@ -362,7 +362,7 @@ describe('CometRewards', () => { it('fails if not enough rewards in the pool to transfer', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP, WBTC }, users: [alice, bob], @@ -390,7 +390,7 @@ describe('CometRewards', () => { it('fails if caller is not permitted to claim rewards for owner', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP }, users: [alice], @@ -410,7 +410,7 @@ describe('CometRewards', () => { describe('getRewardOwed', () => { it('can construct and calculate rewards for owner with upscale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice], @@ -441,7 +441,7 @@ describe('CometRewards', () => { it('can construct and calculate rewards for owner with downscale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice], @@ -474,7 +474,7 @@ describe('CometRewards', () => { it('can construct and calculate rewards for owner with same scale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice], @@ -507,7 +507,7 @@ describe('CometRewards', () => { it('returns 0 owed if user already claimed', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice], @@ -538,7 +538,7 @@ describe('CometRewards', () => { it('fails if comet instance is not configured', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, users: [alice], } = await makeProtocol(); @@ -555,7 +555,7 @@ describe('CometRewards', () => { describe('setRewardConfig', () => { it('allows governor to set rewards token with upscale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP }, } = await makeProtocol(); @@ -571,7 +571,7 @@ describe('CometRewards', () => { it('allows governor to set rewards token with downscale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP }, } = await makeProtocol({ @@ -591,7 +591,7 @@ describe('CometRewards', () => { it('allows governor to set rewards token with same scale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP }, } = await makeProtocol({ @@ -611,7 +611,7 @@ describe('CometRewards', () => { it('does not allow anyone but governor to set config', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP }, users: [alice], @@ -631,7 +631,7 @@ describe('CometRewards', () => { describe('withdrawToken', () => { it('allows governor to withdraw funds added', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP }, users: [alice], @@ -647,7 +647,7 @@ describe('CometRewards', () => { it('does not allow anyone but governor to withdraw', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP }, users: [alice], @@ -669,7 +669,7 @@ describe('CometRewards', () => { describe('setRewardsClaimed', () => { it('allows governor to set rewards claimed', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP }, users: [alice, bob], @@ -704,7 +704,7 @@ describe('CometRewards', () => { it('can be used to zero out retroactive rewards for users', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP, USDC }, users: [alice], @@ -745,7 +745,7 @@ describe('CometRewards', () => { it('reverts if addresses and claimedAmounts have different lengths', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP }, users: [alice], @@ -760,7 +760,7 @@ describe('CometRewards', () => { it('does not allow anyone but governor to set rewards claimed', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP }, users: [alice], @@ -779,7 +779,7 @@ describe('CometRewards', () => { describe('transferGovernor', () => { it('allows governor to transfer governor', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP }, users: [alice], @@ -799,7 +799,7 @@ describe('CometRewards', () => { it('does not allow anyone but governor to transfer governor', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP }, users: [alice], @@ -840,7 +840,7 @@ for (const { multiplier } of TEST_CASES) { describe('claim + supply', () => { it('can construct and claim rewards for owner with upscale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice] @@ -887,7 +887,7 @@ for (const { multiplier } of TEST_CASES) { it('can construct and claim rewards for owner with downscale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice] @@ -933,7 +933,7 @@ for (const { multiplier } of TEST_CASES) { it('can construct and claim rewards for owner with upscale with small rescale factor', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice] @@ -979,7 +979,7 @@ for (const { multiplier } of TEST_CASES) { it('can construct and claim rewards for owner with downscale with small rescale factor', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice] @@ -1025,7 +1025,7 @@ for (const { multiplier } of TEST_CASES) { it('can construct and claim rewards for owner with same scale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice] @@ -1071,7 +1071,7 @@ for (const { multiplier } of TEST_CASES) { it('does not overpay when claiming more than once', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice] @@ -1103,7 +1103,7 @@ for (const { multiplier } of TEST_CASES) { it('fails if comet instance is already configured', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP } } = await makeProtocol({ @@ -1121,7 +1121,7 @@ for (const { multiplier } of TEST_CASES) { it('fails if comet instance is not configured', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, users: [alice] } = await makeProtocol(); @@ -1135,7 +1135,7 @@ for (const { multiplier } of TEST_CASES) { it('fails if not enough rewards in the pool to transfer', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice] @@ -1163,7 +1163,7 @@ for (const { multiplier } of TEST_CASES) { describe('claimTo + borrow', () => { it('can construct and claim rewards to target with upscale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP, WBTC }, users: [alice, bob] @@ -1212,7 +1212,7 @@ for (const { multiplier } of TEST_CASES) { it('can construct and claim rewards to target with downscale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP, WBTC }, users: [alice, bob] @@ -1257,7 +1257,7 @@ for (const { multiplier } of TEST_CASES) { it('can construct and claim rewards to target with same scale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP, WBTC }, users: [alice, bob] @@ -1302,7 +1302,7 @@ for (const { multiplier } of TEST_CASES) { it('does not allow claiming more than once', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP, WBTC }, users: [alice, bob] @@ -1344,7 +1344,7 @@ for (const { multiplier } of TEST_CASES) { it('fails if comet instance is not configured', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, users: [alice, bob] } = await makeProtocol(); @@ -1359,7 +1359,7 @@ for (const { multiplier } of TEST_CASES) { it('fails if not enough rewards in the pool to transfer', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP, WBTC }, users: [alice, bob] @@ -1388,7 +1388,7 @@ for (const { multiplier } of TEST_CASES) { it('fails if caller is not permitted to claim rewards for owner', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP }, users: [alice] @@ -1410,7 +1410,7 @@ for (const { multiplier } of TEST_CASES) { describe('getRewardOwed', () => { it('can construct and calculate rewards for owner with upscale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice] @@ -1453,7 +1453,7 @@ for (const { multiplier } of TEST_CASES) { it('can construct and calculate rewards for owner with downscale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice] @@ -1495,7 +1495,7 @@ for (const { multiplier } of TEST_CASES) { it('can construct and calculate rewards for owner with upscale with small rescale factor', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice] @@ -1537,7 +1537,7 @@ for (const { multiplier } of TEST_CASES) { it('can construct and calculate rewards for owner with downscale with small rescale factor', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice] @@ -1579,7 +1579,7 @@ for (const { multiplier } of TEST_CASES) { it('can construct and calculate rewards for owner with same scale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice] @@ -1621,7 +1621,7 @@ for (const { multiplier } of TEST_CASES) { it('returns 0 owed if user already claimed', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { USDC, COMP }, users: [alice] @@ -1660,7 +1660,7 @@ for (const { multiplier } of TEST_CASES) { it('fails if comet instance is not configured', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, users: [alice] } = await makeProtocol(); @@ -1676,7 +1676,7 @@ for (const { multiplier } of TEST_CASES) { describe('setRewardConfig', () => { it('allows governor to set rewards token with upscale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP } } = await makeProtocol({ @@ -1702,7 +1702,7 @@ for (const { multiplier } of TEST_CASES) { it('allows governor to set rewards token with downscale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP } } = await makeProtocol({ @@ -1728,7 +1728,7 @@ for (const { multiplier } of TEST_CASES) { it('allows governor to set rewards token with upscale with small rescale factor', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP } } = await makeProtocol({ @@ -1754,7 +1754,7 @@ for (const { multiplier } of TEST_CASES) { it('allows governor to set rewards token with downscale with small rescale factor', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP } } = await makeProtocol({ @@ -1780,7 +1780,7 @@ for (const { multiplier } of TEST_CASES) { it('allows governor to set rewards token with same scale', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP } } = await makeProtocol({ @@ -1806,7 +1806,7 @@ for (const { multiplier } of TEST_CASES) { it('does not allow anyone but governor to set config', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, tokens: { COMP }, users: [alice] diff --git a/test/sanity-test.ts b/test/sanity-test.ts index 48973f1e3..5edc4db16 100644 --- a/test/sanity-test.ts +++ b/test/sanity-test.ts @@ -2,7 +2,7 @@ import { ethers, expect, makeProtocol } from './helpers'; describe('getNow', function () { it('reverts if timestamp overflows', async () => { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList: comet } = await makeProtocol(); await ethers.provider.send('evm_mine', [2**40]); await expect(comet.getNow()).to.be.revertedWith("custom error 'TimestampTooLarge()'"); await ethers.provider.send('hardhat_reset', []); // dont break downstream tests... diff --git a/test/supply-test.ts b/test/supply-test.ts index c883fdb8f..2567c7778 100644 --- a/test/supply-test.ts +++ b/test/supply-test.ts @@ -4,7 +4,7 @@ import { EvilToken, EvilToken__factory, NonStandardFaucetFeeToken__factory, NonS describe('supplyTo', function () { it('supplies base from sender if the asset is base', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { USDC } = tokens; const _i0 = await USDC.allocateTo(bob.address, 100e6); @@ -57,7 +57,7 @@ describe('supplyTo', function () { it('supplies max base borrow balance (including accrued) from sender if the asset is base', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { USDC } = tokens; await USDC.allocateTo(bob.address, 100e6); @@ -115,7 +115,7 @@ describe('supplyTo', function () { it('supply max base should supply 0 if user has no borrow position', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { USDC } = tokens; await USDC.allocateTo(bob.address, 100e6); @@ -162,7 +162,7 @@ describe('supplyTo', function () { it('does not emit Transfer for 0 mint', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { USDC } = tokens; await USDC.allocateTo(bob.address, 100e6); @@ -204,7 +204,7 @@ describe('supplyTo', function () { // violated. it('supplies 0 and does not revert when dstPrincipalNew < dstPrincipal', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [alice] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice] } = protocol; const { USDC } = tokens; await comet.setBasePrincipal(alice.address, 99999992291226); @@ -234,7 +234,7 @@ describe('supplyTo', function () { it('user supply is same as total supply', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [bob] } = protocol; const { USDC } = tokens; await setTotalsBasic(comet, { @@ -264,7 +264,7 @@ describe('supplyTo', function () { it('supplies collateral from sender if the asset is collateral', async () => { const protocol = await makeProtocol(); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { COMP } = tokens; const _i0 = await COMP.allocateTo(bob.address, 8e8); @@ -310,7 +310,7 @@ describe('supplyTo', function () { it('calculates base principal correctly', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { USDC } = tokens; await USDC.allocateTo(bob.address, 100e6); @@ -352,7 +352,7 @@ describe('supplyTo', function () { USDC: { initial: 1e6, decimals: 6 }, } }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { COMP } = tokens; const _i0 = await COMP.allocateTo(bob.address, 8e8); @@ -365,7 +365,7 @@ describe('supplyTo', function () { it('reverts if the asset is neither collateral nor base', async () => { const protocol = await makeProtocol(); - const { comet, users: [alice, bob], unsupportedToken: USUP } = protocol; + const { cometWithExtendedAssetList: comet, users: [alice, bob], unsupportedToken: USUP } = protocol; const _i0 = await USUP.allocateTo(bob.address, 1); const baseAsB = USUP.connect(bob); @@ -377,7 +377,7 @@ describe('supplyTo', function () { it('reverts if supply is paused', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, pauseGuardian, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, pauseGuardian, users: [alice, bob] } = protocol; const { USDC } = tokens; await USDC.allocateTo(bob.address, 1); @@ -394,7 +394,7 @@ describe('supplyTo', function () { it('reverts if supply max for a collateral asset', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { COMP } = tokens; await COMP.allocateTo(bob.address, 100e6); @@ -414,7 +414,7 @@ describe('supplyTo', function () { factory: (await ethers.getContractFactory('NonStandardFaucetFeeToken')) as NonStandardFaucetFeeToken__factory, }; const protocol = await makeProtocol({ base: 'USDT', assets: assets }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { USDT } = tokens; // Set fee to 0.1% @@ -479,7 +479,7 @@ describe('supplyTo', function () { }; const protocol = await makeProtocol({ base: 'USDC', assets: assets }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { FeeToken } = tokens; // Set fee to 0.1% @@ -528,7 +528,7 @@ describe('supplyTo', function () { }); it('blocks reentrancy from exceeding the supply cap', async () => { - const { comet, tokens, users: [alice, bob] } = await makeProtocol({ + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = await makeProtocol({ assets: { USDC: { decimals: 6 @@ -565,7 +565,7 @@ describe('supplyTo', function () { describe('supply', function () { it('supplies to sender by default', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [bob] } = protocol; const { USDC } = tokens; const _i0 = await USDC.allocateTo(bob.address, 100e6); @@ -587,7 +587,7 @@ describe('supply', function () { it('reverts if supply is paused', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, pauseGuardian, users: [bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, pauseGuardian, users: [bob] } = protocol; const { USDC } = tokens; await USDC.allocateTo(bob.address, 100e6); @@ -606,7 +606,7 @@ describe('supply', function () { describe('supplyFrom', function () { it('supplies from `from` if specified and sender has permission', async () => { const protocol = await makeProtocol(); - const { comet, tokens, users: [alice, bob, charlie] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob, charlie] } = protocol; const { COMP } = tokens; const _i0 = await COMP.allocateTo(bob.address, 7); @@ -634,7 +634,7 @@ describe('supplyFrom', function () { it('reverts if `from` is specified and sender does not have permission', async () => { const protocol = await makeProtocol(); - const { comet, tokens, users: [alice, bob, charlie] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob, charlie] } = protocol; const { COMP } = tokens; const _i0 = await COMP.allocateTo(bob.address, 7); @@ -646,7 +646,7 @@ describe('supplyFrom', function () { it('reverts if supply is paused', async () => { const protocol = await makeProtocol(); - const { comet, tokens, pauseGuardian, users: [alice, bob, charlie] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, pauseGuardian, users: [alice, bob, charlie] } = protocol; const { COMP } = tokens; await COMP.allocateTo(bob.address, 7); diff --git a/test/tracking-index-bounds-test.ts b/test/tracking-index-bounds-test.ts index c4055b105..5e28fa4dd 100644 --- a/test/tracking-index-bounds-test.ts +++ b/test/tracking-index-bounds-test.ts @@ -12,7 +12,7 @@ describe('total tracking index bounds', function () { baseMinForRewards }; const protocol = await makeProtocol(params); - const { comet } = protocol; + const { cometWithExtendedAssetList: comet } = protocol; const baseScale = (await comet.baseScale()).toBigInt(); // Formula: MAX_UINT64 / (baseTrackingSupplySpeed * baseScale / baseMinForRewards) @@ -26,7 +26,7 @@ describe('total tracking index bounds', function () { totalSupplyBase: BigNumber.from(baseMinForRewards), // 10k USDC base units }); - await fastForward(secondsUntilOverflow-2); + await fastForward(secondsUntilOverflow-1); // First accrue is successful without overflow await comet.accrue(); @@ -44,7 +44,7 @@ describe('total tracking index bounds', function () { baseMinForRewards }; const protocol = await makeProtocol(params); - const { comet } = protocol; + const { cometWithExtendedAssetList: comet } = protocol; const baseScale = (await comet.baseScale()).toBigInt(); // Formula: MAX_UINT64 / (baseTrackingBorrowSpeed * baseScale / baseMinForRewards) @@ -58,7 +58,7 @@ describe('total tracking index bounds', function () { totalBorrowBase: BigNumber.from(baseMinForRewards), // 10k USDC base units }); - await fastForward(secondsUntilOverflow-2); + await fastForward(secondsUntilOverflow-1); // First accrue is successful without overflow await comet.accrue(); @@ -74,7 +74,7 @@ describe('total tracking index bounds', function () { baseTrackingBorrowSpeed: exp(1, 15), }; const protocol = await makeProtocol(params); - const { comet } = protocol; + const { cometWithExtendedAssetList: comet } = protocol; const t0 = await setTotalsBasic(comet, { totalSupplyBase: BigNumber.from(exp(1, 15)).mul(await comet.baseScale()), // 1e15 base units @@ -104,7 +104,7 @@ describe('total tracking index bounds', function () { baseTrackingBorrowSpeed: exp(1, 15), }; const protocol = await makeProtocol(params); - const { comet } = protocol; + const { cometWithExtendedAssetList: comet } = protocol; const t0 = await setTotalsBasic(comet, { totalBorrowBase: BigNumber.from(exp(1, 15)).mul(await comet.baseScale()), // 1e15 base units @@ -139,7 +139,7 @@ describe('total tracking index bounds', function () { baseMinForRewards }; const protocol = await makeProtocol(params); - const { comet } = protocol; + const { cometWithExtendedAssetList: comet } = protocol; const baseScale = (await comet.baseScale()).toBigInt(); // Formula: MAX_UINT64 / (baseTrackingSupplySpeed * baseScale / baseMinForRewards) @@ -153,7 +153,7 @@ describe('total tracking index bounds', function () { totalSupplyBase: BigNumber.from(baseMinForRewards), // 100 WETH base units }); - await fastForward(secondsUntilOverflow-2); + await fastForward(secondsUntilOverflow-1); // First accrue is successful without overflow await comet.accrue(); @@ -172,7 +172,7 @@ describe('total tracking index bounds', function () { baseMinForRewards }; const protocol = await makeProtocol(params); - const { comet } = protocol; + const { cometWithExtendedAssetList: comet } = protocol; const baseScale = (await comet.baseScale()).toBigInt(); // Formula: MAX_UINT64 / (baseTrackingBorrowSpeed * baseScale / baseMinForRewards) @@ -186,7 +186,7 @@ describe('total tracking index bounds', function () { totalBorrowBase: BigNumber.from(baseMinForRewards), // 10k USDC base units }); - await fastForward(secondsUntilOverflow-2); + await fastForward(secondsUntilOverflow-1); // First accrue is successful without overflow await comet.accrue(); @@ -203,7 +203,7 @@ describe('total tracking index bounds', function () { baseTrackingBorrowSpeed: exp(0.001, 15), }; const protocol = await makeProtocol(params); - const { comet } = protocol; + const { cometWithExtendedAssetList: comet } = protocol; const t0 = await setTotalsBasic(comet, { totalSupplyBase: BigNumber.from(exp(1, 12)).mul(await comet.baseScale()), // 1e12 base units @@ -234,7 +234,7 @@ describe('total tracking index bounds', function () { baseTrackingBorrowSpeed: exp(0.001, 15), }; const protocol = await makeProtocol(params); - const { comet } = protocol; + const { cometWithExtendedAssetList: comet } = protocol; const t0 = await setTotalsBasic(comet, { totalBorrowBase: BigNumber.from(exp(1, 12)).mul(await comet.baseScale()), // 1e12 base units diff --git a/test/transfer-test.ts b/test/transfer-test.ts index 3d3f411c6..5b849b56f 100644 --- a/test/transfer-test.ts +++ b/test/transfer-test.ts @@ -4,7 +4,7 @@ describe('transfer', function () { it('transfers base from sender if the asset is base', async () => { const protocol = await makeProtocol({ base: 'USDC' }); const { - comet, + cometWithExtendedAssetList: comet, tokens, users: [alice, bob], } = protocol; @@ -48,7 +48,7 @@ describe('transfer', function () { it('does not emit Transfer if 0 mint/burn', async () => { const protocol = await makeProtocol({ base: 'USDC' }); const { - comet, + cometWithExtendedAssetList: comet, tokens, users: [alice, bob], } = protocol; @@ -70,7 +70,7 @@ describe('transfer', function () { it('transfers max base balance (including accrued) from sender if the asset is base', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { USDC } = tokens; await USDC.allocateTo(comet.address, 100e6); @@ -122,7 +122,7 @@ describe('transfer', function () { it('transfer max base should transfer 0 if user has a borrow position', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { USDC, WETH } = tokens; await comet.setBasePrincipal(bob.address, -100e6); @@ -150,7 +150,7 @@ describe('transfer', function () { it('transfers collateral from sender if the asset is collateral', async () => { const protocol = await makeProtocol(); const { - comet, + cometWithExtendedAssetList: comet, tokens, users: [alice, bob], } = protocol; @@ -186,7 +186,7 @@ describe('transfer', function () { it('calculates base principal correctly', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { USDC } = tokens; await comet.setBasePrincipal(bob.address, 50e6); // 100e6 in present value @@ -215,7 +215,7 @@ describe('transfer', function () { it('reverts if the asset is neither collateral nor base', async () => { const protocol = await makeProtocol(); const { - comet, + cometWithExtendedAssetList: comet, users: [alice, bob], unsupportedToken: USUP, } = protocol; @@ -227,7 +227,7 @@ describe('transfer', function () { it('reverts if transfer is paused', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, pauseGuardian, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, pauseGuardian, users: [alice, bob] } = protocol; const { USDC } = tokens; const cometAsB = comet.connect(bob); @@ -241,7 +241,7 @@ describe('transfer', function () { it('reverts if transfer max for a collateral asset', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { COMP } = tokens; await COMP.allocateTo(bob.address, 100e6); @@ -251,7 +251,7 @@ describe('transfer', function () { }); it('borrows base if collateralized', async () => { - const { comet, tokens, users: [alice, bob] } = await makeProtocol(); + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = await makeProtocol(); const { WETH, USDC } = tokens; await comet.setCollateralBalance(alice.address, WETH.address, exp(1, 18)); @@ -269,7 +269,7 @@ describe('transfer', function () { it('cant borrow less than the minimum', async () => { const protocol = await makeProtocol(); const { - comet, + cometWithExtendedAssetList: comet, tokens, users: [alice, bob], } = protocol; @@ -285,7 +285,7 @@ describe('transfer', function () { it('reverts on self-transfer of base token', async () => { const { - comet, + cometWithExtendedAssetList: comet, tokens, users: [alice], } = await makeProtocol({ base: 'USDC' }); @@ -298,7 +298,7 @@ describe('transfer', function () { it('reverts on self-transfer of collateral', async () => { const { - comet, + cometWithExtendedAssetList: comet, tokens, users: [alice], } = await makeProtocol(); @@ -310,7 +310,7 @@ describe('transfer', function () { }); it('reverts if transferring base results in an under collateralized borrow', async () => { - const { comet, tokens, users: [alice, bob] } = await makeProtocol(); + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = await makeProtocol(); const { USDC } = tokens; await expect( @@ -319,7 +319,7 @@ describe('transfer', function () { }); it('reverts if transferring collateral results in an under collateralized borrow', async () => { - const { comet, tokens, users: [alice, bob] } = await makeProtocol(); + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = await makeProtocol(); const { WETH } = tokens; // user has a borrow, but with collateral to cover @@ -337,7 +337,7 @@ describe('transferFrom', function () { it('transfers from src if specified and sender has permission', async () => { const protocol = await makeProtocol(); const { - comet, + cometWithExtendedAssetList: comet, tokens, users: [alice, bob, charlie], } = protocol; @@ -363,7 +363,7 @@ describe('transferFrom', function () { it('reverts if src is specified and sender does not have permission', async () => { const protocol = await makeProtocol(); const { - comet, + cometWithExtendedAssetList: comet, tokens, users: [alice, bob, charlie], } = protocol; @@ -379,7 +379,7 @@ describe('transferFrom', function () { it('reverts on transfer of base token from address to itself', async () => { const { - comet, + cometWithExtendedAssetList: comet, tokens, users: [alice, bob], } = await makeProtocol({ base: 'USDC' }); @@ -394,7 +394,7 @@ describe('transferFrom', function () { it('reverts on transfer of collateral from address to itself', async () => { const { - comet, + cometWithExtendedAssetList: comet, tokens, users: [alice, bob], } = await makeProtocol(); @@ -409,7 +409,7 @@ describe('transferFrom', function () { it('reverts if transfer is paused', async () => { const protocol = await makeProtocol(); - const { comet, tokens, pauseGuardian, users: [alice, bob, charlie] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, pauseGuardian, users: [alice, bob, charlie] } = protocol; const { COMP } = tokens; await comet.setCollateralBalance(bob.address, COMP.address, 7); diff --git a/test/update-assets-in-test.ts b/test/update-assets-in-test.ts index 7c105f3b9..3a6df1283 100644 --- a/test/update-assets-in-test.ts +++ b/test/update-assets-in-test.ts @@ -2,7 +2,7 @@ import { ethers, expect, makeProtocol } from './helpers'; describe('updateAssetsIn', function () { it("adds asset to user's asset list when initialUserBalance=0 and finalUserBalance>0", async () => { - const { comet, tokens } = await makeProtocol(); + const { cometWithExtendedAssetList: comet, tokens } = await makeProtocol(); const [_governor, _pauseGuardian, user] = await ethers.getSigners(); const compAddress = tokens['COMP'].address; const wethAddress = tokens['WETH'].address; @@ -25,7 +25,7 @@ describe('updateAssetsIn', function () { }); it('works for up to 12 assets', async () => { - const { comet, tokens, users } = await makeProtocol({ + const { cometWithExtendedAssetList: comet, tokens, users } = await makeProtocol({ assets: { USDC: {}, ASSET1: {}, @@ -50,7 +50,7 @@ describe('updateAssetsIn', function () { }); it('does not change state when both initialUserBalance and finalUserBalance are 0', async () => { - const { comet, tokens } = await makeProtocol(); + const { cometWithExtendedAssetList: comet, tokens } = await makeProtocol(); const [_governor, _pauseGuardian, user] = await ethers.getSigners(); const compAddress = tokens['COMP'].address; @@ -62,7 +62,7 @@ describe('updateAssetsIn', function () { }); it('does not change state when both initialUserBalance and finalUserBalance > 0', async () => { - const { comet, tokens } = await makeProtocol(); + const { cometWithExtendedAssetList: comet, tokens } = await makeProtocol(); const [_governor, _pauseGuardian, user] = await ethers.getSigners(); const wethAddress = tokens['WETH'].address; @@ -76,7 +76,7 @@ describe('updateAssetsIn', function () { }); it('removes asset from asset list when initialUserBalance > 0 and finalUserBalance=0', async () => { - const { comet, tokens } = await makeProtocol(); + const { cometWithExtendedAssetList: comet, tokens } = await makeProtocol(); const [_governor, _pauseGuardian, user] = await ethers.getSigners(); const compAddress = tokens['COMP'].address; @@ -93,7 +93,7 @@ describe('updateAssetsIn', function () { }); it('reverts for non-existent asset address', async () => { - const { comet } = await makeProtocol(); + const { cometWithExtendedAssetList: comet } = await makeProtocol(); const [_governor, pauseGuardian, user] = await ethers.getSigners(); const erroneousAssetAddress = pauseGuardian.address; diff --git a/test/withdraw-reserves-test.ts b/test/withdraw-reserves-test.ts index b911c7891..48059caaa 100644 --- a/test/withdraw-reserves-test.ts +++ b/test/withdraw-reserves-test.ts @@ -4,7 +4,7 @@ describe('withdrawReserves', function () { it('withdraws reserves from the protocol', async () => { const tokenBalance = 1000n; const { - comet, + cometWithExtendedAssetList: comet, tokens: { USDC }, users: [alice], governor, @@ -36,7 +36,7 @@ describe('withdrawReserves', function () { it('reverts if called not by governor', async () => { const { - comet, + cometWithExtendedAssetList: comet, users: [alice], } = await makeProtocol(); await expect(comet.connect(alice).withdrawReserves(alice.address, 10)).to.be.revertedWith( @@ -47,7 +47,7 @@ describe('withdrawReserves', function () { it('reverts if not enough reserves are owned by protocol', async () => { const tokenBalance = 1000; const { - comet, + cometWithExtendedAssetList: comet, governor, users: [alice], } = await makeProtocol({ @@ -60,7 +60,7 @@ describe('withdrawReserves', function () { it('accounts for total supply base when calculating reserves', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, users: [alice], } = await makeProtocol({ @@ -81,7 +81,7 @@ describe('withdrawReserves', function () { it('reverts if negative reserves', async () => { const { - comet, + cometWithExtendedAssetList: comet, governor, users: [alice], } = await makeProtocol({ diff --git a/test/withdraw-test.ts b/test/withdraw-test.ts index 7fe2c0f71..d91fd8643 100644 --- a/test/withdraw-test.ts +++ b/test/withdraw-test.ts @@ -4,7 +4,7 @@ import { baseBalanceOf, ethers, event, expect, exp, makeProtocol, portfolio, Ree describe('withdrawTo', function () { it('withdraws base from sender if the asset is base', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { USDC } = tokens; const _i0 = await USDC.allocateTo(comet.address, 100e6); @@ -59,7 +59,7 @@ describe('withdrawTo', function () { it('does not emit Transfer for 0 burn', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { USDC, WETH } = tokens; await USDC.allocateTo(comet.address, 110e6); @@ -89,7 +89,7 @@ describe('withdrawTo', function () { it('withdraws max base balance (including accrued) from sender if the asset is base', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { USDC } = tokens; await USDC.allocateTo(comet.address, 110e6); @@ -149,7 +149,7 @@ describe('withdrawTo', function () { it('withdraw max base should withdraw 0 if user has a borrow position', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { USDC, WETH } = tokens; await comet.setBasePrincipal(bob.address, -100e6); @@ -196,7 +196,7 @@ describe('withdrawTo', function () { // This demonstrates a weird quirk of the present value/principal value rounding down math. it('withdraws 0 but Comet Transfer event amount is 1', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [alice] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice] } = protocol; const { USDC } = tokens; await comet.setBasePrincipal(alice.address, 99999992291226); @@ -235,7 +235,7 @@ describe('withdrawTo', function () { it('withdraws collateral from sender if the asset is collateral', async () => { const protocol = await makeProtocol(); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { COMP } = tokens; const _i0 = await COMP.allocateTo(comet.address, 8e8); @@ -279,12 +279,12 @@ describe('withdrawTo', function () { expect(q1.internal).to.be.deep.equal({ USDC: 0n, COMP: 0n, WETH: 0n, WBTC: 0n }); expect(q1.external).to.be.deep.equal({ USDC: 0n, COMP: 0n, WETH: 0n, WBTC: 0n }); expect(t1.totalSupplyAsset).to.be.equal(0n); - expect(Number(s0.receipt.gasUsed)).to.be.lessThan(85000); + expect(Number(s0.receipt.gasUsed)).to.be.lessThan(87000); }); it('calculates base principal correctly', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { USDC } = tokens; await USDC.allocateTo(comet.address, 100e6); @@ -318,7 +318,7 @@ describe('withdrawTo', function () { it('reverts if withdrawing base exceeds the total supply', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { USDC } = tokens; const _i0 = await USDC.allocateTo(comet.address, 100e6); @@ -330,7 +330,7 @@ describe('withdrawTo', function () { it('reverts if withdrawing collateral exceeds the total supply', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { COMP } = tokens; const _i0 = await COMP.allocateTo(comet.address, 8e8); @@ -342,7 +342,7 @@ describe('withdrawTo', function () { it('reverts if the asset is neither collateral nor base', async () => { const protocol = await makeProtocol(); - const { comet, users: [alice, bob], unsupportedToken: USUP } = protocol; + const { cometWithExtendedAssetList: comet, users: [alice, bob], unsupportedToken: USUP } = protocol; const _i0 = await USUP.allocateTo(comet.address, 1); const cometAsB = comet.connect(bob); @@ -352,7 +352,7 @@ describe('withdrawTo', function () { it('reverts if withdraw is paused', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, pauseGuardian, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, pauseGuardian, users: [alice, bob] } = protocol; const { USDC } = tokens; await USDC.allocateTo(comet.address, 1); @@ -367,7 +367,7 @@ describe('withdrawTo', function () { it('reverts if withdraw max for a collateral asset', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [alice, bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = protocol; const { COMP } = tokens; await COMP.allocateTo(bob.address, 100e6); @@ -377,7 +377,7 @@ describe('withdrawTo', function () { }); it('borrows to withdraw if necessary/possible', async () => { - const { comet, tokens, users: [alice, bob] } = await makeProtocol(); + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = await makeProtocol(); const { WETH, USDC } = tokens; await USDC.allocateTo(comet.address, 1e6); @@ -398,7 +398,7 @@ describe('withdrawTo', function () { describe('withdraw', function () { it('withdraws to sender by default', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, users: [bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [bob] } = protocol; const { USDC } = tokens; const _i0 = await USDC.allocateTo(comet.address, 100e6); @@ -422,7 +422,7 @@ describe('withdraw', function () { it('reverts if withdraw is paused', async () => { const protocol = await makeProtocol({ base: 'USDC' }); - const { comet, tokens, pauseGuardian, users: [bob] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, pauseGuardian, users: [bob] } = protocol; const { USDC } = tokens; await USDC.allocateTo(comet.address, 100e6); @@ -436,7 +436,7 @@ describe('withdraw', function () { }); it('reverts if withdraw amount is less than baseBorrowMin', async () => { - const { comet, tokens, users: [alice] } = await makeProtocol({ + const { cometWithExtendedAssetList: comet, tokens, users: [alice] } = await makeProtocol({ baseBorrowMin: exp(1, 6) }); const { USDC } = tokens; @@ -447,7 +447,7 @@ describe('withdraw', function () { }); it('reverts if base withdraw amount is not collateralzed', async () => { - const { comet, tokens, users: [alice] } = await makeProtocol(); + const { cometWithExtendedAssetList: comet, tokens, users: [alice] } = await makeProtocol(); const { USDC } = tokens; await expect( @@ -456,7 +456,7 @@ describe('withdraw', function () { }); it('reverts if collateral withdraw amount is not collateralized', async () => { - const { comet, tokens, users: [alice] } = await makeProtocol(); + const { cometWithExtendedAssetList: comet, tokens, users: [alice] } = await makeProtocol(); const { WETH } = tokens; const totalsCollateral = Object.assign({}, await comet.totalsCollateral(WETH.address), { @@ -476,7 +476,7 @@ describe('withdraw', function () { describe('reentrancy', function () { it('blocks malicious reentrant transferFrom', async () => { - const { comet, tokens, users: [alice, bob] } = await makeProtocol({ + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = await makeProtocol({ assets: { USDC: { decimals: 6 @@ -522,7 +522,7 @@ describe('withdraw', function () { }); it('blocks malicious reentrant withdrawFrom', async () => { - const { comet, tokens, users: [alice, bob] } = await makeProtocol({ + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob] } = await makeProtocol({ assets: { USDC: { decimals: 6 @@ -574,7 +574,7 @@ describe('withdraw', function () { describe('withdrawFrom', function () { it('withdraws from src if specified and sender has permission', async () => { const protocol = await makeProtocol(); - const { comet, tokens, users: [alice, bob, charlie] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob, charlie] } = protocol; const { COMP } = tokens; const _i0 = await COMP.allocateTo(comet.address, 7); @@ -607,7 +607,7 @@ describe('withdrawFrom', function () { it('reverts if src is specified and sender does not have permission', async () => { const protocol = await makeProtocol(); - const { comet, tokens, users: [alice, bob, charlie] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, users: [alice, bob, charlie] } = protocol; const { COMP } = tokens; const cometAsC = comet.connect(charlie); @@ -618,7 +618,7 @@ describe('withdrawFrom', function () { it('reverts if withdraw is paused', async () => { const protocol = await makeProtocol(); - const { comet, tokens, pauseGuardian, users: [alice, bob, charlie] } = protocol; + const { cometWithExtendedAssetList: comet, tokens, pauseGuardian, users: [alice, bob, charlie] } = protocol; const { COMP } = tokens; await COMP.allocateTo(comet.address, 7); From 877935bb6d03de74b7939be0dbdc370e98181420 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Mon, 1 Jun 2026 16:23:16 +0300 Subject: [PATCH 55/65] fix: remove deleted param from deploy scripts --- deployments/arbitrum/usdt/deploy.ts | 2 +- deployments/base/usds/deploy.ts | 2 +- deployments/linea/usdc/deploy.ts | 2 +- deployments/linea/weth/deploy.ts | 2 +- deployments/mainnet/wbtc/deploy.ts | 2 +- deployments/ronin/weth/deploy.ts | 2 +- deployments/ronin/wron/deploy.ts | 2 +- deployments/unichain/usdc/deploy.ts | 2 +- deployments/unichain/weth/deploy.ts | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/deployments/arbitrum/usdt/deploy.ts b/deployments/arbitrum/usdt/deploy.ts index f88d6d74a..0ebe246de 100644 --- a/deployments/arbitrum/usdt/deploy.ts +++ b/deployments/arbitrum/usdt/deploy.ts @@ -39,7 +39,7 @@ export default async function deploy(deploymentManager: DeploymentManager, deplo const bridgeReceiver = await deploymentManager.fromDep('bridgeReceiver', 'arbitrum', 'usdc.e'); // Deploy Comet - const deployed = await deployComet(deploymentManager, deploySpec, {}, true); + const deployed = await deployComet(deploymentManager, deploySpec); return { ...deployed, diff --git a/deployments/base/usds/deploy.ts b/deployments/base/usds/deploy.ts index f43db73ac..3b49b770c 100644 --- a/deployments/base/usds/deploy.ts +++ b/deployments/base/usds/deploy.ts @@ -64,7 +64,7 @@ async function deployContracts( const bridgeReceiver = await deploymentManager.fromDep('bridgeReceiver', 'base', 'usdbc'); // Deploy Comet - const deployed = await deployComet(deploymentManager, deploySpec, {}, true); + const deployed = await deployComet(deploymentManager, deploySpec); // XXX We will need to deploy a new bulker only if need to support wstETH diff --git a/deployments/linea/usdc/deploy.ts b/deployments/linea/usdc/deploy.ts index 264ff3566..b2e5f4593 100644 --- a/deployments/linea/usdc/deploy.ts +++ b/deployments/linea/usdc/deploy.ts @@ -117,7 +117,7 @@ async function deployContracts( ); // Deploy Comet - const deployed = await deployComet(deploymentManager, deploySpec, {}, true); + const deployed = await deployComet(deploymentManager, deploySpec); const { comet } = deployed; // Deploy Bulker diff --git a/deployments/linea/weth/deploy.ts b/deployments/linea/weth/deploy.ts index 78ae844f3..f3ecbb89a 100644 --- a/deployments/linea/weth/deploy.ts +++ b/deployments/linea/weth/deploy.ts @@ -145,7 +145,7 @@ async function deployContracts( const bridgeReceiver = await deploymentManager.fromDep('bridgeReceiver', 'linea', 'usdc'); // Deploy Comet - const deployed = await deployComet(deploymentManager, deploySpec, {}, true); + const deployed = await deployComet(deploymentManager, deploySpec); return { ...deployed, diff --git a/deployments/mainnet/wbtc/deploy.ts b/deployments/mainnet/wbtc/deploy.ts index f349268b6..8eb21324b 100644 --- a/deployments/mainnet/wbtc/deploy.ts +++ b/deployments/mainnet/wbtc/deploy.ts @@ -28,7 +28,7 @@ export default async function deploy(deploymentManager: DeploymentManager, deplo const bulker = await deploymentManager.fromDep('bulker', 'mainnet', 'weth'); // Deploy Comet - const deployed = await deployComet(deploymentManager, deploySpec, {}, true); + const deployed = await deployComet(deploymentManager, deploySpec); return { ...deployed, diff --git a/deployments/ronin/weth/deploy.ts b/deployments/ronin/weth/deploy.ts index 383b9b10a..16836ff2b 100644 --- a/deployments/ronin/weth/deploy.ts +++ b/deployments/ronin/weth/deploy.ts @@ -180,7 +180,7 @@ async function deployContracts( // Deploy all Comet-related contracts - const deployed = await deployComet(deploymentManager, deploySpec, {}, true); + const deployed = await deployComet(deploymentManager, deploySpec); // Deploy Comet const { comet } = deployed; diff --git a/deployments/ronin/wron/deploy.ts b/deployments/ronin/wron/deploy.ts index 1aae0a786..62f52dfc1 100644 --- a/deployments/ronin/wron/deploy.ts +++ b/deployments/ronin/wron/deploy.ts @@ -86,7 +86,7 @@ async function deployContracts( ); // Deploy all Comet-related contracts - const deployed = await deployComet(deploymentManager, deploySpec, {}, true); + const deployed = await deployComet(deploymentManager, deploySpec); return { ...deployed, diff --git a/deployments/unichain/usdc/deploy.ts b/deployments/unichain/usdc/deploy.ts index cae88536e..a0fd530af 100644 --- a/deployments/unichain/usdc/deploy.ts +++ b/deployments/unichain/usdc/deploy.ts @@ -131,7 +131,7 @@ async function deployContracts( ); // Deploy Comet - const deployed = await deployComet(deploymentManager, deploySpec, {}, true); + const deployed = await deployComet(deploymentManager, deploySpec); const { comet } = deployed; // const signer = await deploymentManager.getSigner(); diff --git a/deployments/unichain/weth/deploy.ts b/deployments/unichain/weth/deploy.ts index a40681b42..5aa0614fe 100644 --- a/deployments/unichain/weth/deploy.ts +++ b/deployments/unichain/weth/deploy.ts @@ -137,7 +137,7 @@ async function deployContracts( const bridgeReceiver = await deploymentManager.fromDep('bridgeReceiver', 'unichain', 'usdc'); // Deploy Comet - const deployed = await deployComet(deploymentManager, deploySpec, {}, true); + const deployed = await deployComet(deploymentManager, deploySpec); return { ...deployed, From f4d74bda1584f5d712cac7681e97af1305557c79 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Mon, 1 Jun 2026 20:57:27 +0300 Subject: [PATCH 56/65] Delete ScrollComet.sol --- contracts/ScrollComet.sol | 1324 ------------------------------------- 1 file changed, 1324 deletions(-) delete mode 100644 contracts/ScrollComet.sol diff --git a/contracts/ScrollComet.sol b/contracts/ScrollComet.sol deleted file mode 100644 index 26cafd500..000000000 --- a/contracts/ScrollComet.sol +++ /dev/null @@ -1,1324 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.15; - -import "./CometMainInterface.sol"; -import "./ERC20.sol"; -import "./IPriceFeed.sol"; - -/** - * @title Compound's Comet Contract on Scroll - * @notice An efficient monolithic money market protocol - * @author Compound - */ -contract ScrollComet is CometMainInterface { - /** General configuration constants **/ - - /// @notice The admin of the protocol - address public override immutable governor; - - /// @notice The account which may trigger pauses - address public override immutable pauseGuardian; - - /// @notice The address of the base token contract - address public override immutable baseToken; - - /// @notice The address of the price feed for the base token - address public override immutable baseTokenPriceFeed; - - /// @notice The address of the extension contract delegate - address public override immutable extensionDelegate; - - /// @notice The point in the supply rates separating the low interest rate slope and the high interest rate slope (factor) - /// @dev uint64 - uint public override immutable supplyKink; - - /// @notice Per second supply interest rate slope applied when utilization is below kink (factor) - /// @dev uint64 - uint public override immutable supplyPerSecondInterestRateSlopeLow; - - /// @notice Per second supply interest rate slope applied when utilization is above kink (factor) - /// @dev uint64 - uint public override immutable supplyPerSecondInterestRateSlopeHigh; - - /// @notice Per second supply base interest rate (factor) - /// @dev uint64 - uint public override immutable supplyPerSecondInterestRateBase; - - /// @notice The point in the borrow rate separating the low interest rate slope and the high interest rate slope (factor) - /// @dev uint64 - uint public override immutable borrowKink; - - /// @notice Per second borrow interest rate slope applied when utilization is below kink (factor) - /// @dev uint64 - uint public override immutable borrowPerSecondInterestRateSlopeLow; - - /// @notice Per second borrow interest rate slope applied when utilization is above kink (factor) - /// @dev uint64 - uint public override immutable borrowPerSecondInterestRateSlopeHigh; - - /// @notice Per second borrow base interest rate (factor) - /// @dev uint64 - uint public override immutable borrowPerSecondInterestRateBase; - - /// @notice The fraction of the liquidation penalty that goes to buyers of collateral instead of the protocol - /// @dev uint64 - uint public override immutable storeFrontPriceFactor; - - /// @notice The scale for base token (must be less than 18 decimals) - /// @dev uint64 - uint public override immutable baseScale; - - /// @notice The scale for reward tracking - /// @dev uint64 - uint public override immutable trackingIndexScale; - - /// @notice The speed at which supply rewards are tracked (in trackingIndexScale) - /// @dev uint64 - uint public override immutable baseTrackingSupplySpeed; - - /// @notice The speed at which borrow rewards are tracked (in trackingIndexScale) - /// @dev uint64 - uint public override immutable baseTrackingBorrowSpeed; - - /// @notice The minimum amount of base principal wei for rewards to accrue - /// @dev This must be large enough so as to prevent division by base wei from overflowing the 64 bit indices - /// @dev uint104 - uint public override immutable baseMinForRewards; - - /// @notice The minimum base amount required to initiate a borrow - uint public override immutable baseBorrowMin; - - /// @notice The minimum base token reserves which must be held before collateral is hodled - uint public override immutable targetReserves; - - /// @notice The number of decimals for wrapped base token - uint8 public override immutable decimals; - - /// @notice The number of assets this contract actually supports - uint8 public override immutable numAssets; - - /// @notice Factor to divide by when accruing rewards in order to preserve 6 decimals (i.e. baseScale / 1e6) - uint internal immutable accrualDescaleFactor; - - /** Collateral asset configuration (packed) **/ - - uint256 internal immutable asset00_a; - uint256 internal immutable asset00_b; - uint256 internal immutable asset01_a; - uint256 internal immutable asset01_b; - uint256 internal immutable asset02_a; - uint256 internal immutable asset02_b; - uint256 internal immutable asset03_a; - uint256 internal immutable asset03_b; - uint256 internal immutable asset04_a; - uint256 internal immutable asset04_b; - uint256 internal immutable asset05_a; - uint256 internal immutable asset05_b; - uint256 internal immutable asset06_a; - uint256 internal immutable asset06_b; - uint256 internal immutable asset07_a; - uint256 internal immutable asset07_b; - uint256 internal immutable asset08_a; - uint256 internal immutable asset08_b; - uint256 internal immutable asset09_a; - uint256 internal immutable asset09_b; - uint256 internal immutable asset10_a; - uint256 internal immutable asset10_b; - uint256 internal immutable asset11_a; - uint256 internal immutable asset11_b; - uint256 internal immutable asset12_a; - uint256 internal immutable asset12_b; - uint256 internal immutable asset13_a; - uint256 internal immutable asset13_b; - uint256 internal immutable asset14_a; - uint256 internal immutable asset14_b; - - /** - * @notice Construct a new protocol instance - * @param config The mapping of initial/constant parameters - **/ - constructor(Configuration memory config) { - // Sanity checks - uint8 decimals_ = ERC20(config.baseToken).decimals(); - if (decimals_ > MAX_BASE_DECIMALS) revert BadDecimals(); - if (config.storeFrontPriceFactor > FACTOR_SCALE) revert BadDiscount(); - if (config.assetConfigs.length > MAX_ASSETS) revert TooManyAssets(); - if (config.baseMinForRewards == 0) revert BadMinimum(); - if (IPriceFeed(config.baseTokenPriceFeed).decimals() != PRICE_FEED_DECIMALS) revert BadDecimals(); - - // Copy configuration - unchecked { - governor = config.governor; - pauseGuardian = config.pauseGuardian; - baseToken = config.baseToken; - baseTokenPriceFeed = config.baseTokenPriceFeed; - extensionDelegate = config.extensionDelegate; - storeFrontPriceFactor = config.storeFrontPriceFactor; - - decimals = decimals_; - baseScale = uint64(10 ** decimals_); - trackingIndexScale = config.trackingIndexScale; - if (baseScale < BASE_ACCRUAL_SCALE) revert BadDecimals(); - accrualDescaleFactor = baseScale / BASE_ACCRUAL_SCALE; - - baseMinForRewards = config.baseMinForRewards; - baseTrackingSupplySpeed = config.baseTrackingSupplySpeed; - baseTrackingBorrowSpeed = config.baseTrackingBorrowSpeed; - - baseBorrowMin = config.baseBorrowMin; - targetReserves = config.targetReserves; - } - - // Set interest rate model configs - unchecked { - supplyKink = config.supplyKink; - supplyPerSecondInterestRateSlopeLow = config.supplyPerYearInterestRateSlopeLow / SECONDS_PER_YEAR; - supplyPerSecondInterestRateSlopeHigh = config.supplyPerYearInterestRateSlopeHigh / SECONDS_PER_YEAR; - supplyPerSecondInterestRateBase = config.supplyPerYearInterestRateBase / SECONDS_PER_YEAR; - borrowKink = config.borrowKink; - borrowPerSecondInterestRateSlopeLow = config.borrowPerYearInterestRateSlopeLow / SECONDS_PER_YEAR; - borrowPerSecondInterestRateSlopeHigh = config.borrowPerYearInterestRateSlopeHigh / SECONDS_PER_YEAR; - borrowPerSecondInterestRateBase = config.borrowPerYearInterestRateBase / SECONDS_PER_YEAR; - } - - // Set asset info - numAssets = uint8(config.assetConfigs.length); - - (asset00_a, asset00_b) = getPackedAssetInternal(config.assetConfigs, 0); - (asset01_a, asset01_b) = getPackedAssetInternal(config.assetConfigs, 1); - (asset02_a, asset02_b) = getPackedAssetInternal(config.assetConfigs, 2); - (asset03_a, asset03_b) = getPackedAssetInternal(config.assetConfigs, 3); - (asset04_a, asset04_b) = getPackedAssetInternal(config.assetConfigs, 4); - (asset05_a, asset05_b) = getPackedAssetInternal(config.assetConfigs, 5); - (asset06_a, asset06_b) = getPackedAssetInternal(config.assetConfigs, 6); - (asset07_a, asset07_b) = getPackedAssetInternal(config.assetConfigs, 7); - (asset08_a, asset08_b) = getPackedAssetInternal(config.assetConfigs, 8); - (asset09_a, asset09_b) = getPackedAssetInternal(config.assetConfigs, 9); - (asset10_a, asset10_b) = getPackedAssetInternal(config.assetConfigs, 10); - (asset11_a, asset11_b) = getPackedAssetInternal(config.assetConfigs, 11); - (asset12_a, asset12_b) = getPackedAssetInternal(config.assetConfigs, 12); - (asset13_a, asset13_b) = getPackedAssetInternal(config.assetConfigs, 13); - (asset14_a, asset14_b) = getPackedAssetInternal(config.assetConfigs, 14); - } - - /** - * @notice Initialize storage for the contract - * @dev Can be used from constructor or proxy - */ - function initializeStorage() override external { - if (lastAccrualTime != 0) revert AlreadyInitialized(); - - // Initialize aggregates - lastAccrualTime = getNowInternal(); - baseSupplyIndex = BASE_INDEX_SCALE; - baseBorrowIndex = BASE_INDEX_SCALE; - - // Implicit initialization (not worth increasing contract size) - // trackingSupplyIndex = 0; - // trackingBorrowIndex = 0; - } - - /** - * @dev Checks and gets the packed asset info for storage - */ - function getPackedAssetInternal(AssetConfig[] memory assetConfigs, uint i) internal view returns (uint256, uint256) { - AssetConfig memory assetConfig; - if (i < assetConfigs.length) { - assembly { - assetConfig := mload(add(add(assetConfigs, 0x20), mul(i, 0x20))) - } - } else { - return (0, 0); - } - address asset = assetConfig.asset; - address priceFeed = assetConfig.priceFeed; - uint8 decimals_ = assetConfig.decimals; - - // Short-circuit if asset is nil - if (asset == address(0)) { - return (0, 0); - } - - // Sanity check price feed and asset decimals - if (IPriceFeed(priceFeed).decimals() != PRICE_FEED_DECIMALS) revert BadDecimals(); - if (ERC20(asset).decimals() != decimals_) revert BadDecimals(); - - // Ensure collateral factors are within range - if (assetConfig.borrowCollateralFactor >= assetConfig.liquidateCollateralFactor) revert BorrowCFTooLarge(); - if (assetConfig.liquidateCollateralFactor > MAX_COLLATERAL_FACTOR) revert LiquidateCFTooLarge(); - - unchecked { - // Keep 4 decimals for each factor - uint64 descale = FACTOR_SCALE / 1e4; - uint16 borrowCollateralFactor = uint16(assetConfig.borrowCollateralFactor / descale); - uint16 liquidateCollateralFactor = uint16(assetConfig.liquidateCollateralFactor / descale); - uint16 liquidationFactor = uint16(assetConfig.liquidationFactor / descale); - - // Be nice and check descaled values are still within range - if (borrowCollateralFactor >= liquidateCollateralFactor) revert BorrowCFTooLarge(); - - // Keep whole units of asset for supply cap - uint64 supplyCap = uint64(assetConfig.supplyCap / (10 ** decimals_)); - - uint256 word_a = (uint160(asset) << 0 | - uint256(borrowCollateralFactor) << 160 | - uint256(liquidateCollateralFactor) << 176 | - uint256(liquidationFactor) << 192); - uint256 word_b = (uint160(priceFeed) << 0 | - uint256(decimals_) << 160 | - uint256(supplyCap) << 168); - - return (word_a, word_b); - } - } - - /** - * @notice Get the i-th asset info, according to the order they were passed in originally - * @param i The index of the asset info to get - * @return The asset info object - */ - function getAssetInfo(uint8 i) override public view returns (AssetInfo memory) { - if (i >= numAssets) revert BadAsset(); - - uint256 word_a; - uint256 word_b; - - if (i == 0) { - word_a = asset00_a; - word_b = asset00_b; - } else if (i == 1) { - word_a = asset01_a; - word_b = asset01_b; - } else if (i == 2) { - word_a = asset02_a; - word_b = asset02_b; - } else if (i == 3) { - word_a = asset03_a; - word_b = asset03_b; - } else if (i == 4) { - word_a = asset04_a; - word_b = asset04_b; - } else if (i == 5) { - word_a = asset05_a; - word_b = asset05_b; - } else if (i == 6) { - word_a = asset06_a; - word_b = asset06_b; - } else if (i == 7) { - word_a = asset07_a; - word_b = asset07_b; - } else if (i == 8) { - word_a = asset08_a; - word_b = asset08_b; - } else if (i == 9) { - word_a = asset09_a; - word_b = asset09_b; - } else if (i == 10) { - word_a = asset10_a; - word_b = asset10_b; - } else if (i == 11) { - word_a = asset11_a; - word_b = asset11_b; - } else if (i == 12) { - word_a = asset12_a; - word_b = asset12_b; - } else if (i == 13) { - word_a = asset13_a; - word_b = asset13_b; - } else if (i == 14) { - word_a = asset14_a; - word_b = asset14_b; - } else { - revert Absurd(); - } - - address asset = address(uint160(word_a & type(uint160).max)); - uint64 rescale = FACTOR_SCALE / 1e4; - uint64 borrowCollateralFactor = uint64(((word_a >> 160) & type(uint16).max) * rescale); - uint64 liquidateCollateralFactor = uint64(((word_a >> 176) & type(uint16).max) * rescale); - uint64 liquidationFactor = uint64(((word_a >> 192) & type(uint16).max) * rescale); - - address priceFeed = address(uint160(word_b & type(uint160).max)); - uint8 decimals_ = uint8(((word_b >> 160) & type(uint8).max)); - uint64 scale = uint64(10 ** decimals_); - uint128 supplyCap = uint128(((word_b >> 168) & type(uint64).max) * scale); - - return AssetInfo({ - offset: i, - asset: asset, - priceFeed: priceFeed, - scale: scale, - borrowCollateralFactor: borrowCollateralFactor, - liquidateCollateralFactor: liquidateCollateralFactor, - liquidationFactor: liquidationFactor, - supplyCap: supplyCap - }); - } - - /** - * @dev Determine index of asset that matches given address - */ - function getAssetInfoByAddress(address asset) override public view returns (AssetInfo memory) { - for (uint8 i = 0; i < numAssets; ) { - AssetInfo memory assetInfo = getAssetInfo(i); - if (assetInfo.asset == asset) { - return assetInfo; - } - unchecked { i++; } - } - revert BadAsset(); - } - - /** - * @return The current timestamp - **/ - function getNowInternal() virtual internal view returns (uint40) { - if (block.timestamp >= 2**40) revert TimestampTooLarge(); - return uint40(block.timestamp); - } - - /** - * @dev Calculate accrued interest indices for base token supply and borrows - **/ - function accruedInterestIndices(uint timeElapsed) internal view returns (uint64, uint64) { - uint64 baseSupplyIndex_ = baseSupplyIndex; - uint64 baseBorrowIndex_ = baseBorrowIndex; - if (timeElapsed > 0) { - uint utilization = getUtilization(); - uint supplyRate = getSupplyRate(utilization); - uint borrowRate = getBorrowRate(utilization); - baseSupplyIndex_ += safe64(mulFactor(baseSupplyIndex_, supplyRate * timeElapsed)); - baseBorrowIndex_ += safe64(mulFactor(baseBorrowIndex_, borrowRate * timeElapsed)); - } - return (baseSupplyIndex_, baseBorrowIndex_); - } - - /** - * @dev Accrue interest (and rewards) in base token supply and borrows - **/ - function accrueInternal() internal { - uint40 now_ = getNowInternal(); - uint timeElapsed = uint256(now_ - lastAccrualTime); - if (timeElapsed > 0) { - (baseSupplyIndex, baseBorrowIndex) = accruedInterestIndices(timeElapsed); - if (totalSupplyBase >= baseMinForRewards) { - trackingSupplyIndex += safe64(divBaseWei(baseTrackingSupplySpeed * timeElapsed, totalSupplyBase)); - } - if (totalBorrowBase >= baseMinForRewards) { - trackingBorrowIndex += safe64(divBaseWei(baseTrackingBorrowSpeed * timeElapsed, totalBorrowBase)); - } - lastAccrualTime = now_; - } - } - - /** - * @notice Accrue interest and rewards for an account - **/ - function accrueAccount(address account) override external { - accrueInternal(); - - UserBasic memory basic = userBasic[account]; - updateBasePrincipal(account, basic, basic.principal); - } - - /** - * @dev Note: Does not accrue interest first - * @param utilization The utilization to check the supply rate for - * @return The per second supply rate at `utilization` - */ - function getSupplyRate(uint utilization) override public view returns (uint64) { - if (utilization <= supplyKink) { - // interestRateBase + interestRateSlopeLow * utilization - return safe64(supplyPerSecondInterestRateBase + mulFactor(supplyPerSecondInterestRateSlopeLow, utilization)); - } else { - // interestRateBase + interestRateSlopeLow * kink + interestRateSlopeHigh * (utilization - kink) - return safe64(supplyPerSecondInterestRateBase + mulFactor(supplyPerSecondInterestRateSlopeLow, supplyKink) + mulFactor(supplyPerSecondInterestRateSlopeHigh, (utilization - supplyKink))); - } - } - - /** - * @dev Note: Does not accrue interest first - * @param utilization The utilization to check the borrow rate for - * @return The per second borrow rate at `utilization` - */ - function getBorrowRate(uint utilization) override public view returns (uint64) { - if (utilization <= borrowKink) { - // interestRateBase + interestRateSlopeLow * utilization - return safe64(borrowPerSecondInterestRateBase + mulFactor(borrowPerSecondInterestRateSlopeLow, utilization)); - } else { - // interestRateBase + interestRateSlopeLow * kink + interestRateSlopeHigh * (utilization - kink) - return safe64(borrowPerSecondInterestRateBase + mulFactor(borrowPerSecondInterestRateSlopeLow, borrowKink) + mulFactor(borrowPerSecondInterestRateSlopeHigh, (utilization - borrowKink))); - } - } - - /** - * @dev Note: Does not accrue interest first - * @return The utilization rate of the base asset - */ - function getUtilization() override public view returns (uint) { - uint totalSupply_ = presentValueSupply(baseSupplyIndex, totalSupplyBase); - uint totalBorrow_ = presentValueBorrow(baseBorrowIndex, totalBorrowBase); - if (totalSupply_ == 0) { - return 0; - } else { - return totalBorrow_ * FACTOR_SCALE / totalSupply_; - } - } - - /** - * @notice Get the current price from a feed - * @param priceFeed The address of a price feed - * @return The price, scaled by `PRICE_SCALE` - */ - function getPrice(address priceFeed) override public view returns (uint256) { - (, int price, , , ) = IPriceFeed(priceFeed).latestRoundData(); - if (price <= 0) revert BadPrice(); - return uint256(price); - } - - /** - * @notice Gets the total balance of protocol collateral reserves for an asset - * @dev Note: Reverts if collateral reserves are somehow negative, which should not be possible - * @param asset The collateral asset - */ - function getCollateralReserves(address asset) override public view returns (uint) { - return ERC20(asset).balanceOf(address(this)) - totalsCollateral[asset].totalSupplyAsset; - } - - /** - * @notice Gets the total amount of protocol reserves of the base asset - */ - function getReserves() override public view returns (int) { - (uint64 baseSupplyIndex_, uint64 baseBorrowIndex_) = accruedInterestIndices(getNowInternal() - lastAccrualTime); - uint balance = ERC20(baseToken).balanceOf(address(this)); - uint totalSupply_ = presentValueSupply(baseSupplyIndex_, totalSupplyBase); - uint totalBorrow_ = presentValueBorrow(baseBorrowIndex_, totalBorrowBase); - return signed256(balance) - signed256(totalSupply_) + signed256(totalBorrow_); - } - - /** - * @notice Check whether an account has enough collateral to borrow - * @param account The address to check - * @return Whether the account is minimally collateralized enough to borrow - */ - function isBorrowCollateralized(address account) override public view returns (bool) { - int104 principal = userBasic[account].principal; - - if (principal >= 0) { - return true; - } - - uint16 assetsIn = userBasic[account].assetsIn; - int liquidity = signedMulPrice( - presentValue(principal), - getPrice(baseTokenPriceFeed), - uint64(baseScale) - ); - - for (uint8 i = 0; i < numAssets; ) { - if (isInAsset(assetsIn, i)) { - if (liquidity >= 0) { - return true; - } - - AssetInfo memory asset = getAssetInfo(i); - uint newAmount = mulPrice( - userCollateral[account][asset.asset].balance, - getPrice(asset.priceFeed), - asset.scale - ); - liquidity += signed256(mulFactor( - newAmount, - asset.borrowCollateralFactor - )); - } - unchecked { i++; } - } - - return liquidity >= 0; - } - - /** - * @notice Check whether an account has enough collateral to not be liquidated - * @param account The address to check - * @return Whether the account is minimally collateralized enough to not be liquidated - */ - function isLiquidatable(address account) override public view returns (bool) { - int104 principal = userBasic[account].principal; - - if (principal >= 0) { - return false; - } - - uint16 assetsIn = userBasic[account].assetsIn; - int liquidity = signedMulPrice( - presentValue(principal), - getPrice(baseTokenPriceFeed), - uint64(baseScale) - ); - - for (uint8 i = 0; i < numAssets; ) { - if (isInAsset(assetsIn, i)) { - if (liquidity >= 0) { - return false; - } - - AssetInfo memory asset = getAssetInfo(i); - uint newAmount = mulPrice( - userCollateral[account][asset.asset].balance, - getPrice(asset.priceFeed), - asset.scale - ); - liquidity += signed256(mulFactor( - newAmount, - asset.liquidateCollateralFactor - )); - } - unchecked { i++; } - } - - return liquidity < 0; - } - - /** - * @dev The change in principal broken into repay and supply amounts - */ - function repayAndSupplyAmount(int104 oldPrincipal, int104 newPrincipal) internal pure returns (uint104, uint104) { - // If the new principal is less than the old principal, then no amount has been repaid or supplied - if (newPrincipal < oldPrincipal) return (0, 0); - - if (newPrincipal <= 0) { - return (uint104(newPrincipal - oldPrincipal), 0); - } else if (oldPrincipal >= 0) { - return (0, uint104(newPrincipal - oldPrincipal)); - } else { - return (uint104(-oldPrincipal), uint104(newPrincipal)); - } - } - - /** - * @dev The change in principal broken into withdraw and borrow amounts - */ - function withdrawAndBorrowAmount(int104 oldPrincipal, int104 newPrincipal) internal pure returns (uint104, uint104) { - // If the new principal is greater than the old principal, then no amount has been withdrawn or borrowed - if (newPrincipal > oldPrincipal) return (0, 0); - - if (newPrincipal >= 0) { - return (uint104(oldPrincipal - newPrincipal), 0); - } else if (oldPrincipal <= 0) { - return (0, uint104(oldPrincipal - newPrincipal)); - } else { - return (uint104(oldPrincipal), uint104(-newPrincipal)); - } - } - - /** - * @notice Pauses different actions within Comet - * @param supplyPaused Boolean for pausing supply actions - * @param transferPaused Boolean for pausing transfer actions - * @param withdrawPaused Boolean for pausing withdraw actions - * @param absorbPaused Boolean for pausing absorb actions - * @param buyPaused Boolean for pausing buy actions - */ - function pause( - bool supplyPaused, - bool transferPaused, - bool withdrawPaused, - bool absorbPaused, - bool buyPaused - ) override external { - if (msg.sender != governor && msg.sender != pauseGuardian) revert Unauthorized(); - - pauseFlags = - uint8(0) | - (toUInt8(supplyPaused) << PAUSE_SUPPLY_OFFSET) | - (toUInt8(transferPaused) << PAUSE_TRANSFER_OFFSET) | - (toUInt8(withdrawPaused) << PAUSE_WITHDRAW_OFFSET) | - (toUInt8(absorbPaused) << PAUSE_ABSORB_OFFSET) | - (toUInt8(buyPaused) << PAUSE_BUY_OFFSET); - - emit PauseAction(supplyPaused, transferPaused, withdrawPaused, absorbPaused, buyPaused); - } - - /** - * @return Whether or not supply actions are paused - */ - function isSupplyPaused() override public view returns (bool) { - return toBool(pauseFlags & (uint8(1) << PAUSE_SUPPLY_OFFSET)); - } - - /** - * @return Whether or not transfer actions are paused - */ - function isTransferPaused() override public view returns (bool) { - return toBool(pauseFlags & (uint8(1) << PAUSE_TRANSFER_OFFSET)); - } - - /** - * @return Whether or not withdraw actions are paused - */ - function isWithdrawPaused() override public view returns (bool) { - return toBool(pauseFlags & (uint8(1) << PAUSE_WITHDRAW_OFFSET)); - } - - /** - * @return Whether or not absorb actions are paused - */ - function isAbsorbPaused() override public view returns (bool) { - return toBool(pauseFlags & (uint8(1) << PAUSE_ABSORB_OFFSET)); - } - - /** - * @return Whether or not buy actions are paused - */ - function isBuyPaused() override public view returns (bool) { - return toBool(pauseFlags & (uint8(1) << PAUSE_BUY_OFFSET)); - } - - /** - * @dev Multiply a number by a factor - */ - function mulFactor(uint n, uint factor) internal pure returns (uint) { - return n * factor / FACTOR_SCALE; - } - - /** - * @dev Divide a number by an amount of base - */ - function divBaseWei(uint n, uint baseWei) internal view returns (uint) { - return n * baseScale / baseWei; - } - - /** - * @dev Multiply a `fromScale` quantity by a price, returning a common price quantity - */ - function mulPrice(uint n, uint price, uint64 fromScale) internal pure returns (uint) { - return n * price / fromScale; - } - - /** - * @dev Multiply a signed `fromScale` quantity by a price, returning a common price quantity - */ - function signedMulPrice(int n, uint price, uint64 fromScale) internal pure returns (int) { - return n * signed256(price) / int256(uint256(fromScale)); - } - - /** - * @dev Divide a common price quantity by a price, returning a `toScale` quantity - */ - function divPrice(uint n, uint price, uint64 toScale) internal pure returns (uint) { - return n * toScale / price; - } - - /** - * @dev Whether user has a non-zero balance of an asset, given assetsIn flags - */ - function isInAsset(uint16 assetsIn, uint8 assetOffset) internal pure returns (bool) { - return (assetsIn & (uint16(1) << assetOffset) != 0); - } - - /** - * @dev Update assetsIn bit vector if user has entered or exited an asset - */ - function updateAssetsIn( - address account, - AssetInfo memory assetInfo, - uint128 initialUserBalance, - uint128 finalUserBalance - ) internal { - if (initialUserBalance == 0 && finalUserBalance != 0) { - // set bit for asset - userBasic[account].assetsIn |= (uint16(1) << assetInfo.offset); - } else if (initialUserBalance != 0 && finalUserBalance == 0) { - // clear bit for asset - userBasic[account].assetsIn &= ~(uint16(1) << assetInfo.offset); - } - } - - /** - * @dev Write updated principal to store and tracking participation - */ - function updateBasePrincipal(address account, UserBasic memory basic, int104 principalNew) internal { - int104 principal = basic.principal; - basic.principal = principalNew; - - if (principal >= 0) { - uint indexDelta = uint256(trackingSupplyIndex - basic.baseTrackingIndex); - basic.baseTrackingAccrued += safe64(uint104(principal) * indexDelta / trackingIndexScale / accrualDescaleFactor); - } else { - uint indexDelta = uint256(trackingBorrowIndex - basic.baseTrackingIndex); - basic.baseTrackingAccrued += safe64(uint104(-principal) * indexDelta / trackingIndexScale / accrualDescaleFactor); - } - - if (principalNew >= 0) { - basic.baseTrackingIndex = trackingSupplyIndex; - } else { - basic.baseTrackingIndex = trackingBorrowIndex; - } - - userBasic[account] = basic; - } - - /** - * @dev Safe ERC20 transfer in, assumes no fee is charged and amount is transferred - */ - function doTransferIn(address asset, address from, uint amount) internal { - bool success = ERC20(asset).transferFrom(from, address(this), amount); - if (!success) revert TransferInFailed(); - } - - /** - * @dev Safe ERC20 transfer out - */ - function doTransferOut(address asset, address to, uint amount) internal { - bool success = ERC20(asset).transfer(to, amount); - if (!success) revert TransferOutFailed(); - } - - /** - * @notice Supply an amount of asset to the protocol - * @param asset The asset to supply - * @param amount The quantity to supply - */ - function supply(address asset, uint amount) override external { - return supplyInternal(msg.sender, msg.sender, msg.sender, asset, amount); - } - - /** - * @notice Supply an amount of asset to dst - * @param dst The address which will hold the balance - * @param asset The asset to supply - * @param amount The quantity to supply - */ - function supplyTo(address dst, address asset, uint amount) override external { - return supplyInternal(msg.sender, msg.sender, dst, asset, amount); - } - - /** - * @notice Supply an amount of asset from `from` to dst, if allowed - * @param from The supplier address - * @param dst The address which will hold the balance - * @param asset The asset to supply - * @param amount The quantity to supply - */ - function supplyFrom(address from, address dst, address asset, uint amount) override external { - return supplyInternal(msg.sender, from, dst, asset, amount); - } - - /** - * @dev Supply either collateral or base asset, depending on the asset, if operator is allowed - * @dev Note: Specifying an `amount` of uint256.max will repay all of `dst`'s accrued base borrow balance - */ - function supplyInternal(address operator, address from, address dst, address asset, uint amount) internal { - if (isSupplyPaused()) revert Paused(); - if (!hasPermission(from, operator)) revert Unauthorized(); - - if (asset == baseToken) { - if (amount == type(uint256).max) { - amount = borrowBalanceOf(dst); - } - return supplyBase(from, dst, amount); - } else { - return supplyCollateral(from, dst, asset, safe128(amount)); - } - } - - /** - * @dev Supply an amount of base asset from `from` to dst - */ - function supplyBase(address from, address dst, uint256 amount) internal { - doTransferIn(baseToken, from, amount); - - accrueInternal(); - - UserBasic memory dstUser = userBasic[dst]; - int104 dstPrincipal = dstUser.principal; - int256 dstBalance = presentValue(dstPrincipal) + signed256(amount); - int104 dstPrincipalNew = principalValue(dstBalance); - - (uint104 repayAmount, uint104 supplyAmount) = repayAndSupplyAmount(dstPrincipal, dstPrincipalNew); - - totalSupplyBase += supplyAmount; - totalBorrowBase -= repayAmount; - - updateBasePrincipal(dst, dstUser, dstPrincipalNew); - - emit Supply(from, dst, amount); - - if (supplyAmount > 0) { - emit Transfer(address(0), dst, presentValueSupply(baseSupplyIndex, supplyAmount)); - } - } - - /** - * @dev Supply an amount of collateral asset from `from` to dst - */ - function supplyCollateral(address from, address dst, address asset, uint128 amount) internal { - doTransferIn(asset, from, amount); - - AssetInfo memory assetInfo = getAssetInfoByAddress(asset); - TotalsCollateral memory totals = totalsCollateral[asset]; - totals.totalSupplyAsset += amount; - if (totals.totalSupplyAsset > assetInfo.supplyCap) revert SupplyCapExceeded(); - - uint128 dstCollateral = userCollateral[dst][asset].balance; - uint128 dstCollateralNew = dstCollateral + amount; - - totalsCollateral[asset] = totals; - userCollateral[dst][asset].balance = dstCollateralNew; - - updateAssetsIn(dst, assetInfo, dstCollateral, dstCollateralNew); - - emit SupplyCollateral(from, dst, asset, amount); - } - - /** - * @notice ERC20 transfer an amount of base token to dst - * @param dst The recipient address - * @param amount The quantity to transfer - * @return true - */ - function transfer(address dst, uint amount) override external returns (bool) { - transferInternal(msg.sender, msg.sender, dst, baseToken, amount); - return true; - } - - /** - * @notice ERC20 transfer an amount of base token from src to dst, if allowed - * @param src The sender address - * @param dst The recipient address - * @param amount The quantity to transfer - * @return true - */ - function transferFrom(address src, address dst, uint amount) override external returns (bool) { - transferInternal(msg.sender, src, dst, baseToken, amount); - return true; - } - - /** - * @notice Transfer an amount of asset to dst - * @param dst The recipient address - * @param asset The asset to transfer - * @param amount The quantity to transfer - */ - function transferAsset(address dst, address asset, uint amount) override external { - return transferInternal(msg.sender, msg.sender, dst, asset, amount); - } - - /** - * @notice Transfer an amount of asset from src to dst, if allowed - * @param src The sender address - * @param dst The recipient address - * @param asset The asset to transfer - * @param amount The quantity to transfer - */ - function transferAssetFrom(address src, address dst, address asset, uint amount) override external { - return transferInternal(msg.sender, src, dst, asset, amount); - } - - /** - * @dev Transfer either collateral or base asset, depending on the asset, if operator is allowed - * @dev Note: Specifying an `amount` of uint256.max will transfer all of `src`'s accrued base balance - */ - function transferInternal(address operator, address src, address dst, address asset, uint amount) internal { - if (isTransferPaused()) revert Paused(); - if (!hasPermission(src, operator)) revert Unauthorized(); - if (src == dst) revert NoSelfTransfer(); - - if (asset == baseToken) { - if (amount == type(uint256).max) { - amount = balanceOf(src); - } - return transferBase(src, dst, amount); - } else { - return transferCollateral(src, dst, asset, safe128(amount)); - } - } - - /** - * @dev Transfer an amount of base asset from src to dst, borrowing if possible/necessary - */ - function transferBase(address src, address dst, uint256 amount) internal { - accrueInternal(); - - UserBasic memory srcUser = userBasic[src]; - UserBasic memory dstUser = userBasic[dst]; - - int104 srcPrincipal = srcUser.principal; - int104 dstPrincipal = dstUser.principal; - int256 srcBalance = presentValue(srcPrincipal) - signed256(amount); - int256 dstBalance = presentValue(dstPrincipal) + signed256(amount); - int104 srcPrincipalNew = principalValue(srcBalance); - int104 dstPrincipalNew = principalValue(dstBalance); - - (uint104 withdrawAmount, uint104 borrowAmount) = withdrawAndBorrowAmount(srcPrincipal, srcPrincipalNew); - (uint104 repayAmount, uint104 supplyAmount) = repayAndSupplyAmount(dstPrincipal, dstPrincipalNew); - - // Note: Instead of `total += addAmount - subAmount` to avoid underflow errors. - totalSupplyBase = totalSupplyBase + supplyAmount - withdrawAmount; - totalBorrowBase = totalBorrowBase + borrowAmount - repayAmount; - - updateBasePrincipal(src, srcUser, srcPrincipalNew); - updateBasePrincipal(dst, dstUser, dstPrincipalNew); - - if (srcBalance < 0) { - if (uint256(-srcBalance) < baseBorrowMin) revert BorrowTooSmall(); - if (!isBorrowCollateralized(src)) revert NotCollateralized(); - } - - if (withdrawAmount > 0) { - emit Transfer(src, address(0), presentValueSupply(baseSupplyIndex, withdrawAmount)); - } - - if (supplyAmount > 0) { - emit Transfer(address(0), dst, presentValueSupply(baseSupplyIndex, supplyAmount)); - } - } - - /** - * @dev Transfer an amount of collateral asset from src to dst - */ - function transferCollateral(address src, address dst, address asset, uint128 amount) internal { - uint128 srcCollateral = userCollateral[src][asset].balance; - uint128 dstCollateral = userCollateral[dst][asset].balance; - uint128 srcCollateralNew = srcCollateral - amount; - uint128 dstCollateralNew = dstCollateral + amount; - - userCollateral[src][asset].balance = srcCollateralNew; - userCollateral[dst][asset].balance = dstCollateralNew; - - AssetInfo memory assetInfo = getAssetInfoByAddress(asset); - updateAssetsIn(src, assetInfo, srcCollateral, srcCollateralNew); - updateAssetsIn(dst, assetInfo, dstCollateral, dstCollateralNew); - - // Note: no accrue interest, BorrowCF < LiquidationCF covers small changes - if (!isBorrowCollateralized(src)) revert NotCollateralized(); - - emit TransferCollateral(src, dst, asset, amount); - } - - /** - * @notice Withdraw an amount of asset from the protocol - * @param asset The asset to withdraw - * @param amount The quantity to withdraw - */ - function withdraw(address asset, uint amount) override external { - return withdrawInternal(msg.sender, msg.sender, msg.sender, asset, amount); - } - - /** - * @notice Withdraw an amount of asset to `to` - * @param to The recipient address - * @param asset The asset to withdraw - * @param amount The quantity to withdraw - */ - function withdrawTo(address to, address asset, uint amount) override external { - return withdrawInternal(msg.sender, msg.sender, to, asset, amount); - } - - /** - * @notice Withdraw an amount of asset from src to `to`, if allowed - * @param src The sender address - * @param to The recipient address - * @param asset The asset to withdraw - * @param amount The quantity to withdraw - */ - function withdrawFrom(address src, address to, address asset, uint amount) override external { - return withdrawInternal(msg.sender, src, to, asset, amount); - } - - /** - * @dev Withdraw either collateral or base asset, depending on the asset, if operator is allowed - * @dev Note: Specifying an `amount` of uint256.max will withdraw all of `src`'s accrued base balance - */ - function withdrawInternal(address operator, address src, address to, address asset, uint amount) internal { - if (isWithdrawPaused()) revert Paused(); - if (!hasPermission(src, operator)) revert Unauthorized(); - - if (asset == baseToken) { - if (amount == type(uint256).max) { - amount = balanceOf(src); - } - return withdrawBase(src, to, amount); - } else { - return withdrawCollateral(src, to, asset, safe128(amount)); - } - } - - /** - * @dev Withdraw an amount of base asset from src to `to`, borrowing if possible/necessary - */ - function withdrawBase(address src, address to, uint256 amount) internal { - accrueInternal(); - - UserBasic memory srcUser = userBasic[src]; - int104 srcPrincipal = srcUser.principal; - int256 srcBalance = presentValue(srcPrincipal) - signed256(amount); - int104 srcPrincipalNew = principalValue(srcBalance); - - (uint104 withdrawAmount, uint104 borrowAmount) = withdrawAndBorrowAmount(srcPrincipal, srcPrincipalNew); - - totalSupplyBase -= withdrawAmount; - totalBorrowBase += borrowAmount; - - updateBasePrincipal(src, srcUser, srcPrincipalNew); - - if (srcBalance < 0) { - if (uint256(-srcBalance) < baseBorrowMin) revert BorrowTooSmall(); - if (!isBorrowCollateralized(src)) revert NotCollateralized(); - } - - doTransferOut(baseToken, to, amount); - - emit Withdraw(src, to, amount); - - if (withdrawAmount > 0) { - emit Transfer(src, address(0), presentValueSupply(baseSupplyIndex, withdrawAmount)); - } - } - - /** - * @dev Withdraw an amount of collateral asset from src to `to` - */ - function withdrawCollateral(address src, address to, address asset, uint128 amount) internal { - uint128 srcCollateral = userCollateral[src][asset].balance; - uint128 srcCollateralNew = srcCollateral - amount; - - totalsCollateral[asset].totalSupplyAsset -= amount; - userCollateral[src][asset].balance = srcCollateralNew; - - AssetInfo memory assetInfo = getAssetInfoByAddress(asset); - updateAssetsIn(src, assetInfo, srcCollateral, srcCollateralNew); - - // Note: no accrue interest, BorrowCF < LiquidationCF covers small changes - if (!isBorrowCollateralized(src)) revert NotCollateralized(); - - doTransferOut(asset, to, amount); - - emit WithdrawCollateral(src, to, asset, amount); - } - - /** - * @notice Absorb a list of underwater accounts onto the protocol balance sheet - * @param absorber The recipient of the incentive paid to the caller of absorb - * @param accounts The list of underwater accounts to absorb - */ - function absorb(address absorber, address[] calldata accounts) override external { - if (isAbsorbPaused()) revert Paused(); - - uint startGas = gasleft(); - accrueInternal(); - for (uint i = 0; i < accounts.length; ) { - absorbInternal(absorber, accounts[i]); - unchecked { i++; } - } - uint gasUsed = startGas - gasleft(); - - // Note: liquidator points are an imperfect tool for governance, - // to be used while evaluating strategies for incentivizing absorption. - // Using gas price instead of base fee would more accurately reflect spend, - // but is also subject to abuse if refunds were to be given automatically. - LiquidatorPoints memory points = liquidatorPoints[absorber]; - points.numAbsorbs++; - points.numAbsorbed += safe64(accounts.length); - liquidatorPoints[absorber] = points; - } - - /** - * @dev Transfer user's collateral and debt to the protocol itself. - */ - function absorbInternal(address absorber, address account) internal { - if (!isLiquidatable(account)) revert NotLiquidatable(); - - UserBasic memory accountUser = userBasic[account]; - int104 oldPrincipal = accountUser.principal; - int256 oldBalance = presentValue(oldPrincipal); - uint16 assetsIn = accountUser.assetsIn; - - uint256 basePrice = getPrice(baseTokenPriceFeed); - uint256 deltaValue = 0; - - for (uint8 i = 0; i < numAssets; ) { - if (isInAsset(assetsIn, i)) { - AssetInfo memory assetInfo = getAssetInfo(i); - address asset = assetInfo.asset; - uint128 seizeAmount = userCollateral[account][asset].balance; - userCollateral[account][asset].balance = 0; - totalsCollateral[asset].totalSupplyAsset -= seizeAmount; - - uint256 value = mulPrice(seizeAmount, getPrice(assetInfo.priceFeed), assetInfo.scale); - deltaValue += mulFactor(value, assetInfo.liquidationFactor); - - emit AbsorbCollateral(absorber, account, asset, seizeAmount, value); - } - unchecked { i++; } - } - - uint256 deltaBalance = divPrice(deltaValue, basePrice, uint64(baseScale)); - int256 newBalance = oldBalance + signed256(deltaBalance); - // New balance will not be negative, all excess debt absorbed by reserves - if (newBalance < 0) { - newBalance = 0; - } - - int104 newPrincipal = principalValue(newBalance); - updateBasePrincipal(account, accountUser, newPrincipal); - - // reset assetsIn - userBasic[account].assetsIn = 0; - - (uint104 repayAmount, uint104 supplyAmount) = repayAndSupplyAmount(oldPrincipal, newPrincipal); - - // Reserves are decreased by increasing total supply and decreasing borrows - // the amount of debt repaid by reserves is `newBalance - oldBalance` - totalSupplyBase += supplyAmount; - totalBorrowBase -= repayAmount; - - uint256 basePaidOut = unsigned256(newBalance - oldBalance); - uint256 valueOfBasePaidOut = mulPrice(basePaidOut, basePrice, uint64(baseScale)); - emit AbsorbDebt(absorber, account, basePaidOut, valueOfBasePaidOut); - - if (newPrincipal > 0) { - emit Transfer(address(0), account, presentValueSupply(baseSupplyIndex, unsigned104(newPrincipal))); - } - } - - /** - * @notice Buy collateral from the protocol using base tokens, increasing protocol reserves - A minimum collateral amount should be specified to indicate the maximum slippage acceptable for the buyer. - * @param asset The asset to buy - * @param minAmount The minimum amount of collateral tokens that should be received by the buyer - * @param baseAmount The amount of base tokens used to buy the collateral - * @param recipient The recipient address - */ - function buyCollateral(address asset, uint minAmount, uint baseAmount, address recipient) override external { - if (isBuyPaused()) revert Paused(); - - int reserves = getReserves(); - if (reserves >= 0 && uint(reserves) >= targetReserves) revert NotForSale(); - - // Note: Re-entrancy can skip the reserves check above on a second buyCollateral call. - doTransferIn(baseToken, msg.sender, baseAmount); - - uint collateralAmount = quoteCollateral(asset, baseAmount); - if (collateralAmount < minAmount) revert TooMuchSlippage(); - if (collateralAmount > getCollateralReserves(asset)) revert InsufficientReserves(); - - // Note: Pre-transfer hook can re-enter buyCollateral with a stale collateral ERC20 balance. - // Assets should not be listed which allow re-entry from pre-transfer now, as too much collateral could be bought. - // This is also a problem if quoteCollateral derives its discount from the collateral ERC20 balance. - doTransferOut(asset, recipient, safe128(collateralAmount)); - - emit BuyCollateral(msg.sender, asset, baseAmount, collateralAmount); - } - - /** - * @notice Gets the quote for a collateral asset in exchange for an amount of base asset - * @param asset The collateral asset to get the quote for - * @param baseAmount The amount of the base asset to get the quote for - * @return The quote in terms of the collateral asset - */ - function quoteCollateral(address asset, uint baseAmount) override public view returns (uint) { - AssetInfo memory assetInfo = getAssetInfoByAddress(asset); - uint256 assetPrice = getPrice(assetInfo.priceFeed); - // Store front discount is derived from the collateral asset's liquidationFactor and storeFrontPriceFactor - // discount = storeFrontPriceFactor * (1e18 - liquidationFactor) - uint256 discountFactor = mulFactor(storeFrontPriceFactor, FACTOR_SCALE - assetInfo.liquidationFactor); - uint256 assetPriceDiscounted = mulFactor(assetPrice, FACTOR_SCALE - discountFactor); - uint256 basePrice = getPrice(baseTokenPriceFeed); - // # of collateral assets - // = (TotalValueOfBaseAmount / DiscountedPriceOfCollateralAsset) * assetScale - // = ((basePrice * baseAmount / baseScale) / assetPriceDiscounted) * assetScale - return basePrice * baseAmount * assetInfo.scale / assetPriceDiscounted / baseScale; - } - - /** - * @notice Withdraws base token reserves if called by the governor - * @param to An address of the receiver of withdrawn reserves - * @param amount The amount of reserves to be withdrawn from the protocol - */ - function withdrawReserves(address to, uint amount) override external { - if (msg.sender != governor) revert Unauthorized(); - - int reserves = getReserves(); - if (reserves < 0 || amount > unsigned256(reserves)) revert InsufficientReserves(); - - doTransferOut(baseToken, to, amount); - - emit WithdrawReserves(to, amount); - } - - /** - * @notice Sets Comet's ERC20 allowance of an asset for a manager - * @dev Only callable by governor - * @dev Note: Setting the `asset` as Comet's address will allow the manager - * to withdraw from Comet's Comet balance - * @param asset The asset that the manager will gain approval of - * @param manager The account which will be allowed or disallowed - * @param amount The amount of an asset to approve - */ - function approveThis(address manager, address asset, uint amount) override external { - if (msg.sender != governor) revert Unauthorized(); - - ERC20(asset).approve(manager, amount); - } - - /** - * @notice Get the total number of tokens in circulation - * @dev Note: uses updated interest indices to calculate - * @return The supply of tokens - **/ - function totalSupply() override external view returns (uint256) { - (uint64 baseSupplyIndex_, ) = accruedInterestIndices(getNowInternal() - lastAccrualTime); - return presentValueSupply(baseSupplyIndex_, totalSupplyBase); - } - - /** - * @notice Get the total amount of debt - * @dev Note: uses updated interest indices to calculate - * @return The amount of debt - **/ - function totalBorrow() override external view returns (uint256) { - (, uint64 baseBorrowIndex_) = accruedInterestIndices(getNowInternal() - lastAccrualTime); - return presentValueBorrow(baseBorrowIndex_, totalBorrowBase); - } - - /** - * @notice Query the current positive base balance of an account or zero - * @dev Note: uses updated interest indices to calculate - * @param account The account whose balance to query - * @return The present day base balance magnitude of the account, if positive - */ - function balanceOf(address account) override public view returns (uint256) { - (uint64 baseSupplyIndex_, ) = accruedInterestIndices(getNowInternal() - lastAccrualTime); - int104 principal = userBasic[account].principal; - return principal > 0 ? presentValueSupply(baseSupplyIndex_, unsigned104(principal)) : 0; - } - - /** - * @notice Query the current negative base balance of an account or zero - * @dev Note: uses updated interest indices to calculate - * @param account The account whose balance to query - * @return The present day base balance magnitude of the account, if negative - */ - function borrowBalanceOf(address account) override public view returns (uint256) { - (, uint64 baseBorrowIndex_) = accruedInterestIndices(getNowInternal() - lastAccrualTime); - int104 principal = userBasic[account].principal; - return principal < 0 ? presentValueBorrow(baseBorrowIndex_, unsigned104(-principal)) : 0; - } - - /** - * @notice Fallback to calling the extension delegate for everything else - */ - fallback() external payable { - address delegate = extensionDelegate; - assembly { - calldatacopy(0, 0, calldatasize()) - let result := delegatecall(gas(), delegate, 0, calldatasize(), 0, 0) - returndatacopy(0, 0, returndatasize()) - switch result - case 0 { revert(0, returndatasize()) } - default { return(0, returndatasize()) } - } - } -} From 38e68d99575e5c51c2c428b63b3dfb114e20797c Mon Sep 17 00:00:00 2001 From: VladyslavBudiukWOOF Date: Mon, 8 Jun 2026 17:07:50 +0200 Subject: [PATCH 57/65] fix: revert multichain proposal simulation from develop --- deployments/relations.ts | 3 +- plugins/scenario/utils/hreForBase.ts | 22 +- scenario/constraints/ProposalConstraint.ts | 22 +- scenario/utils/index.ts | 182 ++++++-------- scenario/utils/isBridgeProposal.ts | 271 ++++++++++----------- scenario/utils/relayArbitrumMessage.ts | 203 +-------------- scenario/utils/relayBaseMessage.ts | 121 ++------- scenario/utils/relayLineaMessage.ts | 9 +- scenario/utils/relayMantleMessage.ts | 5 +- scenario/utils/relayMessage.ts | 28 +-- scenario/utils/relayOptimismMessage.ts | 180 ++------------ scenario/utils/relayScrollMessage.ts | 4 +- scenario/utils/relayUnichainMessage.ts | 25 +- tasks/deployment_manager/task.ts | 4 +- 14 files changed, 303 insertions(+), 776 deletions(-) diff --git a/deployments/relations.ts b/deployments/relations.ts index 6d1ea6384..15df618f3 100644 --- a/deployments/relations.ts +++ b/deployments/relations.ts @@ -56,14 +56,13 @@ const relationConfigMap: RelationConfigMap = { // This is a workaround for contracts that don't work in Hardhat fork // invalid opcode when calling symbol() - // Arbitrum-specific known contract mappings if (address === '0xd09acb80c1e8f2291862c4978a008791c9167003') { return 'tETH'; } if (address === '0x5a7facb970d094b6c7ff1df0ea68d99e6e73cbff') { return 'weETH'; } - if (address === '0x87eee96d50fb761ad85b1c982d28a042169d61b1') { + if (address.toLowerCase() === '0x87eee96d50fb761ad85b1c982d28a042169d61b1') { return 'wrsETH'; } // Mantle-specific known contract mapping diff --git a/plugins/scenario/utils/hreForBase.ts b/plugins/scenario/utils/hreForBase.ts index b3d7d139d..00f2c28f9 100644 --- a/plugins/scenario/utils/hreForBase.ts +++ b/plugins/scenario/utils/hreForBase.ts @@ -9,7 +9,6 @@ import { Environment } from 'hardhat/internal/core/runtime-environment'; import { ForkSpec } from '../World'; import { HttpNetworkUserConfig } from 'hardhat/types'; import { EthereumProvider } from 'hardhat/types/provider'; -import { networkConfigs } from '../../../hardhat.config'; /* mimics https://github.com/nomiclabs/hardhat/blob/master/packages/hardhat-core/src/internal/lib/hardhat-lib.ts @@ -90,12 +89,6 @@ function getBlockRollback(base: ForkSpec) { return 25; } -let activeMigration = false; - -export function migrationStarted() { - activeMigration = true; -} - export async function forkedHreForBase(base: ForkSpec): Promise { const ctx: HardhatContext = HardhatContext.getHardhatContext(); @@ -108,21 +101,16 @@ export async function forkedHreForBase(base: ForkSpec): Promise { - if (activeMigration){ - return networkConfigs.find(c => c.network === base.network)?.url; - } - return baseNetwork.url; - })(); - const provider = new ethers.providers.JsonRpcProvider(providerUrl); - if(providerUrl) + const provider = new ethers.providers.JsonRpcProvider(baseNetwork.url); + if(baseNetwork.url) console.log(`Forking from network: ${base.network} at block number: ${await provider.getBlockNumber() - (getBlockRollback(base) || 0)}`); // noNetwork otherwise - if (!base.blockNumber && providerUrl && getBlockRollback(base) !== undefined) + if (!base.blockNumber && baseNetwork.url && getBlockRollback(base) !== undefined) base.blockNumber = await provider.getBlockNumber() - getBlockRollback(base); // arbitrary number of blocks to go back if (getBlockRollback(base) === 0) { + const provider = new ethers.providers.JsonRpcProvider(baseNetwork.url); const block = await provider.getBlockNumber(); base.blockNumber = block - 1; } @@ -136,7 +124,7 @@ export async function forkedHreForBase(base: ForkSpec): Promise { @@ -78,20 +78,24 @@ export class ProposalConstraint implements StaticConstra ); } - // temporary hack to skip proposal 580 - if (proposal.id.eq(580)) { - console.log('Skipping proposal 580'); + // temporary hack to skip proposal 519 + if (proposal.id.eq(519)) { + console.log('Skipping proposal 519'); continue; } try { // Execute the proposal debug(`${label} Processing pending proposal ${proposal.id}`); - await executeOpenProposalAndRelay( - governanceDeploymentManager, - ctx.world.deploymentManager, - proposal - ); + if (isBridged) { + await executeOpenProposalAndRelay( + governanceDeploymentManager, + ctx.world.deploymentManager, + proposal + ); + } else { + await executeOpenProposal(governanceDeploymentManager, proposal); + } debug(`${label} Open proposal ${proposal.id} was executed`); } catch (err) { debug(`${label} Failed to execute proposal ${proposal.id}`, err.message); diff --git a/scenario/utils/index.ts b/scenario/utils/index.ts index c42e32f67..edbf5544f 100644 --- a/scenario/utils/index.ts +++ b/scenario/utils/index.ts @@ -12,10 +12,10 @@ import { utils, } from 'ethers'; import { execSync } from 'child_process'; -import { existsSync, unlinkSync } from 'fs'; +import { existsSync } from 'fs'; import { CometContext } from '../context/CometContext'; import CometAsset from '../context/CometAsset'; -import { ethers, exp } from '../../test/helpers'; +import { exp } from '../../test/helpers'; import { DeploymentManager } from '../../plugins/deployment_manager'; import { impersonateAddress } from '../../plugins/scenario/utils'; import { ProposalState, OpenProposal } from '../context/Gov'; @@ -917,6 +917,8 @@ export async function tenderlyExecute( }, ]; + const chainId2 = bdm.hre.ethers.provider.network.chainId; + console.log(`\n========================== TENDERLY ==========================\n`); console.log(`\nExecuting Tenderly simulation for proposal ${id}...`); @@ -926,93 +928,54 @@ export async function tenderlyExecute( const exec1 = bundle[bundle.length - 1].simulation; - console.log(` >>> PROPOSAL EXECUTED ${id}`); + console.log(` >>> PROPOSAL EXECUTED ${id} \n`); console.log(`Simulation ${exec1.id} done, status: ${exec1.status}`); - console.log(`Link: https://www.tdly.co/shared/simulation/${exec1.id} \n`); - - const bdms = [bdm]; - for (const dm of gdm.bridgedDeploymentManagers.values()) { - if (!bdms.includes(dm)) { - bdms.push(dm); - } - } + console.log(`Link: https://www.tdly.co/shared/simulation/${exec1.id}`); + let proposals; + if (chainId1 !== chainId2) { + proposals = await relayMessage(gdm, bdm, parseFloat(B0.toString()), bundle[bundle.length - 1].transaction.transaction_info.logs); + + debug(`Proposals relayed: ${proposals.length}`); + const timelockL2 = await bdm.getContractOrThrow('timelock'); + const delay = await timelockL2.delay(); + const relayMessages = loadCachedRelayMessages(); + const latestL2 = await bdm.hre.ethers.provider.getBlock('latest'); + const maxEta = Math.max(...proposals.map(p => Number(p.eta || 0))) + delay.toNumber(); + const T0L2 = BigInt(Math.max(latestL2.timestamp, maxEta + 1)); + const B0L2 = Number(latestL2.number) + 1; + const simsL2 = relayMessages.map((msg, i, arr) => { + const isLast = i === arr.length - 1; + + const timestamp = isLast + ? Number(T0L2) + : latestL2.timestamp; + + const block = isLast + ? B0L2 : latestL2.number; + + return { + network_id: chainId2.toString(), + from: msg.signer, + to: msg.messenger, + block_number: Number(block), + block_header: { + timestamp: bdm.hre.ethers.utils.hexlify(Number(timestamp)) + }, + input: msg.callData, + save: true, + save_if_fails: true, + gas_price: 0, + gas_limit: 16_777_215, + }; + }); - // make bdm contain only 1 dm per network - const uniqueBdms = new Map(); - for (const dm of bdms) { - const chainId = dm.hre.ethers.provider.network.chainId; - if (!uniqueBdms.has(chainId)) { - uniqueBdms.set(chainId, dm); - } - } - bdms.length = 0; - bdms.push(...uniqueBdms.values()); - - - for (const currentBdm of bdms) { - const chainId2 = currentBdm.hre.ethers.provider.network.chainId; - let proposals; - if (chainId1 !== chainId2) { - const relayPath = path.resolve(__dirname, '../../cache/relay.json'); - if (existsSync(relayPath)) unlinkSync(relayPath); - - proposals = await relayMessage(gdm, currentBdm, parseFloat(B0.toString()), bundle[bundle.length - 1].transaction.transaction_info.logs); - - debug(`Proposals relayed to ${currentBdm.network}: ${proposals?.length ?? 0}`); - - if (proposals && proposals.length > 0) { - const timelockL2 = await currentBdm.getContractOrThrow('timelock'); - const delay = await timelockL2.delay(); - const relayMessages = loadCachedRelayMessages(); - const executeProposalSig = ethers.utils.id('executeProposal(uint256)').substring(0, 10); - - const latestL2 = await currentBdm.hre.ethers.provider.getBlock('latest'); - const maxEta = Math.max(...proposals.map(p => Number(p.eta || 0))) + delay.toNumber(); - const T0L2 = Math.max(latestL2.timestamp, maxEta + 1); - const B0L2 = Number(latestL2.number) + 1; - - let previousBlock = latestL2.number; - let previousTimestamp = T0L2; - const simsL2 = relayMessages.map((msg) => { - let block = previousBlock; - let timestamp = previousTimestamp; - - if (msg.callData.startsWith(executeProposalSig) && !msg.eta) { - block = block + 1; - timestamp = timestamp + delay.toNumber() + 1; - } - - previousBlock = block; - previousTimestamp = timestamp; - - return { - network_id: chainId2.toString(), - from: msg.signer, - to: msg.messenger, - block_number: Number(block), - block_header: { - timestamp: currentBdm.hre.ethers.utils.hexlify(Number(timestamp)) - }, - input: msg.callData, - save: true, - save_if_fails: true, - gas_price: 0, - }; - }); - - if (simsL2.length > 0) { - const bundle2 = await simulateBundle(currentBdm, simsL2, Number(B0L2)); - - // filter from bundle every entry with simulation.input that starts with 0x0d61b519 i.e. executeProposal(uint256) - const filteredBundle = bundle2.filter(entry => entry.simulation.input.startsWith(executeProposalSig)); - for (const sim of filteredBundle) { - await shareSimulation(currentBdm, sim.simulation.id); - console.log(`\nRelayed to ${currentBdm.network}`); - console.log(`Simulation ${sim.simulation.id} done, status: ${sim.simulation.status}`); - console.log(`Link: https://www.tdly.co/shared/simulation/${sim.simulation.id} \n`); - } - } - } + if (simsL2.length > 0) { + const bundle2 = await simulateBundle(bdm, simsL2, Number(B0L2)); + console.log(` >>> PROPOSAL RELAYED ${id} \n`); + const sim = bundle2[bundle2.length - 1]; + await shareSimulation(bdm, sim.simulation.id); + console.log(`Simulation ${sim.simulation.id} done, status: ${sim.simulation.status}`); + console.log(`Link: https://www.tdly.co/shared/simulation/${sim.simulation.id}`); } } @@ -1028,9 +991,7 @@ async function simulateBundle( const results = []; for (const sim of simulations) { - const project = 'comet'; - const username = process.env.TENDERLY_USERNAME || ''; - const accessKey = process.env.TENDERLY_ACCESS_KEY || ''; + const { username, project, accessKey } = (dm.hre.config as any).tenderly; // Merge rolling state changes with simulation's own state_objects const stateObjects = sim.state_objects @@ -1088,9 +1049,7 @@ async function simulateBundle( } async function shareSimulation(dm: DeploymentManager, simulationId: string) { - const project = 'comet'; - const username = process.env.TENDERLY_USERNAME || ''; - const accessKey = process.env.TENDERLY_ACCESS_KEY || ''; + const { username, project, accessKey } = (dm.hre.config as any).tenderly; return axios.post( `https://api.tenderly.co/api/v1/account/${username}/project/${project}/simulations/${simulationId}/share`, {}, @@ -1552,26 +1511,25 @@ export async function executeOpenProposalAndRelay( await governanceDeploymentManager.hre.ethers.provider.getBlockNumber(); await executeOpenProposal(governanceDeploymentManager, openProposal); console.log(`Executed proposal ${openProposal.id} on ${governanceDeploymentManager.network}, checking if relay to ${bridgeDeploymentManager.network} is needed...`); + await mockAllRedstoneOracles(bridgeDeploymentManager); console.log(`All Redstone oracles on ${bridgeDeploymentManager.network} are mocked`); - const bridgeManagers = await isBridgeProposal( - governanceDeploymentManager, - bridgeDeploymentManager, - openProposal - ); - for (const bridgeManager of bridgeManagers) { - await mockAllRedstoneOracles(bridgeManager); - if (bridgeManager) { - await relayMessage( - governanceDeploymentManager, - bridgeManager, - startingBlockNumber - ); - } else { - console.log( - `[${governanceDeploymentManager.network} -> ${bridgeManager.network}] Proposal ${openProposal.id} doesn't target bridge; not relaying` - ); - return; - } + if ( + await isBridgeProposal( + governanceDeploymentManager, + bridgeDeploymentManager, + openProposal + ) + ) { + await relayMessage( + governanceDeploymentManager, + bridgeDeploymentManager, + startingBlockNumber + ); + } else { + console.log( + `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Proposal ${openProposal.id} doesn't target bridge; not relaying` + ); + return; } } diff --git a/scenario/utils/isBridgeProposal.ts b/scenario/utils/isBridgeProposal.ts index 63957eccf..f2d4ac362 100644 --- a/scenario/utils/isBridgeProposal.ts +++ b/scenario/utils/isBridgeProposal.ts @@ -1,155 +1,142 @@ import { DeploymentManager } from '../../plugins/deployment_manager'; -import { getRoots } from '../../plugins/deployment_manager/Roots'; import { OpenProposal } from '../context/Gov'; -import { utils } from 'ethers'; -import { forkedHreForBase } from '../../plugins/scenario/utils/hreForBase'; - -const EXCLUDED_ROOTS = ['comptrollerV2', 'comet', 'configurator', 'rewards', 'bulker', 'cometFactory']; - -const CCTP_DOMAIN_TO_NETWORK: Record = { - 0: 'mainnet', - 1: 'avalanche', - 2: 'optimism', - 3: 'arbitrum', - 6: 'base', - 7: 'polygon', -}; - -const ROOT_TO_NETWORK: Record = { - fxRoot: 'polygon', - arbitrumInbox: 'arbitrum', - arbitrumL1GatewayRouter: 'arbitrum', - baseL1CrossDomainMessenger: 'base', - baseL1StandardBridge: 'base', - baseL1USDSBridge: 'base', - opL1CrossDomainMessenger: 'optimism', - opL1StandardBridge: 'optimism', - mantleL1CrossDomainMessenger: 'mantle', - mantleL1StandardBridge: 'mantle', - unichainL1CrossDomainMessenger: 'unichain', - unichainL1StandardBridge: 'unichain', - scrollMessenger: 'scroll', - scrollL1USDCGateway: 'scroll', - lineaMessageService: 'linea', - lineaL1TokenBridge: 'linea', - lineaL1USDCBridge: 'linea', - l1CCIPRouter: 'ronin', - l1TokenAdminRegistry: 'ronin', - roninl1CCIPOnRamp: 'ronin', - roninl1NativeBridge: 'ronin', -}; - -function parseCCTPNetworks(openProposal: OpenProposal, cctpAddress: string): string[] { - const networks: string[] = []; - const cctpLower = cctpAddress.toLowerCase(); - - for (let i = 0; i < openProposal.targets.length; i++) { - if (openProposal.targets[i].toLowerCase() !== cctpLower) continue; - const sig = openProposal.signatures[i]; - if (!sig.startsWith('depositForBurn(')) continue; - - const calldata = openProposal.calldatas[i]; - // destinationDomain is the second parameter (uint32) in all depositForBurn variants - const decoded = utils.defaultAbiCoder.decode(['uint256', 'uint32'], utils.hexDataSlice(calldata, 0, 64)); - const domain = decoded[1]; - const network = CCTP_DOMAIN_TO_NETWORK[domain]; - if (network) networks.push(network); - } - return networks; -} - -export async function getProposalBridgeNetworks( - governanceDeploymentManager: DeploymentManager, - openProposal: OpenProposal -): Promise { - const roots = await getRoots(governanceDeploymentManager.cache); - const targets = openProposal.targets.map(t => t.toLowerCase()); - - const networks = new Set(); - for (const [alias, address] of roots) { - if (EXCLUDED_ROOTS.includes(alias)) continue; - - if (alias === 'CCTPTokenMessenger' && targets.includes(address.toLowerCase())) { - for (const net of parseCCTPNetworks(openProposal, address)) { - networks.add(net); - } - continue; - } - - const network = ROOT_TO_NETWORK[alias]; - if (network && targets.includes(address.toLowerCase())) { - networks.add(network); - } - } - return [...new Set(networks)]; -} - -const existingBridgeManagers: Record = {}; export async function isBridgeProposal( governanceDeploymentManager: DeploymentManager, bridgeDeploymentManager: DeploymentManager, openProposal: OpenProposal ) { - const bridgeNetworks = await getProposalBridgeNetworks(governanceDeploymentManager, openProposal); - const otherBridgeNetworks = bridgeNetworks.filter(n => n !== bridgeDeploymentManager.network); - const bridgeManagers = [bridgeDeploymentManager]; - if (!existingBridgeManagers[bridgeDeploymentManager.network]) { - existingBridgeManagers[bridgeDeploymentManager.network] = bridgeDeploymentManager; - } - if (!existingBridgeManagers[governanceDeploymentManager.network]) { - existingBridgeManagers[governanceDeploymentManager.network] = governanceDeploymentManager; - } - for(const bridgeNetwork of otherBridgeNetworks) { - if (existingBridgeManagers[bridgeNetwork]) { - bridgeManagers.push(existingBridgeManagers[bridgeNetwork]); - continue; + const bridgeNetwork = bridgeDeploymentManager.network; + console.log(`Checking if proposal ${openProposal.id} is a bridge proposal on ${bridgeNetwork}`); + switch (bridgeNetwork) { + case 'arbitrum': { + const inbox = await governanceDeploymentManager.getContractOrThrow('arbitrumInbox'); + const l1GatewayRouter = await governanceDeploymentManager.getContractOrThrow( + 'arbitrumL1GatewayRouter' + ); + const targets = openProposal.targets; + return targets.includes(inbox.address) || targets.includes(l1GatewayRouter.address); } - - let deploymentToken: string; - - let dm: DeploymentManager; - let existingBridgedDm: DeploymentManager | undefined; - for (const cachedDm of governanceDeploymentManager.bridgedDeploymentManagers.values()) { - if (cachedDm.network === bridgeNetwork) { - existingBridgedDm = cachedDm; - break; - } + case 'polygon': { + const { + fxRoot, + RootChainManager + } = await governanceDeploymentManager.getContracts(); + const bridgeAddresses = [fxRoot, RootChainManager] + .filter(x => x) + .map(x => x.address.toLowerCase()); + const targets = openProposal.targets; + return targets.some(t => bridgeAddresses.includes(t.toLowerCase())); } - - if (existingBridgedDm) { - dm = existingBridgedDm; - } else { - // default deployment token is USDC for all networks except Ronin (WETH) and Mantle (USDE) - switch (bridgeNetwork) { - case 'arbitrum': - case 'polygon': - case 'base': - case 'linea': - case 'optimism': - case 'unichain': - case 'scroll': - deploymentToken = 'usdc'; - break; - case 'mantle': - deploymentToken = 'usde'; - break; - case 'ronin': - deploymentToken = 'weth'; - break; - default: { - const tag = `[${governanceDeploymentManager.network} -> ${bridgeNetwork}]`; - throw new Error(`${tag} Unable to determine whether to relay Proposal ${openProposal.id}`); - } - } - - const hre = await forkedHreForBase({ name: '', network: bridgeNetwork, deployment: '' }); - dm = await governanceDeploymentManager.addBridgedDeploymentManager(bridgeNetwork, deploymentToken, hre); + case 'base': { + const baseL1CrossDomainMessenger = await governanceDeploymentManager.getContractOrThrow( + 'baseL1CrossDomainMessenger' + ); + const baseL1StandardBridge = await governanceDeploymentManager.getContractOrThrow( + 'baseL1StandardBridge' + ); + const baseL1USDSBridge = await governanceDeploymentManager.getContractOrThrow( + 'baseL1USDSBridge' + ); + const targets = openProposal.targets; + const bridgeContracts = [baseL1CrossDomainMessenger.address, baseL1StandardBridge.address, baseL1USDSBridge.address]; + + return targets.some(t => bridgeContracts.includes(t)); + } + case 'linea': { + const lineaMessageService = await governanceDeploymentManager.getContractOrThrow( + 'lineaMessageService' + ); + const lineaL1USDCBridge = await governanceDeploymentManager.getContractOrThrow( + 'lineaL1USDCBridge' + ); + const lineaL1TokenBridge = await governanceDeploymentManager.getContractOrThrow( + 'lineaL1TokenBridge' + ); + const bridgeContracts = [ + lineaMessageService.address, + lineaL1USDCBridge.address, + lineaL1TokenBridge.address + ]; + const targets = openProposal.targets; + return targets.some(t => bridgeContracts.includes(t)); + } + // case 'linea': { + // const governor = await governanceDeploymentManager.getContractOrThrow('governor'); + // const lineaMessageService = await governanceDeploymentManager.getContractOrThrow( + // 'lineaMessageService' + // ); + // const { targets } = await governor.getActions(openProposal.id); + // return targets.includes(lineaMessageService.address); + // } + case 'optimism': { + const opL1CrossDomainMessenger = await governanceDeploymentManager.getContractOrThrow( + 'opL1CrossDomainMessenger' + ); + const opL1StandardBridge = await governanceDeploymentManager.getContractOrThrow( + 'opL1StandardBridge' + ); + const targets = openProposal.targets; + const bridgeContracts = [opL1CrossDomainMessenger.address, opL1StandardBridge.address]; + return targets.some(t => bridgeContracts.includes(t)); + } + case 'mantle': { + const mantleL1CrossDomainMessenger = await governanceDeploymentManager.getContractOrThrow( + 'mantleL1CrossDomainMessenger' + ); + const mantleL1StandardBridge = await governanceDeploymentManager.getContractOrThrow( + 'mantleL1StandardBridge' + ); + const targets = openProposal.targets; + const bridgeContracts = [ + mantleL1CrossDomainMessenger.address, + mantleL1StandardBridge.address + ]; + return targets.some(t => bridgeContracts.includes(t)); + } + case 'unichain': { + const unichainL1CrossDomainMessenger = await governanceDeploymentManager.getContractOrThrow( + 'unichainL1CrossDomainMessenger' + ); + const unichainL1StandardBridge = await governanceDeploymentManager.getContractOrThrow( + 'unichainL1StandardBridge' + ); + const targets = openProposal.targets; + const bridgeContracts = [ + unichainL1CrossDomainMessenger.address, + unichainL1StandardBridge.address + ]; + return targets.some(t => bridgeContracts.includes(t)); + } + case 'scroll': { + const scrollMessenger = await governanceDeploymentManager.getContractOrThrow( + 'scrollMessenger' + ); + const targets = openProposal.targets; + return targets.includes(scrollMessenger.address); + } + case 'ronin': { + const governor = await governanceDeploymentManager.getContractOrThrow('governor'); + const l1CCIPRouter = await governanceDeploymentManager.getContractOrThrow( + 'l1CCIPRouter' + ); + const roninl1NativeBridge = await governanceDeploymentManager.getContractOrThrow( + 'roninl1NativeBridge' + ); + const roninL1OnRamp = await governanceDeploymentManager.getContractOrThrow( + 'roninl1CCIPOnRamp' + ); + const { targets } = await governor.proposalDetails(openProposal.id); + const bridgeContracts = [ + roninl1NativeBridge.address, + l1CCIPRouter.address, + roninL1OnRamp.address + ]; + return targets.some(t => bridgeContracts.includes(t)); + } + default: { + const tag = `[${bridgeNetwork} -> ${governanceDeploymentManager.network}]`; + throw new Error(`${tag} Unable to determine whether to relay Proposal ${openProposal.id}`); } - - existingBridgeManagers[bridgeNetwork] = dm; - bridgeManagers.push(dm); } - return bridgeManagers; } - diff --git a/scenario/utils/relayArbitrumMessage.ts b/scenario/utils/relayArbitrumMessage.ts index 3c19598a7..550979448 100644 --- a/scenario/utils/relayArbitrumMessage.ts +++ b/scenario/utils/relayArbitrumMessage.ts @@ -1,7 +1,7 @@ import { DeploymentManager } from '../../plugins/deployment_manager'; import { impersonateAddress } from '../../plugins/scenario/utils'; import { setNextBaseFeeToZero, setNextBlockTimestamp } from './hreUtils'; -import { utils, BigNumber, Contract, constants } from 'ethers'; +import { utils, BigNumber } from 'ethers'; import { Log } from '@ethersproject/abstract-provider'; import { sourceTokens } from '../../plugins/scenario/utils/TokenSourcer'; import { OpenBridgedProposal } from '../context/Gov'; @@ -84,18 +84,18 @@ export async function relayArbitrumMessage( const header = '0x'; const headerLength = header.length; const wordLength = 2 * 32; - const innerData = header + data.slice(headerLength + (11 * wordLength)); + const innnerData = header + data.slice(headerLength + (11 * wordLength)); const toValue = data.slice(headerLength + (2 * wordLength), headerLength + (3 * wordLength)); let toAddress = BigNumber.from(`0x${toValue}`).toHexString(); - // if length of toAddress is less than 42, then it is padded with 0s and we need to add them after 0x + // if lenght of toAddress is less than 42, then it is padded with 0s and we need to add them after 0x if(toAddress.length < 42) { toAddress = `0x${toAddress.slice(2).padStart(40, '0')}`; } const messageNum = topics[1]; return { - data: innerData, + data: innnerData, toAddress, messageNum }; @@ -232,18 +232,6 @@ export async function relayArbitrumMessage( await signer.getAddress() ); } else { - // Mock ArbSys precompile (0x64) — Arbitrum precompiles don't exist in Hardhat's EVM, - // but the L2 gateways call ArbSys.sendTxToL1 internally during outboundTransfer. - // Bytecode 0x60206000f3 disassembles to: PUSH1 0x20 | PUSH1 0x00 | RETURN - // which returns 32 zero bytes from uninitialized memory for any call. - await bridgeDeploymentManager.hre.network.provider.request({ - method: 'hardhat_setCode', - params: [ - '0x0000000000000000000000000000000000000064', - '0x60206000f3', - ], - }); - await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); } openBridgedProposals.push({ @@ -256,189 +244,6 @@ export async function relayArbitrumMessage( return openBridgedProposals; } -export async function simulateL2ToL1TokenBridging( - governanceDeploymentManager: DeploymentManager, - bridgeDeploymentManager: DeploymentManager, - tenderlyLogs?: any[], - proposalId?: BigNumber -) { - if(tenderlyLogs) { - return; - } - console.log('Simulating L2→L1 token bridging for any executed Arbitrum proposals...'); - - // L2 contracts - const bridgeReceiver = await bridgeDeploymentManager.getContractOrThrow('bridgeReceiver'); - - // Parse recent ProposalCreated events to find actions that bridge tokens from L2 to L1 - // ProposalCreated(address indexed rootMessageSender, uint256 id, address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, uint256 eta) - console.log('Fetching recent ProposalCreated events from BridgeReceiver...'); - const latestBlockNumber = await bridgeDeploymentManager.hre.ethers.provider.getBlockNumber(); - const proposalCreatedEvents = await bridgeDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: latestBlockNumber - 1000, // look back 1000 blocks for ProposalCreated events, which should be sufficient to cover any recent proposals given typical block times on Arbitrum - toBlock: 'latest', - address: bridgeReceiver.address, - topics: [utils.id('ProposalCreated(address,uint256,address[],uint256[],string[],bytes[],uint256)')] - }); - const outboundTransferSignature = 'outboundTransfer(address,address,uint256,bytes)'; - const outboundTransfer2Signature = 'outboundTransfer(address,address,uint256,uint256,uint256,bytes)'; - const depositForBurnSignature = 'depositForBurn(uint256,uint32,bytes32,address,bytes32,uint256,uint32)'; - const ARBITRUM_GATEWAY_ROUTER = '0x5288c571Fd7aD117beA99bF60FE0846C4E84F933'; - const ARBITRUM_BRIDGE = '0x8315177ab297ba92a06054ce80a67ed4dbd7ed3a'; - const ARBITRUM_OUTBOX = '0x667e23ABd27E623c11d4CC00ca3EC4d0bD63337a'; - const MAINNET_WETH = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'; - - for (const event of proposalCreatedEvents) { - const decodedEvent = bridgeReceiver.interface.parseLog(event); - const { id, targets, signatures, calldatas } = decodedEvent.args; - - if (proposalId && id.toString() !== proposalId.toString()) { - continue; - } - - for (let i = 0; i < signatures.length; i++) { - // Look for L2→L1 outboundTransfer calls (standard Arbitrum gateway bridge) - if (signatures[i] === outboundTransferSignature || signatures[i] === outboundTransfer2Signature) { - const [l1Token, to, amount] = (() => { - if (signatures[i] === outboundTransferSignature) { - return utils.defaultAbiCoder.decode( - ['address', 'address', 'uint256', 'bytes'], - calldatas[i] - ); - } else if (signatures[i] === outboundTransfer2Signature) { - return utils.defaultAbiCoder.decode( - ['address', 'address', 'uint256', 'uint256', 'uint256', 'bytes'], - calldatas[i] - ); - } - })(); - console.log(`Simulating L2→L1 token bridging: ${amount.toString()} of ${l1Token} to ${to}`); - - const gatewayAddress = await (async () => { - if(targets[i].toLowerCase() === ARBITRUM_GATEWAY_ROUTER.toLowerCase()) { // Arbitrum WETH gateway - const router = new Contract( - ARBITRUM_GATEWAY_ROUTER, - ['function l1TokenToGateway(address l1Token) view returns (address)'], - await governanceDeploymentManager.getSigner() - ); - return await router.l1TokenToGateway(l1Token); - } - return targets[i]; - })(); - const l2Gateway = new Contract( - gatewayAddress, - ['function counterpartGateway() view returns (address)'], - await bridgeDeploymentManager.getSigner() - ); - const l1GatewayAddress = await l2Gateway.counterpartGateway(); - - const l1Gateway = new Contract( - l1GatewayAddress, - [ - 'function finalizeInboundTransfer(address _token, address _from, address _to, uint256 _amount, bytes calldata _data)', - 'function inbox() view returns (address)' - ], - await governanceDeploymentManager.getSigner() - ); - // override 0x4 slot in outbox to L2 gateway - await governanceDeploymentManager.hre.network.provider.send('hardhat_setStorageAt', [ - ARBITRUM_OUTBOX, - '0x4', - utils.hexZeroPad(gatewayAddress, 32) - ]); - - // impersonate outbox to call finalizeInboundTransfer, as if the message came from L2 gateway - const outboxSigner = await impersonateAddress( - governanceDeploymentManager, - ARBITRUM_OUTBOX - ); - - await governanceDeploymentManager.hre.network.provider.send('hardhat_setBalance', [ - outboxSigner.address, - '0x1000000000000000000', - ]); - - const arbitrumBridge = new Contract( - ARBITRUM_BRIDGE, - ['function executeCall(address to, uint256 value, bytes calldata data)'], - outboxSigner - ); - - const data = l1Gateway.interface.encodeFunctionData( - 'finalizeInboundTransfer', - [ - l1Token, - ARBITRUM_GATEWAY_ROUTER, - to, amount, - utils.defaultAbiCoder.encode(['uint256', 'bytes'], [0, '0x']) - ]); - console.log(`Relaying message to L1 gateway at ${l1GatewayAddress} with data: ${data}`); - const bridgeTx = await arbitrumBridge.connect(outboxSigner).executeCall( - l1Gateway.address, - l1Token.toLowerCase() === MAINNET_WETH.toLowerCase() ? amount : 0, - data, - ); - await (bridgeTx).wait(); - // stop impersonation after the call - await governanceDeploymentManager.hre.network.provider.send('hardhat_stopImpersonatingAccount', [ - outboxSigner.address - ]); - // override 0x4 slot in outbox to L2 gateway - await governanceDeploymentManager.hre.network.provider.send('hardhat_setStorageAt', [ - ARBITRUM_OUTBOX, - '0x4', - utils.hexZeroPad(constants.AddressZero, 32) - ]); - } - - // Look for L2→L1 CCTP depositForBurn calls (Circle CCTP bridge, e.g. native USDC) - if (signatures[i] === depositForBurnSignature) { - const [amount, , mintRecipientBytes32, burnToken] = utils.defaultAbiCoder.decode( - ['uint256', 'uint32', 'bytes32', 'address', 'bytes32', 'uint256', 'uint32'], - calldatas[i] - ); - - const mintRecipient = utils.getAddress('0x' + utils.hexlify(mintRecipientBytes32).slice(-40)); - - try { - // L2 - const l2CCTPTokenMessenger = await bridgeDeploymentManager.getContractOrThrow('CCTPMessageTransmitter'); - // Resolve L1 token via CCTP TokenMinter: burnToken (L2) → localToken (L1) - const l1CCTPTokenMessenger = await governanceDeploymentManager.getContractOrThrow('CCTPTokenMessenger'); - const tokenMinterAddress = await l1CCTPTokenMessenger.localMinter(); - const L1TokenMinter = new Contract( - tokenMinterAddress, - ['function mint(uint32 sourceDomain, bytes32 burnToken, address recipientOne, address recipientTwo, uint256 amountOne, uint256 amountTwo) returns (address)'], - await governanceDeploymentManager.getSigner() - ); - const l1CCTPTokenMessengerSigner = await impersonateAddress( - governanceDeploymentManager, - l1CCTPTokenMessenger.address - ); - await governanceDeploymentManager.hre.network.provider.send('hardhat_setBalance', [ - l1CCTPTokenMessengerSigner.address, - '0x1000000000000000000', - ]); - const sourceDomain = await l2CCTPTokenMessenger.localDomain(); - const mintTx = await L1TokenMinter.connect(l1CCTPTokenMessengerSigner).mint( - sourceDomain, - utils.hexZeroPad(burnToken, 32), - mintRecipient, - L1TokenMinter.address, // mint to the token minter first, since some tokens (e.g. USDC) have a cap on max amount per mint, and the token minter can then transfer to the recipient - amount, - 1 - ); - console.log('Simulated CCTP mint transaction:', mintTx.hash); - await mintTx.wait(); - } catch (e) { - console.log(`Warning: Could not simulate CCTP L2→L1 bridging for depositForBurn: ${e.message}`); - } - } - await governanceDeploymentManager.hre.network.provider.send('evm_mine'); - } - } -} - export async function relayArbitrumCCTPMint( governanceDeploymentManager: DeploymentManager, bridgeDeploymentManager: DeploymentManager, diff --git a/scenario/utils/relayBaseMessage.ts b/scenario/utils/relayBaseMessage.ts index bb3a3cac4..e357eceb4 100644 --- a/scenario/utils/relayBaseMessage.ts +++ b/scenario/utils/relayBaseMessage.ts @@ -1,7 +1,7 @@ import { DeploymentManager } from '../../plugins/deployment_manager'; import { impersonateAddress } from '../../plugins/scenario/utils'; import { setNextBaseFeeToZero, setNextBlockTimestamp } from './hreUtils'; -import { BigNumber, ethers, utils } from 'ethers'; +import { BigNumber, ethers } from 'ethers'; import { Log } from '@ethersproject/abstract-provider'; import { OpenBridgedProposal } from '../context/Gov'; import { applyL1ToL2Alias, isTenderlyLog } from './index'; @@ -142,7 +142,7 @@ export default async function relayBaseMessage( } } else if (target === bridgeReceiver.address) { // Cross-chain message passing - if (relayMessageTxn) { + if (!tenderlyLogs && relayMessageTxn) { const proposalCreatedEvent = relayMessageTxn.events.find( (event) => event.address === bridgeReceiver.address ); @@ -154,9 +154,28 @@ export default async function relayBaseMessage( openBridgedProposals.push({ id, eta }); } } else { - // throw error only on last relay message and no proposal created event found - if(sentMessageEvents.indexOf(sentMessageEvent) === sentMessageEvents.length - 1 && openBridgedProposals.length === 0) - throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); + throw new Error( + `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message` + ); + } + } + + // Handle proposal creation for tenderly + if (tenderlyLogs) { + // We need to check for ProposalCreated events since we don't get them in the loop above + const proposalFilter = bridgeReceiver.filters.ProposalCreated(); + const proposalEvents = await bridgeDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: 'latest', + toBlock: 'latest', + address: bridgeReceiver.address, + topics: proposalFilter.topics + }); + + for (let event of proposalEvents) { + const { + args: { id, eta }, + } = bridgeReceiver.interface.parseLog(event); + openBridgedProposals.push({ id, eta }); } } @@ -188,94 +207,4 @@ export default async function relayBaseMessage( } return openBridgedProposals; -} - -export async function simulateL2ToL1TokenBridging( - governanceDeploymentManager: DeploymentManager, - bridgeDeploymentManager: DeploymentManager, - tenderlyLogs?: any[] -) { - if(tenderlyLogs) { - return; - } - console.log('Simulating L2→L1 token bridging for any executed Base proposals...'); - - // L2 contracts - const bridgeReceiver = await bridgeDeploymentManager.getContractOrThrow('bridgeReceiver'); - const baseL2Bridge = await bridgeDeploymentManager.getContractOrThrow('l2StandardBridge'); - const l2CrossDomainMessenger = await bridgeDeploymentManager.getContractOrThrow('l2CrossDomainMessenger'); - - // L1 contracts - const baseL1CrossDomainMessenger = await governanceDeploymentManager.getContractOrThrow('baseL1CrossDomainMessenger'); - const baseL1Bridge = await governanceDeploymentManager.getContractOrThrow('baseL1StandardBridge'); - const BASE_L1_PORTAL = '0x49048044D57e1C92A77f79988d21Fa8fAF74E97e'; - - // Parse recent ProposalCreated events to find actions that bridge tokens from L2 to L1 - // ProposalCreated(address indexed rootMessageSender, uint256 id, address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, uint256 eta) - console.log('Fetching recent ProposalCreated events from BridgeReceiver...'); - const latestBlockNumber = await bridgeDeploymentManager.hre.ethers.provider.getBlockNumber(); - const proposalCreatedEvents = await bridgeDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: latestBlockNumber - 1000, // look back 1000 blocks for ProposalCreated events, which should be sufficient to cover any recent proposals given typical block times on Base - toBlock: 'latest', - address: bridgeReceiver.address, - topics: [utils.id('ProposalCreated(address,uint256,address[],uint256[],string[],bytes[],uint256)')] - }); - - const bridgeERC20ToSignature = 'bridgeERC20To(address,address,address,uint256,uint32,bytes)'; - - for (const event of proposalCreatedEvents) { - const decodedEvent = bridgeReceiver.interface.parseLog(event); - const { signatures, calldatas } = decodedEvent.args; - - - for (let i = 0; i < signatures.length; i++) { - if (signatures[i] === bridgeERC20ToSignature) { - const [localToken, remoteToken, to, amount, , extraData] = utils.defaultAbiCoder.decode( - ['address', 'address', 'address', 'uint256', 'uint32', 'bytes'], - calldatas[i] - ); - - console.log(`Simulating L2→L1 bridgeERC20To: ${amount.toString()} of ${remoteToken} to ${to}`); - - console.log('Setting up L1 state to simulate finalizeBridgeERC20...'); - console.log('Base L1 Portal address:', BASE_L1_PORTAL); - console.log('Overriding slot', utils.hexZeroPad('0x32', 32)); - console.log('l2CrossDomainMessenger:', utils.hexZeroPad(l2CrossDomainMessenger.address, 32)); - await governanceDeploymentManager.hre.network.provider.send('hardhat_setStorageAt', [ - BASE_L1_PORTAL, - utils.hexZeroPad('0x32', 32), - utils.hexZeroPad(l2CrossDomainMessenger.address, 32) - ]); - - await governanceDeploymentManager.hre.network.provider.send('hardhat_setStorageAt', [ - baseL1CrossDomainMessenger.address, - '0xcc', - utils.hexZeroPad(baseL2Bridge.address, 32) - ]); - - const domainMessengerSigner = await impersonateAddress( - governanceDeploymentManager, - baseL1CrossDomainMessenger.address - ); - - await governanceDeploymentManager.hre.network.provider.send('hardhat_setBalance', [ - domainMessengerSigner.address, - ethers.utils.hexStripZeros(ethers.utils.parseEther('1').toHexString()), - ]); - - await ( - await baseL1Bridge.connect(domainMessengerSigner).finalizeBridgeERC20( - remoteToken, localToken, bridgeReceiver.address, to, amount, extraData, - { gasPrice: 0, gasLimit: 2_500_000 } - ) - ).wait(); - - await governanceDeploymentManager.hre.network.provider.send('hardhat_setStorageAt', [ - BASE_L1_PORTAL, - utils.hexZeroPad('0x32', 32), - utils.hexZeroPad('0xdead', 32) - ]); - } - } - } -} +} \ No newline at end of file diff --git a/scenario/utils/relayLineaMessage.ts b/scenario/utils/relayLineaMessage.ts index 0f3986550..78f2b0f14 100644 --- a/scenario/utils/relayLineaMessage.ts +++ b/scenario/utils/relayLineaMessage.ts @@ -6,7 +6,7 @@ import { OpenBridgedProposal } from '../context/Gov'; import { impersonateAddress } from '../../plugins/scenario/utils'; import { isTenderlyLog } from './index'; -const LINEA_SETTER_ROLE_ACCOUNT = '0x2b0F9C76970975aec03784EFd763623757EF7652'; +const LINEA_SETTER_ROLE_ACCOUNT = '0xc1C6B09D1eB6fCA0fF3cA11027E5Bc4AeDb47F67'; export default async function relayLineaMessage( governanceDeploymentManager: DeploymentManager, @@ -245,9 +245,9 @@ export default async function relayLineaMessage( // Add the proposal to the list of open bridged proposals to be executed after all the messages have been relayed openBridgedProposals.push({ id, eta }); } else { - // throw error only on last relay message and no proposal created event found - if(messageSentEvents.indexOf(messageSentEvent) === messageSentEvents.length - 1 && openBridgedProposals.length === 0) - throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); + throw new Error( + `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message` + ); } } @@ -276,7 +276,6 @@ export default async function relayLineaMessage( `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Executed bridged proposal ${id}` ); } - return openBridgedProposals; } diff --git a/scenario/utils/relayMantleMessage.ts b/scenario/utils/relayMantleMessage.ts index c052e0184..812255b75 100644 --- a/scenario/utils/relayMantleMessage.ts +++ b/scenario/utils/relayMantleMessage.ts @@ -127,9 +127,7 @@ export default async function relayMantleMessage( // Add the proposal to the list of open bridged proposals to be executed after all the messages have been relayed openBridgedProposals.push({ id, eta }); } else { - // throw error only on last relay message and no proposal created event found - if(sentMessageEvents.indexOf(sentMessageEvent) === sentMessageEvents.length - 1 && openBridgedProposals.length === 0) - throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); + throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); } } @@ -160,6 +158,5 @@ export default async function relayMantleMessage( `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Executed bridged proposal ${id}` ); } - return openBridgedProposals; } diff --git a/scenario/utils/relayMessage.ts b/scenario/utils/relayMessage.ts index ac94cb1ae..fa0523665 100644 --- a/scenario/utils/relayMessage.ts +++ b/scenario/utils/relayMessage.ts @@ -1,9 +1,9 @@ import { DeploymentManager } from '../../plugins/deployment_manager'; import relayPolygonMessage from './relayPolygonMessage'; -import { relayArbitrumMessage, relayArbitrumCCTPMint, simulateL2ToL1TokenBridging } from './relayArbitrumMessage'; -import relayBaseMessage,{ simulateL2ToL1TokenBridging as simulateBaseL2ToL1TokenBridging} from './relayBaseMessage'; +import { relayArbitrumMessage, relayArbitrumCCTPMint } from './relayArbitrumMessage'; +import relayBaseMessage from './relayBaseMessage'; import relayLineaMessage from './relayLineaMessage'; -import relayOptimismMessage, { simulateL2ToL1TokenBridging as simulateOptimismL2ToL1TokenBridging } from './relayOptimismMessage'; +import relayOptimismMessage from './relayOptimismMessage'; import relayMantleMessage from './relayMantleMessage'; import { relayUnichainMessage, relayUnichainCCTPMint } from './relayUnichainMessage'; import relayScrollMessage from './relayScrollMessage'; @@ -16,36 +16,23 @@ export default async function relayMessage( tenderlyLogs?: any[] ) { const bridgeNetwork = bridgeDeploymentManager.network; - if(bridgeNetwork === governanceDeploymentManager.network) return; // no need to relay if the proposal is on the same network console.log(`Relaying messages from ${governanceDeploymentManager.network} -> ${bridgeNetwork}`); let proposal; switch (bridgeNetwork) { case 'base': - proposal = await relayBaseMessage( + return await relayBaseMessage( governanceDeploymentManager, bridgeDeploymentManager, startingBlockNumber, tenderlyLogs ); - await simulateBaseL2ToL1TokenBridging( - governanceDeploymentManager, - bridgeDeploymentManager, - tenderlyLogs - ); - return proposal; case 'optimism': - proposal = await relayOptimismMessage( + return await relayOptimismMessage( governanceDeploymentManager, bridgeDeploymentManager, startingBlockNumber, tenderlyLogs ); - await simulateOptimismL2ToL1TokenBridging( - governanceDeploymentManager, - bridgeDeploymentManager, - tenderlyLogs - ); - return proposal; case 'mantle': return await relayMantleMessage( governanceDeploymentManager, @@ -87,11 +74,6 @@ export default async function relayMessage( startingBlockNumber, tenderlyLogs ); - await simulateL2ToL1TokenBridging( - governanceDeploymentManager, - bridgeDeploymentManager, - tenderlyLogs - ); return proposal; case 'linea': return await relayLineaMessage( diff --git a/scenario/utils/relayOptimismMessage.ts b/scenario/utils/relayOptimismMessage.ts index 695ed040a..5ce1d076d 100644 --- a/scenario/utils/relayOptimismMessage.ts +++ b/scenario/utils/relayOptimismMessage.ts @@ -1,7 +1,7 @@ import { DeploymentManager } from '../../plugins/deployment_manager'; import { impersonateAddress } from '../../plugins/scenario/utils'; import { setNextBaseFeeToZero, setNextBlockTimestamp } from './hreUtils'; -import { BigNumber, ethers, utils, Contract } from 'ethers'; +import { BigNumber, ethers } from 'ethers'; import { Log } from '@ethersproject/abstract-provider'; import { OpenBridgedProposal } from '../context/Gov'; import { applyL1ToL2Alias, isTenderlyLog } from './index'; @@ -144,169 +144,35 @@ export default async function relayOptimismMessage( throw e; } } else { - // throw error only on last relay message and no proposal created event found - if(sentMessageEvents.indexOf(sentMessageEvent) === sentMessageEvents.length - 1 && openBridgedProposals.length === 0) - throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); + throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); } - } - - // Execute open bridged proposals now that all messages have been bridged - for (let proposal of openBridgedProposals) { - const { eta, id } = proposal; - // Fast forward l2 time - await setNextBlockTimestamp(bridgeDeploymentManager, eta.toNumber() + 1); - // Execute queued proposal - await setNextBaseFeeToZero(bridgeDeploymentManager); + // Execute open bridged proposals now that all messages have been bridged + for (let proposal of openBridgedProposals) { + const { eta, id } = proposal; + // Fast forward l2 time + await setNextBlockTimestamp(bridgeDeploymentManager, eta.toNumber() + 1); - if (tenderlyLogs) { - const callData = bridgeReceiver.interface.encodeFunctionData('executeProposal', [id]); - const signer = await bridgeDeploymentManager.getSigner(); + // Execute queued proposal + await setNextBaseFeeToZero(bridgeDeploymentManager); - bridgeDeploymentManager.stashRelayMessage( - bridgeReceiver.address, - callData, - signer.address - ); - } else { - await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); - } - console.log( - `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Executed bridged proposal ${id}` - ); - } + if (tenderlyLogs) { + const callData = bridgeReceiver.interface.encodeFunctionData('executeProposal', [id]); + const signer = await bridgeDeploymentManager.getSigner(); - return openBridgedProposals; -} - -export async function simulateL2ToL1TokenBridging( - governanceDeploymentManager: DeploymentManager, - bridgeDeploymentManager: DeploymentManager, - tenderlyLogs?: any[] -) { - if(tenderlyLogs) { - return; - } - console.log('Simulating L2→L1 token bridging for any executed Optimism proposals...'); - - // L2 contracts - const bridgeReceiver = await bridgeDeploymentManager.getContractOrThrow('bridgeReceiver'); - const optimismL2Bridge = await bridgeDeploymentManager.getContractOrThrow('l2StandardBridge'); - const l2CrossDomainMessenger = await bridgeDeploymentManager.getContractOrThrow('l2CrossDomainMessenger'); - - // L1 contracts - const opL1CrossDomainMessenger = await governanceDeploymentManager.getContractOrThrow('opL1CrossDomainMessenger'); - const optimismL1Bridge = await governanceDeploymentManager.getContractOrThrow('opL1StandardBridge'); - const OPTIMISM_L1_PORTAL = '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed'; - - // Parse recent ProposalCreated events to find actions that bridge tokens from L2 to L1 - // ProposalCreated(address indexed rootMessageSender, uint256 id, address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, uint256 eta) - console.log('Fetching recent ProposalCreated events from BridgeReceiver...'); - const latestBlockNumber = await bridgeDeploymentManager.hre.ethers.provider.getBlockNumber(); - const proposalCreatedEvents = await bridgeDeploymentManager.hre.ethers.provider.getLogs({ - fromBlock: latestBlockNumber - 1000, // look back 1000 blocks for ProposalCreated events, which should be sufficient to cover any recent proposals given typical block times on Optimism - toBlock: 'latest', - address: bridgeReceiver.address, - topics: [utils.id('ProposalCreated(address,uint256,address[],uint256[],string[],bytes[],uint256)')] - }); - - const bridgeERC20ToSignature = 'bridgeERC20To(address,address,address,uint256,uint32,bytes)'; - const depositForBurnSignature = 'depositForBurn(uint256,uint32,bytes32,address,bytes32,uint256,uint32)'; - - for (const event of proposalCreatedEvents) { - const decodedEvent = bridgeReceiver.interface.parseLog(event); - const { signatures, calldatas } = decodedEvent.args; - - for (let i = 0; i < signatures.length; i++) { - if (signatures[i] === bridgeERC20ToSignature) { - const [localToken, remoteToken, to, amount, , extraData] = utils.defaultAbiCoder.decode( - ['address', 'address', 'address', 'uint256', 'uint32', 'bytes'], - calldatas[i] - ); - - console.log(`Simulating L2→L1 bridgeERC20To: ${amount.toString()} of ${remoteToken} to ${to}`); - - console.log('Setting up L1 state to simulate finalizeBridgeERC20...'); - console.log('Optimism L1 Portal address:', OPTIMISM_L1_PORTAL); - console.log('Overriding slot', utils.hexZeroPad('0x32', 32)); - console.log('l2CrossDomainMessenger:', utils.hexZeroPad(l2CrossDomainMessenger.address, 32)); - await governanceDeploymentManager.hre.network.provider.send('hardhat_setStorageAt', [ - OPTIMISM_L1_PORTAL, - utils.hexZeroPad('0x32', 32), - utils.hexZeroPad(l2CrossDomainMessenger.address, 32) - ]); - - await governanceDeploymentManager.hre.network.provider.send('hardhat_setStorageAt', [ - opL1CrossDomainMessenger.address, - '0xcc', - utils.hexZeroPad(optimismL2Bridge.address, 32) - ]); - - const domainMessengerSigner = await impersonateAddress( - governanceDeploymentManager, - opL1CrossDomainMessenger.address + bridgeDeploymentManager.stashRelayMessage( + bridgeReceiver.address, + callData, + signer.address ); - await governanceDeploymentManager.hre.network.provider.send('hardhat_setBalance', [ - domainMessengerSigner.address, - ethers.utils.hexStripZeros(ethers.utils.parseEther('1').toHexString()), - ]); - - await ( - await optimismL1Bridge.connect(domainMessengerSigner).finalizeBridgeERC20( - remoteToken, localToken, bridgeReceiver.address, to, amount, extraData, - { gasPrice: 0, gasLimit: 2_500_000 } - ) - ).wait(); - await governanceDeploymentManager.hre.network.provider.send('hardhat_setStorageAt', [ - OPTIMISM_L1_PORTAL, - utils.hexZeroPad('0x32', 32), - utils.hexZeroPad('0xdead', 32) - ]); - } - - // Look for L2→L1 CCTP depositForBurn calls (Circle CCTP bridge, e.g. native USDC) - if (signatures[i] === depositForBurnSignature) { - const [amount, , mintRecipientBytes32, burnToken] = utils.defaultAbiCoder.decode( - ['uint256', 'uint32', 'bytes32', 'address', 'bytes32', 'uint256', 'uint32'], - calldatas[i] - ); - - const mintRecipient = utils.getAddress('0x' + utils.hexlify(mintRecipientBytes32).slice(-40)); - - try { - // L2 - const l2CCTPTokenMessenger = await bridgeDeploymentManager.getContractOrThrow('CCTPMessageTransmitter'); - // Resolve L1 token via CCTP TokenMinter: burnToken (L2) → localToken (L1) - const l1CCTPTokenMessenger = await governanceDeploymentManager.getContractOrThrow('CCTPTokenMessenger'); - const tokenMinterAddress = await l1CCTPTokenMessenger.localMinter(); - const L1TokenMinter = new Contract( - tokenMinterAddress, - ['function mint(uint32 sourceDomain, bytes32 burnToken, address recipientOne, address recipientTwo, uint256 amountOne, uint256 amountTwo) returns (address)'], - await governanceDeploymentManager.getSigner() - ); - const l1CCTPTokenMessengerSigner = await impersonateAddress( - governanceDeploymentManager, - l1CCTPTokenMessenger.address - ); - await governanceDeploymentManager.hre.network.provider.send('hardhat_setBalance', [ - l1CCTPTokenMessengerSigner.address, - '0x1000000000000000000', - ]); - const sourceDomain = await l2CCTPTokenMessenger.localDomain(); - const mintTx = await L1TokenMinter.connect(l1CCTPTokenMessengerSigner).mint( - sourceDomain, - utils.hexZeroPad(burnToken, 32), - mintRecipient, - L1TokenMinter.address, // mint to the token minter first, since some tokens (e.g. USDC) have a cap on max amount per mint, and the token minter can then transfer to the recipient - amount, - 1 - ); - console.log('Simulated CCTP mint transaction:', mintTx.hash); - await mintTx.wait(); - } catch (e) { - console.log(`Warning: Could not simulate CCTP L2→L1 bridging for depositForBurn: ${e.message}`); - } + } else { + await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); } + console.log( + `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Executed bridged proposal ${id}` + ); } + + return openBridgedProposals; } } diff --git a/scenario/utils/relayScrollMessage.ts b/scenario/utils/relayScrollMessage.ts index 3d6b5b7bf..686658cd0 100644 --- a/scenario/utils/relayScrollMessage.ts +++ b/scenario/utils/relayScrollMessage.ts @@ -167,9 +167,7 @@ export default async function relayScrollMessage( // Add the proposal to the list of open bridged proposals to be executed after all the messages have been relayed openBridgedProposals.push({ id, eta }); } else { - // throw error only on last relay message and no proposal created event found - if(messageSentEvents.indexOf(messageSentEvent) === messageSentEvents.length - 1 && openBridgedProposals.length === 0) - throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); + throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); } } diff --git a/scenario/utils/relayUnichainMessage.ts b/scenario/utils/relayUnichainMessage.ts index 5f49b9773..5b3db9b5b 100644 --- a/scenario/utils/relayUnichainMessage.ts +++ b/scenario/utils/relayUnichainMessage.ts @@ -124,7 +124,7 @@ export async function relayUnichainMessage( } } else if (target === bridgeReceiver.address) { // Cross-chain message passing - if (relayMessageTxn) { + if (!tenderlyLogs && relayMessageTxn) { const proposalCreatedEvent = relayMessageTxn.events.find(event => event.address === bridgeReceiver.address); const { args: { id, eta } } = bridgeReceiver.interface.parseLog(proposalCreatedEvent); @@ -132,9 +132,26 @@ export async function relayUnichainMessage( openBridgedProposals.push({ id, eta }); } } else { - // throw error only on last relay message and no proposal created event found - if(sentMessageEvents.indexOf(sentMessageEvent) === sentMessageEvents.length - 1 && openBridgedProposals.length === 0) - throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); + throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); + } + } + + // Handle proposal creation for tenderly + if (tenderlyLogs) { + // We need to check for ProposalCreated events since we don't get them in the loop above + const proposalFilter = bridgeReceiver.filters.ProposalCreated(); + const proposalEvents = await bridgeDeploymentManager.hre.ethers.provider.getLogs({ + fromBlock: 'latest', + toBlock: 'latest', + address: bridgeReceiver.address, + topics: proposalFilter.topics + }); + + for (let event of proposalEvents) { + const { + args: { id, eta }, + } = bridgeReceiver.interface.parseLog(event); + openBridgedProposals.push({ id, eta }); } } diff --git a/tasks/deployment_manager/task.ts b/tasks/deployment_manager/task.ts index 47bfc06c7..d4378cb64 100644 --- a/tasks/deployment_manager/task.ts +++ b/tasks/deployment_manager/task.ts @@ -4,7 +4,7 @@ import { writeEnacted } from '../../plugins/deployment_manager/Enacted'; import { HardhatRuntimeEnvironment, HardhatConfig } from 'hardhat/types'; import { DeploymentManager, VerifyArgs } from '../../plugins/deployment_manager'; import { impersonateAddress } from '../../plugins/scenario/utils'; -import hreForBase, { migrationStarted} from '../../plugins/scenario/utils/hreForBase'; +import hreForBase from '../../plugins/scenario/utils/hreForBase'; // TODO: Don't depend on scenario's hreForBase async function getForkEnv(env: HardhatRuntimeEnvironment, deployment: string): Promise { @@ -248,7 +248,6 @@ task('migrate', 'Runs migration') governanceDm = dm; } - migrationStarted(); if (impersonate && !simulate) { throw new Error('Cannot impersonate an address if not simulating a migration. Please specify --simulate to simulate.'); } else if (impersonate && simulate) { @@ -377,7 +376,6 @@ task('deploy_and_migrate', 'Runs deploy and migration') governanceDm = dm; } - migrationStarted(); if (impersonate && !simulate) { throw new Error('Cannot impersonate an address if not simulating a migration. Please specify --simulate to simulate.'); } else if (impersonate && simulate) { From f780802705ebcbfe7138007a602c47be63b25b86 Mon Sep 17 00:00:00 2001 From: Mykhailo Shabodyash Date: Mon, 15 Jun 2026 20:00:09 +0300 Subject: [PATCH 58/65] feat: New migration --- .../migrations/1781520280_setup_franchiser.ts | 164 ++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts diff --git a/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts b/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts new file mode 100644 index 000000000..106b0eaaa --- /dev/null +++ b/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts @@ -0,0 +1,164 @@ +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { exp, proposal } from '../../../../src/deploy'; +import { Contract } from 'ethers'; + +const OLD_FRANCHISER_FACTORY = '0xE696d89f4F378772f437F01FaaD70240abdf1854'; +const FRANCHISER_POOL_FACTORY = '0x4f858af44fD7f2B4BFe61ceee1560E4Dd5531896'; + +const poolConfig = { + coordinator: '0xbbf3f1421d886e9b2c5d716b5192ac998af2012c', + guardian: '0xbbf3f1421d886e9b2c5d716b5192ac998af2012c', + maxDelegatees: 30, + freezePeriod: 10 * 24 * 60 * 60, // 10 days in seconds + amount: exp(610000, 18), // 610,000 COMP +}; + +const oldFranchisers = [ + '0xDff7Ea1B9c6c23d63B9038428767231439321D12', + '0x99e0705d0C93f1cb982bCE4c14ce7feD7e23Cf83', + '0x1e76b5bcf86967d5555ECDEDDd67248F949dc5BC', + '0x2F845447F1040176091Ed16C72E9c4ddC292F14B', + '0xC623e9bc66cF498ABdC3c7297e9Df95f20C2F0a8', + '0xca038273e110c8e39543E7FAB9279FB42fE32c63', + '0x59dC38b5CEe74ca7189394eddAf5A13611DF0B63', + '0xe8B2B94612240d57D830944a668E4e48eDF9F9D8', + '0xEC8604670F07dB6E40f84147F4297b7f58775350', + '0x603657fDEc47a9dF15A5661cE011E13C0D449982', + '0x1543D57471A5F168cBabb5922246a77013c9d2E4', + '0xBbc353508e782d44fFbD28d2869bd527070b24F2', + '0x78BE1f3dd735bB4F20decb62A1beCE31DA452126', +]; + +const delegatePowerBefore: { [delegatee: string]: bigint } = {}; + +export default migration('1781520280_setup_franchiser', { + async prepare() { + return {}; + }, + + async enact(deploymentManager: DeploymentManager) { + const trace = deploymentManager.tracer(); + + const { + governor, + timelock, + COMP, + } = await deploymentManager.getContracts(); + + const oldFranchiserFactory = await deploymentManager.existing('oldFranchiserFactory', OLD_FRANCHISER_FACTORY); + const franchiserPoolFactory = await deploymentManager.existing('franchiserPoolFactory', FRANCHISER_POOL_FACTORY); + + let totalBalance = BigInt(0); + const delegateesConfig: {delegatee: string, balance: bigint}[] = []; + + for (const franchiser of oldFranchisers) { + const balance = await COMP.balanceOf(franchiser); + + const franchiserContract = new Contract( + franchiser, + ['function delegatee() view returns (address)'], + await deploymentManager.getSigner() + ); + const delegatee = await franchiserContract.delegatee(); + trace(`Franchiser ${franchiser}, (delegatee ${delegatee}) has balance ${balance.toString()}`); + delegateesConfig.push({ delegatee, balance: balance.toBigInt() }); + totalBalance += balance.toBigInt(); + + const delegatePower = await COMP.getCurrentVotes(delegatee); + delegatePowerBefore[delegatee] = delegatePower.toBigInt(); + } + + trace(`Total balance of old franchisers: ${totalBalance}`); + + const delegatees = delegateesConfig.map(({ delegatee }) => delegatee); + + const mainnetActions = [ + // 1. Recall COMP tokens from old franchisers back to the timelock + { + contract: oldFranchiserFactory, + signature: 'recallMany(address[],address[])', + args: [ + delegatees, + Array(delegatees.length).fill(timelock.address), + ], + }, + // 2. Approve factory to transfer COMP tokens on behalf of the timelock + { + contract: COMP, + signature: 'approve(address,uint256)', + args: [franchiserPoolFactory.address, poolConfig.amount], + }, + // 3. Create a new pool for the franchisers + { + contract: franchiserPoolFactory, + signature: 'createPoolAndFund(address,address,uint256,uint256,address[],uint256[])', + args: [ + poolConfig.coordinator, + poolConfig.guardian, + poolConfig.maxDelegatees, + poolConfig.freezePeriod, + delegateesConfig.map(({ delegatee }) => delegatee), + delegateesConfig.map(({ balance }) => balance.toString()) + ], + }, + ]; + + const description = `DESCRIPTION`; + + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ), 0, 300_000 + ); + + const event = txn.events.find( + (event: { event: string }) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + }, + + async enacted(): Promise { + return false; + }, + + async verify(deploymentManager: DeploymentManager) { + + const { COMP } = await deploymentManager.getContracts(); + + const franchiserPoolFactory = await deploymentManager.existing('franchiserPoolFactory', FRANCHISER_POOL_FACTORY); + + const pools = await franchiserPoolFactory.getAllPools(); + expect(pools.length).to.equal(1); + + const pool = new Contract( + pools[0], + [ + 'function coordinator() view returns (address)', + 'function guardian() view returns (address)', + 'function maxDelegatees() view returns (uint256)', + 'function freezePeriod() view returns (uint256)', + ], + await deploymentManager.getSigner() + ); + + expect(await pool.coordinator()).to.equal(poolConfig.coordinator); + expect(await pool.guardian()).to.equal(poolConfig.guardian); + expect(await pool.maxDelegatees()).to.equal(poolConfig.maxDelegatees); + expect(await pool.freezePeriod()).to.equal(poolConfig.freezePeriod); + + expect(await COMP.balanceOf(pools[0])).to.equal(poolConfig.amount); + + for (const franchiser of oldFranchisers) { + expect(await COMP.balanceOf(franchiser)).to.equal(0); + } + + // Verify that delegatees have the same voting power captured before migration. + for (const delegatee of Object.keys(delegatePowerBefore)) { + const delegatePowerAfter = await COMP.getCurrentVotes(delegatee); + expect(delegatePowerAfter.toBigInt()).to.equal(delegatePowerBefore[delegatee]); + } + }, +}); From 2b51ee21bb8bc1912c9eda764ebd172042a677f8 Mon Sep 17 00:00:00 2001 From: Mykhailo Shabodyash Date: Mon, 15 Jun 2026 20:00:27 +0300 Subject: [PATCH 59/65] fix: Use tenderly params from .env --- scenario/utils/index.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/scenario/utils/index.ts b/scenario/utils/index.ts index edbf5544f..5181ea6b4 100644 --- a/scenario/utils/index.ts +++ b/scenario/utils/index.ts @@ -990,9 +990,11 @@ async function simulateBundle( const rollingStateChanges = {}; const results = []; - for (const sim of simulations) { - const { username, project, accessKey } = (dm.hre.config as any).tenderly; + const project = 'comet'; + const username = process.env.TENDERLY_USERNAME || ''; + const accessKey = process.env.TENDERLY_ACCESS_KEY || ''; + for (const sim of simulations) { // Merge rolling state changes with simulation's own state_objects const stateObjects = sim.state_objects ? { ...rollingStateChanges, ...sim.state_objects } @@ -1048,8 +1050,11 @@ async function simulateBundle( return results; } -async function shareSimulation(dm: DeploymentManager, simulationId: string) { - const { username, project, accessKey } = (dm.hre.config as any).tenderly; +async function shareSimulation(dm: DeploymentManager, simulationId: string) { + const project = 'comet'; + const username = process.env.TENDERLY_USERNAME || ''; + const accessKey = process.env.TENDERLY_ACCESS_KEY || ''; + return axios.post( `https://api.tenderly.co/api/v1/account/${username}/project/${project}/simulations/${simulationId}/share`, {}, From 875df2ce56d510e7dcbb3019a3bbf22760f2e504 Mon Sep 17 00:00:00 2001 From: Mykhailo Shabodyash Date: Tue, 16 Jun 2026 22:50:08 +0300 Subject: [PATCH 60/65] feat: description --- .../migrations/1781520280_setup_franchiser.ts | 53 ++++++++++++++++--- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts b/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts index 106b0eaaa..125eedaf4 100644 --- a/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts +++ b/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts @@ -8,8 +8,8 @@ const OLD_FRANCHISER_FACTORY = '0xE696d89f4F378772f437F01FaaD70240abdf1854'; const FRANCHISER_POOL_FACTORY = '0x4f858af44fD7f2B4BFe61ceee1560E4Dd5531896'; const poolConfig = { - coordinator: '0xbbf3f1421d886e9b2c5d716b5192ac998af2012c', - guardian: '0xbbf3f1421d886e9b2c5d716b5192ac998af2012c', + coordinator: '0x9825413dd3875E01B34451A7A7e066b2225a234E', + guardian: '0xbbf3f1421D886E9b2c5D716B5192aC998af2012c', maxDelegatees: 30, freezePeriod: 10 * 24 * 60 * 60, // 10 days in seconds amount: exp(610000, 18), // 610,000 COMP @@ -55,13 +55,14 @@ export default migration('1781520280_setup_franchiser', { for (const franchiser of oldFranchisers) { const balance = await COMP.balanceOf(franchiser); - + const franchiserContract = new Contract( franchiser, ['function delegatee() view returns (address)'], await deploymentManager.getSigner() ); const delegatee = await franchiserContract.delegatee(); + trace(`Franchiser ${franchiser}, (delegatee ${delegatee}) has balance ${balance.toString()}`); delegateesConfig.push({ delegatee, balance: balance.toBigInt() }); totalBalance += balance.toBigInt(); @@ -105,7 +106,49 @@ export default migration('1781520280_setup_franchiser', { }, ]; - const description = `DESCRIPTION`; + const description = `# Migrate to Franchiser V2 + +## Proposal summary + +Woof proposes migrating the current franchiser program to Franchiser V2, which separates funding from day-to-day delegate management while preserving current delegate voting power. + +### Why this change + +- Governance currently must allocate COMP and choose delegatees in the same proposal. +- Reassigning delegates requires a full governance cycle. +- A delegate whose power is being revoked can still vote against that proposal. +- The new design reduces operational overhead and improves incident response. + +### New operating model + +| Role / Component | Responsibility | +| --- | --- | +| FranchiserPoolFactory | Governance entry point for creating, funding, halting, and updating pools. | +| FranchiserPool | Coordinator and Guardian entry point for delegate management and emergency controls. | +| Franchiser | Holds delegated COMP for top-level delegatees and preserves the existing subdelegate model. | +| Governance | Can create and fund pools, halt a pool, and update the coordinator, guardian, delegate cap, or freeze period. | +| Coordinator | Can delegate, recall, and reassign COMP among top-level delegatees without moving COMP out of the program. | +| Guardian | Can recall specific delegates, freeze the pool while recalling all delegates, or suspend the Coordinator without recalling delegates. | + +### Safety properties + +- Frozen pools block Coordinator actions, but Guardian actions remain available. +- Governance can unfreeze a pool early or let the freeze expire automatically. +- The minimum freeze period is 10 days, giving Governance time to replace compromised actors or fully shut down the program if needed. +- Idle COMP remains in the pool, while delegated COMP is held by top-level Franchiser instances. + +## Note + +The migration preserves delegate voting power while moving administration to a more flexible operating model. + +## Proposal actions + +The first proposal action recalls COMP from the old franchisers back to the timelock. + +The second action approves the FranchiserPoolFactory to transfer COMP on behalf of the timelock. + +The third action creates a new pool for the franchisers, funding it with recalled 610,000 COMP and assigning the same delegatees as before. +`; const txn = await deploymentManager.retry(async () => trace( @@ -149,8 +192,6 @@ export default migration('1781520280_setup_franchiser', { expect(await pool.maxDelegatees()).to.equal(poolConfig.maxDelegatees); expect(await pool.freezePeriod()).to.equal(poolConfig.freezePeriod); - expect(await COMP.balanceOf(pools[0])).to.equal(poolConfig.amount); - for (const franchiser of oldFranchisers) { expect(await COMP.balanceOf(franchiser)).to.equal(0); } From 776380a76c5f0be8a4cba253068943a9b58cc295 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash <171867410+MishaShWoof@users.noreply.github.com> Date: Thu, 18 Jun 2026 13:31:29 +0300 Subject: [PATCH 61/65] fix: Update description and contract abi and address --- .../usdc/migrations/1781520280_setup_franchiser.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts b/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts index 125eedaf4..224b7aa55 100644 --- a/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts +++ b/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts @@ -5,7 +5,7 @@ import { exp, proposal } from '../../../../src/deploy'; import { Contract } from 'ethers'; const OLD_FRANCHISER_FACTORY = '0xE696d89f4F378772f437F01FaaD70240abdf1854'; -const FRANCHISER_POOL_FACTORY = '0x4f858af44fD7f2B4BFe61ceee1560E4Dd5531896'; +const FRANCHISER_POOL_FACTORY = '0x219a69E60Eaf34A7658848664b907Fa6d72B5CEb'; const poolConfig = { coordinator: '0x9825413dd3875E01B34451A7A7e066b2225a234E', @@ -94,12 +94,13 @@ export default migration('1781520280_setup_franchiser', { // 3. Create a new pool for the franchisers { contract: franchiserPoolFactory, - signature: 'createPoolAndFund(address,address,uint256,uint256,address[],uint256[])', + signature: 'createPoolAndFund(address,address,uint256,uint256,uint256,address[],uint256[])', args: [ poolConfig.coordinator, poolConfig.guardian, poolConfig.maxDelegatees, poolConfig.freezePeriod, + poolConfig.amount, delegateesConfig.map(({ delegatee }) => delegatee), delegateesConfig.map(({ balance }) => balance.toString()) ], @@ -112,6 +113,8 @@ export default migration('1781520280_setup_franchiser', { Woof proposes migrating the current franchiser program to Franchiser V2, which separates funding from day-to-day delegate management while preserving current delegate voting power. +Further detailed information can be found in the [Franchiser repository](https://github.com/woof-software/compound-franchiser) and [proposal pull request](https://github.com/compound-finance/comet/pull/1134). + ### Why this change - Governance currently must allocate COMP and choose delegatees in the same proposal. @@ -196,6 +199,9 @@ The third action creates a new pool for the franchisers, funding it with recalle expect(await COMP.balanceOf(franchiser)).to.equal(0); } + // Check that all COMP is used for franchisers and none is left in the pool contract. + expect(await COMP.balanceOf(pools[0])).to.equal(0); + // Verify that delegatees have the same voting power captured before migration. for (const delegatee of Object.keys(delegatePowerBefore)) { const delegatePowerAfter = await COMP.getCurrentVotes(delegatee); From 53c9c8b800285271c8517caa1a0b3b05eebae8aa Mon Sep 17 00:00:00 2001 From: Mykhailo Shabodyash Date: Mon, 6 Jul 2026 19:01:35 +0300 Subject: [PATCH 62/65] feat: new deployment and audit link --- .../mainnet/usdc/migrations/1781520280_setup_franchiser.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts b/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts index 224b7aa55..d3e1a6c6b 100644 --- a/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts +++ b/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts @@ -5,7 +5,7 @@ import { exp, proposal } from '../../../../src/deploy'; import { Contract } from 'ethers'; const OLD_FRANCHISER_FACTORY = '0xE696d89f4F378772f437F01FaaD70240abdf1854'; -const FRANCHISER_POOL_FACTORY = '0x219a69E60Eaf34A7658848664b907Fa6d72B5CEb'; +const FRANCHISER_POOL_FACTORY = '0x8421c35b1235741e00d2475f365A434d4b476A19'; const poolConfig = { coordinator: '0x9825413dd3875E01B34451A7A7e066b2225a234E', @@ -144,6 +144,10 @@ Further detailed information can be found in the [Franchiser repository](https:/ The migration preserves delegate voting power while moving administration to a more flexible operating model. +## Audit + +The Franchiser V2 code has been audited by ChainSecurity, and the audit report is available [here](https://www.chainsecurity.com/security-audit/compound-franchiser-v2). + ## Proposal actions The first proposal action recalls COMP from the old franchisers back to the timelock. From 04aeb9d844783cddbe9f27f41b728a2375338895 Mon Sep 17 00:00:00 2001 From: Mykhailo Shabodyash Date: Tue, 7 Jul 2026 14:58:02 +0300 Subject: [PATCH 63/65] fix: new description and updated logic for proposal --- .../migrations/1781520280_setup_franchiser.ts | 117 ++++++++++++------ scenario/utils/index.ts | 2 + 2 files changed, 83 insertions(+), 36 deletions(-) diff --git a/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts b/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts index d3e1a6c6b..cc47e3efc 100644 --- a/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts +++ b/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts @@ -31,7 +31,20 @@ const oldFranchisers = [ '0x78BE1f3dd735bB4F20decb62A1beCE31DA452126', ]; +const delegateesToSkip = [ + '0x13BDaE8c5F0fC40231F0E6A4ad70196F59138548', // Michigan Blockchain | 29,999.88 COMP + '0x4f894Bfc9481110278C356adE1473eBe2127Fd3C', // Reservoir / AlphaGrowth | 50,000.00 COMP + '0x72C58877ef744b86F6ef416a3bE26Ec19d587708', // Sharp | 1,178.70 COMP +]; + +const delegateesToReallocate = [ + { delegatee: '0x070341aA5Ed571f0FB2c4a5641409B1A46b4961b', amount: exp(8262.46, 18) }, // FranklinDAO + { delegatee: '0xc5547B4907418C2EC0C2A95beC6fEE8354657759', amount: exp(40000, 18) }, // DAOplomats + { delegatee: '0x1F3D3A7A9c548bE39539b39D7400302753E20591', amount: exp(32916.12, 18) }, // blockful +]; + const delegatePowerBefore: { [delegatee: string]: bigint } = {}; +const delegateesConfig: {delegatee: string, balance: bigint}[] = []; export default migration('1781520280_setup_franchiser', { async prepare() { @@ -51,7 +64,6 @@ export default migration('1781520280_setup_franchiser', { const franchiserPoolFactory = await deploymentManager.existing('franchiserPoolFactory', FRANCHISER_POOL_FACTORY); let totalBalance = BigInt(0); - const delegateesConfig: {delegatee: string, balance: bigint}[] = []; for (const franchiser of oldFranchisers) { const balance = await COMP.balanceOf(franchiser); @@ -73,8 +85,27 @@ export default migration('1781520280_setup_franchiser', { trace(`Total balance of old franchisers: ${totalBalance}`); + // Capture baseline voting power for reallocated delegatees that have no old franchiser (e.g. brand-new delegates). + for (const { delegatee } of delegateesToReallocate) { + if (!(delegatee in delegatePowerBefore)) { + delegatePowerBefore[delegatee] = (await COMP.getCurrentVotes(delegatee)).toBigInt(); + } + } + const delegatees = delegateesConfig.map(({ delegatee }) => delegatee); + for (const { delegatee, amount } of delegateesToReallocate) { + const existing = delegateesConfig.find((c) => c.delegatee === delegatee); + if (existing) { + existing.balance += amount; + } else { + delegateesConfig.push({ delegatee, balance: amount }); + } + } + + const delegateesForRenewal = delegateesConfig.filter(({ delegatee }) => !delegateesToSkip.includes(delegatee)); + trace(`Delegatees for renewal: ${delegateesForRenewal.map(({ delegatee }) => delegatee).join(', ')}`); + const mainnetActions = [ // 1. Recall COMP tokens from old franchisers back to the timelock { @@ -101,60 +132,60 @@ export default migration('1781520280_setup_franchiser', { poolConfig.maxDelegatees, poolConfig.freezePeriod, poolConfig.amount, - delegateesConfig.map(({ delegatee }) => delegatee), - delegateesConfig.map(({ balance }) => balance.toString()) + delegateesForRenewal.map(({ delegatee }) => delegatee), + delegateesForRenewal.map(({ balance }) => balance.toString()) ], }, ]; - const description = `# Migrate to Franchiser V2 + const description = `# Franchiser Operational Upgrade and Rebalance + +## Summary -## Proposal summary +This proposal upgrades Compound's treasury-delegation (Franchiser) system to a new pool-based architecture and, in the same step, carries out the first scheduled biannual delegate rebalancing under **Proposal 504 — [Compound Delegate Race (Cycle 2)](https://www.comp.xyz/t/compound-delegate-race-cycle-2/7302)**. -Woof proposes migrating the current franchiser program to Franchiser V2, which separates funding from day-to-day delegate management while preserving current delegate voting power. +The total COMP delegated through the program does not change. Existing delegations migrate to the new pool with no interruption to voting power, and the pool reclaimed from under-participating delegates is redistributed to qualified active delegates. COMP remains in Governance-owned contracts throughout. -Further detailed information can be found in the [Franchiser repository](https://github.com/woof-software/compound-franchiser) and [proposal pull request](https://github.com/compound-finance/comet/pull/1134). +## Background -### Why this change +Proposal 504 established a standing six-monthly review of treasury-delegated voting power, with a uniform on-chain participation standard and a defined reallocation procedure. The first review window (Proposals 505–586) has closed and participation has been verified on-chain. The full review, application window, and waterfall are documented on the forum: [comp.xyz/t/7862](https://www.comp.xyz/t/7862). -- Governance currently must allocate COMP and choose delegatees in the same proposal. -- Reassigning delegates requires a full governance cycle. -- A delegate whose power is being revoked can still vote against that proposal. -- The new design reduces operational overhead and improves incident response. +## What this proposal does -### New operating model +1. **Upgrade.** Migrate the treasury-delegation program to the upgraded Franchiser pool: existing delegations move into a new Governance-funded pool, with the CGWG multisig set as Coordinator and a Guardian set for emergency oversight. Governance retains sole authority to fund, halt, or reclaim the pool in full. -| Role / Component | Responsibility | -| --- | --- | -| FranchiserPoolFactory | Governance entry point for creating, funding, halting, and updating pools. | -| FranchiserPool | Coordinator and Guardian entry point for delegate management and emergency controls. | -| Franchiser | Holds delegated COMP for top-level delegatees and preserves the existing subdelegate model. | -| Governance | Can create and fund pools, halt a pool, and update the coordinator, guardian, delegate cap, or freeze period. | -| Coordinator | Can delegate, recall, and reassign COMP among top-level delegatees without moving COMP out of the program. | -| Guardian | Can recall specific delegates, freeze the pool while recalling all delegates, or suspend the Coordinator without recalling delegates. | +2. **Rebalance.** As part of the migration, three delegations that fell below the participation standard are not renewed — releasing **81,178.58 COMP** — which is redistributed to the qualified applicants per the waterfall. -### Safety properties +**Not renewed — 81,178.58 COMP reclaimed:** -- Frozen pools block Coordinator actions, but Guardian actions remain available. -- Governance can unfreeze a pool early or let the freeze expire automatically. -- The minimum freeze period is 10 days, giving Governance time to replace compromised actors or fully shut down the program if needed. -- Idle COMP remains in the pool, while delegated COMP is held by top-level Franchiser instances. +| Delegatee | Address | COMP | +|---|---|---:| +| Michigan Blockchain | \`0x13BD…8548\` | 29,999.88 | +| Reservoir / AlphaGrowth | \`0x4f89…fd3c\` | 50,000.00 | +| Sharp | \`0x72C5…7708\` | 1,178.70 | -## Note +**Reallocated — 81,178.58 COMP:** -The migration preserves delegate voting power while moving administration to a more flexible operating model. +| Delegate | Address | COMP | +|---|---|---:| +| FranklinDAO | \`0x0703…961b\` | 8,262.46 | +| DAOplomats | \`0xc554…7759\` | 40,000.00 | +| blockful | \`0x1F3D…0591\` | 32,916.12 | -## Audit +## The upgraded architecture -The Franchiser V2 code has been audited by ChainSecurity, and the audit report is available [here](https://www.chainsecurity.com/security-audit/compound-franchiser-v2). +The upgrade replaces per-delegation Franchiser deployments with a single pool, split across three role-gated contracts: -## Proposal actions +- **FranchiserPoolFactory** — the Governance-only entry point. Governance creates, funds, and can halt a pool; halting recalls all delegates and returns the full COMP balance to the Timelock (the only path for COMP to leave the program). +- **FranchiserPool** — holds the program's idle COMP. A **Coordinator** (the CGWG multisig) can \`delegate\`, \`recall\`, and \`reassign\` voting power among delegates within Governance-set limits. A separate **Guardian** can emergency-\`recall\` a delegate or \`freeze\` the pool (10-day minimum), but can never move or delegate COMP. +- **Franchiser** — unchanged from V1: holds delegated COMP and grants voting power to a delegatee (who may name up to one sub-delegate). -The first proposal action recalls COMP from the old franchisers back to the timelock. +Governance (the Timelock) sets each pool's parameters — delegate cap, Coordinator, Guardian, freeze period — and can change them or halt the program at any time by on-chain vote. -The second action approves the FranchiserPoolFactory to transfer COMP on behalf of the timelock. +## Guarantees -The third action creates a new pool for the franchisers, funding it with recalled 610,000 COMP and assigning the same delegatees as before. +- **Delegation only, never custody.** COMP stays in Governance-owned contracts at every step (Timelock → pool → Franchiser); no working group, Coordinator, or Guardian ever takes custody of the tokens. +- **Total set by governance.** This proposal does not change the program's total delegated COMP — it migrates and reallocates the existing pool. Any change to the total returns to an on-chain vote, and Governance can recall or reassign any delegation at any time. `; const txn = await deploymentManager.retry(async () => @@ -206,10 +237,24 @@ The third action creates a new pool for the franchisers, funding it with recalle // Check that all COMP is used for franchisers and none is left in the pool contract. expect(await COMP.balanceOf(pools[0])).to.equal(0); - // Verify that delegatees have the same voting power captured before migration. + // Verify that delegatees have the expected voting power after migration. for (const delegatee of Object.keys(delegatePowerBefore)) { const delegatePowerAfter = await COMP.getCurrentVotes(delegatee); - expect(delegatePowerAfter.toBigInt()).to.equal(delegatePowerBefore[delegatee]); + const reallocation = delegateesToReallocate.find(({ delegatee: d }) => d === delegatee); + + if (delegateesToSkip.includes(delegatee)) { + // Delegatees that were skipped for reallocation should have 0 voting power after migration. + expect(delegatePowerBefore[delegatee] - delegatePowerAfter.toBigInt()) + .to.equal(delegateesConfig.find(({ delegatee: d }) => d === delegatee)?.balance); + } + else if (reallocation) { + // Delegatees that received a reallocation should gain exactly the reallocated amount. + expect(delegatePowerAfter.toBigInt() - delegatePowerBefore[delegatee]).to.equal(reallocation.amount); + } + else { + // Delegatees that were renewed should have the same voting power as before migration. + expect(delegatePowerAfter.toBigInt()).to.equal(delegatePowerBefore[delegatee]); + } } }, }); diff --git a/scenario/utils/index.ts b/scenario/utils/index.ts index 9c4ba9f11..473c16b8e 100644 --- a/scenario/utils/index.ts +++ b/scenario/utils/index.ts @@ -358,6 +358,8 @@ export async function isValidAssetIndex( if (assetNum >= MAX_ASSETS) return false; // Asset info checks. If any of these are false, the asset is invalid. This means that the asset is deprecated. const comet = await ctx.getComet(); + const numAssets = await comet.numAssets(); + if (assetNum >= numAssets) return false; const assetInfo = await comet.getAssetInfo(assetNum); if (assetInfo.borrowCollateralFactor.toBigInt() == 0n) return false; if (assetInfo.supplyCap.toBigInt() == 0n) return false; From 131e04c505277cf6c95b13ae6ab7219b4601b2d6 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Tue, 14 Jul 2026 02:45:29 +0000 Subject: [PATCH 64/65] Modified migration from GitHub Actions --- .../mainnet/usdc/migrations/1781520280_setup_franchiser.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts b/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts index cc47e3efc..8639ba703 100644 --- a/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts +++ b/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts @@ -201,8 +201,8 @@ Governance (the Timelock) sets each pool's parameters — delegate cap, Coordina trace(`Created proposal ${proposalId}.`); }, - async enacted(): Promise { - return false; + async enacted(deploymentManager: DeploymentManager): Promise { + return true; }, async verify(deploymentManager: DeploymentManager) { From 4b992e25b7e079fd7d2f6d27f325dc296a0a7abd Mon Sep 17 00:00:00 2001 From: Mykhailo Shabodyash Date: Tue, 14 Jul 2026 17:01:00 +0300 Subject: [PATCH 65/65] feat: change mock address to actual --- .../mainnet/usdc/migrations/1781520280_setup_franchiser.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts b/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts index 8639ba703..d92a98944 100644 --- a/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts +++ b/deployments/mainnet/usdc/migrations/1781520280_setup_franchiser.ts @@ -8,7 +8,7 @@ const OLD_FRANCHISER_FACTORY = '0xE696d89f4F378772f437F01FaaD70240abdf1854'; const FRANCHISER_POOL_FACTORY = '0x8421c35b1235741e00d2475f365A434d4b476A19'; const poolConfig = { - coordinator: '0x9825413dd3875E01B34451A7A7e066b2225a234E', + coordinator: '0xfd947c72f09703210eeCbcab9c9206fE5e1Bb6e2', guardian: '0xbbf3f1421D886E9b2c5D716B5192aC998af2012c', maxDelegatees: 30, freezePeriod: 10 * 24 * 60 * 60, // 10 days in seconds @@ -201,8 +201,8 @@ Governance (the Timelock) sets each pool's parameters — delegate cap, Coordina trace(`Created proposal ${proposalId}.`); }, - async enacted(deploymentManager: DeploymentManager): Promise { - return true; + async enacted(): Promise { + return false; }, async verify(deploymentManager: DeploymentManager) {