diff --git a/.env.example b/.env.example index 2f00c733..037aa5cd 100644 --- a/.env.example +++ b/.env.example @@ -5,20 +5,16 @@ # ############################ RPC_ETH_MAINNET= -RPC_ETH_GOERLI= +RPC_ETH_SEPOLIA= RPC_OPT_MAINNET=https://mainnet.optimism.io -RPC_OPT_GOERLI=https://goerli.optimism.io - -RPC_ARB_MAINNET=https://arb1.arbitrum.io/rpc -RPC_ARB_GOERLI=https://goerli-rollup.arbitrum.io/rpc +RPC_OPT_SEPOLIA=https://sepolia.optimism.io # ############################ # Etherscan # ############################ ETHERSCAN_API_KEY_ETH= -ETHERSCAN_API_KEY_ARB= ETHERSCAN_API_KEY_OPT= # ############################ @@ -29,7 +25,7 @@ ETHERSCAN_API_KEY_OPT= TOKEN= # Name of the network environments used by deployment scripts. -# Might be one of: "mainnet", "goerli". +# Might be one of: "mainnet", "sepolia". NETWORK=mainnet # Run deployment in the forking network instead of public ones @@ -38,7 +34,6 @@ FORKING=true # Private key of the deployer account used for deployment process ETH_DEPLOYER_PRIVATE_KEY= OPT_DEPLOYER_PRIVATE_KEY= -ARB_DEPLOYER_PRIVATE_KEY= L1_DEV_MULTISIG= L1_PROXY_ADMIN= @@ -63,14 +58,6 @@ L2_WITHDRAWALS_DISABLERS=[] # Integration Acceptance & E2E Testing # ############################ -TESTING_ARB_NETWORK= -TESTING_ARB_L1_TOKEN=0x7AEE39c46f20135114e85A03C02aB4FE73fB8127 -TESTING_ARB_L2_TOKEN=0x775ede8029C117effce283b3391E420EacF3c85F -TESTING_ARB_L1_ERC20_TOKEN_GATEWAY=0x0A7e12b563Ba623646a31a09F0182e8aD45D6cfD -TESTING_ARB_L2_ERC20_TOKEN_GATEWAY=0x8c269989D839eE9DaEe64D57C8c41404DF87F722 -TESTING_ARB_L1_GATEWAY_ROUTER=0xa2a8F940752aDc4A3278B63B96d56D72D2b075B1 -TESTING_ARB_L2_GATEWAY_ROUTER=0x57f54f87C44d816f60b92864e23b8c0897D4d81D - TESTING_OPT_NETWORK= TESTING_OPT_L1_TOKEN=0xaF8a2F0aE374b03376155BF745A3421Dac711C12 TESTING_OPT_L2_TOKEN=0xAED5F9aaF167923D34174b8E636aaF040A11f6F7 @@ -84,7 +71,6 @@ TESTING_OPT_L2_ERC20_TOKEN_BRIDGE=0x447CD1794d209Ac4E6B4097B34658bc00C4d0a51 TESTING_USE_DEPLOYED_CONTRACTS=false TESTING_L1_TOKENS_HOLDER= -TESTING_ARB_GOV_BRIDGE_EXECUTOR= TESTING_OPT_GOV_BRIDGE_EXECUTOR= # ############################ @@ -92,5 +78,4 @@ TESTING_OPT_GOV_BRIDGE_EXECUTOR= # ############################ TESTING_PRIVATE_KEY= -TESTING_OPT_LDO_HOLDER_PRIVATE_KEY= -TESTING_ARB_LDO_HOLDER_PRIVATE_KEY= +TESTING_OPT_LDO_HOLDER_PRIVATE_KEY= \ No newline at end of file diff --git a/.env.wsteth.arb_goerli b/.env.wsteth.arb_goerli deleted file mode 100644 index 6694eda7..00000000 --- a/.env.wsteth.arb_goerli +++ /dev/null @@ -1,75 +0,0 @@ -# Detailed info: https://github.com/lidofinance/lido-l2#Project-Configuration - -# ############################ -# RPCs -# ############################ - -RPC_ETH_GOERLI= -RPC_ARB_GOERLI=https://goerli-rollup.arbitrum.io/rpc - -# ############################ -# Etherscan -# ############################ - -ETHERSCAN_API_KEY_ETH= -ETHERSCAN_API_KEY_ARB= - -# ############################ -# Bridge/Gateway Deployment -# ############################ - -# Address of the token to deploy the bridge/gateway for -TOKEN=0x6320cd32aa674d2898a68ec82e869385fc5f7e2f - -# Name of the network environments used by deployment scripts. -# Might be one of: "mainnet", "goerli". -NETWORK=goerli - -# Run deployment in the forking network instead of public ones -FORKING=true - -# Private key of the deployer account used for deployment process - -ETH_DEPLOYER_PRIVATE_KEY= -ARB_DEPLOYER_PRIVATE_KEY= - -L1_PROXY_ADMIN=0x4333218072D5d7008546737786663c38B4D561A4 -L1_BRIDGE_ADMIN=0x4333218072D5d7008546737786663c38B4D561A4 -L1_DEPOSITS_ENABLED=true -L1_WITHDRAWALS_ENABLED=true -L1_DEPOSITS_ENABLERS=["0x4333218072D5d7008546737786663c38B4D561A4"] -L1_DEPOSITS_DISABLERS=["0x4333218072D5d7008546737786663c38B4D561A4","0x7fE7fa4EF7D134Dbf8B616Ba7B675F26286BC2cd"] -L1_WITHDRAWALS_ENABLERS=["0x4333218072D5d7008546737786663c38B4D561A4"] -L1_WITHDRAWALS_DISABLERS=["0x4333218072D5d7008546737786663c38B4D561A4","0x7fE7fa4EF7D134Dbf8B616Ba7B675F26286BC2cd"] - -L2_PROXY_ADMIN=0x43De3B7115baA4EbAbd7c5Eaf4cB2856238C6A50 -L2_BRIDGE_ADMIN=0x43De3B7115baA4EbAbd7c5Eaf4cB2856238C6A50 -L2_DEPOSITS_ENABLED=true -L2_WITHDRAWALS_ENABLED=true -L2_DEPOSITS_ENABLERS=["0x43De3B7115baA4EbAbd7c5Eaf4cB2856238C6A50"] -L2_DEPOSITS_DISABLERS=["0x43De3B7115baA4EbAbd7c5Eaf4cB2856238C6A50","0x7fE7fa4EF7D134Dbf8B616Ba7B675F26286BC2cd"] -L2_WITHDRAWALS_ENABLERS=["0x43De3B7115baA4EbAbd7c5Eaf4cB2856238C6A50"] -L2_WITHDRAWALS_DISABLERS=["0x43De3B7115baA4EbAbd7c5Eaf4cB2856238C6A50","0x7fE7fa4EF7D134Dbf8B616Ba7B675F26286BC2cd"] - -# ############################ -# Integration Acceptance & E2E Testing -# ############################ - -TESTING_ARB_NETWORK=goerli -TESTING_ARB_L1_TOKEN=0x6320cd32aa674d2898a68ec82e869385fc5f7e2f -TESTING_ARB_L2_TOKEN=0xbED18985eC648Ce4b0C5Fc3061d1323116702BC4 -TESTING_ARB_L1_ERC20_TOKEN_GATEWAY=0x0ecCFbBEe34f04187361818832385EB4cC11b678 -TESTING_ARB_L2_ERC20_TOKEN_GATEWAY=0x12dD5832Fd7e02e49d97D1CBBd14579794945c1E - -# ############################ -# Integration Testing -# ############################ - -TESTING_USE_DEPLOYED_CONTRACTS=true -TESTING_L1_TOKENS_HOLDER= - -# ############################ -# E2E Testing -# ############################ - -TESTING_PRIVATE_KEY= diff --git a/.env.wsteth.arb_mainnet b/.env.wsteth.arb_mainnet deleted file mode 100644 index 782ee7a1..00000000 --- a/.env.wsteth.arb_mainnet +++ /dev/null @@ -1,75 +0,0 @@ -# Detailed info: https://github.com/lidofinance/lido-l2#Project-Configuration - -# ############################ -# RPCs -# ############################ - -RPC_ETH_MAINNET= -RPC_ARB_MAINNET= - -# ############################ -# Etherscan -# ############################ - -ETHERSCAN_API_KEY_ETH= -ETHERSCAN_API_KEY_ARB= - -# ############################ -# Bridge/Gateway Deployment -# ############################ - -# Address of the token to deploy the bridge/gateway for -TOKEN=0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0 - -# Name of the network environments used by deployment scripts. -# Might be one of: "mainnet", "goerli". -NETWORK=mainnet - -# Run deployment in the forking network instead of public ones -FORKING=true - -# Private key of the deployer account used for deployment process - -ETH_DEPLOYER_PRIVATE_KEY= -ARB_DEPLOYER_PRIVATE_KEY= - -L1_PROXY_ADMIN=0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c -L1_BRIDGE_ADMIN=0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c -L1_DEPOSITS_ENABLED=false -L1_WITHDRAWALS_ENABLED=true -L1_DEPOSITS_ENABLERS=["0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c","0x3cd9F71F80AB08ea5a7Dca348B5e94BC595f26A0"] -L1_DEPOSITS_DISABLERS=["0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c","0x73b047fe6337183A454c5217241D780a932777bD"] -L1_WITHDRAWALS_ENABLERS=["0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c"] -L1_WITHDRAWALS_DISABLERS=["0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c","0x73b047fe6337183A454c5217241D780a932777bD"] - -L2_PROXY_ADMIN=0x1dcA41859Cd23b526CBe74dA8F48aC96e14B1A29 -L2_BRIDGE_ADMIN=0x1dcA41859Cd23b526CBe74dA8F48aC96e14B1A29 -L2_DEPOSITS_ENABLED=true -L2_WITHDRAWALS_ENABLED=true -L2_DEPOSITS_ENABLERS=["0x1dcA41859Cd23b526CBe74dA8F48aC96e14B1A29"] -L2_DEPOSITS_DISABLERS=["0x1dcA41859Cd23b526CBe74dA8F48aC96e14B1A29","0xfDCf209A213a0b3C403d543F87E74FCbcA11de34"] -L2_WITHDRAWALS_ENABLERS=["0x1dcA41859Cd23b526CBe74dA8F48aC96e14B1A29"] -L2_WITHDRAWALS_DISABLERS=["0x1dcA41859Cd23b526CBe74dA8F48aC96e14B1A29","0xfDCf209A213a0b3C403d543F87E74FCbcA11de34"] - -# ############################ -# Integration Acceptance & E2E Testing -# ############################ - -TESTING_ARB_NETWORK=mainnet -TESTING_ARB_L1_TOKEN=0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0 -TESTING_ARB_L2_TOKEN=0x5979D7b546E38E414F7E9822514be443A4800529 -TESTING_ARB_L1_ERC20_TOKEN_GATEWAY=0x0F25c1DC2a9922304f2eac71DCa9B07E310e8E5a -TESTING_ARB_L2_ERC20_TOKEN_GATEWAY=0x07D4692291B9E30E326fd31706f686f83f331B82 - -# ############################ -# Integration Testing -# ############################ - -TESTING_USE_DEPLOYED_CONTRACTS=true -TESTING_L1_TOKENS_HOLDER= - -# ############################ -# E2E Testing -# ############################ - -TESTING_PRIVATE_KEY= diff --git a/.env.wsteth.opt_goerli b/.env.wsteth.opt_goerli deleted file mode 100644 index 18eb8378..00000000 --- a/.env.wsteth.opt_goerli +++ /dev/null @@ -1,71 +0,0 @@ -# Detailed info: https://github.com/lidofinance/lido-l2#Project-Configuration - -# ############################ -# RPCs -# ############################ - -RPC_ETH_GOERLI= -RPC_OPT_GOERLI=https://goerli.optimism.io - -# ############################ -# Etherscan -# ############################ - -ETHERSCAN_API_KEY_ETH= -ETHERSCAN_API_KEY_OPT= - -# ############################ -# Bridge/Gateway Deployment -# ############################ - -# Address of the token to deploy the bridge/gateway for -TOKEN=0x6320cd32aa674d2898a68ec82e869385fc5f7e2f - -# Name of the network environments used by deployment scripts. -# Might be one of: "mainnet", "goerli". -NETWORK=goerli - -# Private key of the deployer account used for deployment process -ETH_DEPLOYER_PRIVATE_KEY= -OPT_DEPLOYER_PRIVATE_KEY= - -L1_PROXY_ADMIN=0x4333218072D5d7008546737786663c38B4D561A4 -L1_BRIDGE_ADMIN=0x4333218072D5d7008546737786663c38B4D561A4 -L1_DEPOSITS_ENABLED=true -L1_WITHDRAWALS_ENABLED=true -L1_DEPOSITS_ENABLERS=["0x4333218072D5d7008546737786663c38B4D561A4"] -L1_DEPOSITS_DISABLERS="["0x4333218072D5d7008546737786663c38B4D561A4", "0x7fE7fa4EF7D134Dbf8B616Ba7B675F26286BC2cd"]" -L1_WITHDRAWALS_ENABLERS=["0x4333218072D5d7008546737786663c38B4D561A4"] -L1_WITHDRAWALS_DISABLERS="["0x4333218072D5d7008546737786663c38B4D561A4", "0x7fE7fa4EF7D134Dbf8B616Ba7B675F26286BC2cd"]" - -L2_PROXY_ADMIN=0x55C39356C714Cde16F8a80302c1Ce9DfAC6f5a35 -L2_BRIDGE_ADMIN=0x55C39356C714Cde16F8a80302c1Ce9DfAC6f5a35 -L2_DEPOSITS_ENABLED=true -L2_WITHDRAWALS_ENABLED=true -L2_DEPOSITS_ENABLERS=["0x55C39356C714Cde16F8a80302c1Ce9DfAC6f5a35"] -L2_DEPOSITS_DISABLERS="["0x55C39356C714Cde16F8a80302c1Ce9DfAC6f5a35", "0x7fE7fa4EF7D134Dbf8B616Ba7B675F26286BC2cd"]" -L2_WITHDRAWALS_ENABLERS=["0x55C39356C714Cde16F8a80302c1Ce9DfAC6f5a35"] -L2_WITHDRAWALS_DISABLERS="["0x55C39356C714Cde16F8a80302c1Ce9DfAC6f5a35", "0x7fE7fa4EF7D134Dbf8B616Ba7B675F26286BC2cd"]" - -# ############################ -# Integration & E2E Testing -# ############################ - -TESTING_OPT_NETWORK=goerli -TESTING_OPT_L1_TOKEN=0x6320cd32aa674d2898a68ec82e869385fc5f7e2f -TESTING_OPT_L2_TOKEN=0xe8964a99d5DE7cEE2743B20113a52C953b0916E9 -TESTING_OPT_L1_ERC20_TOKEN_BRIDGE=0xDdC89Bd27F9A1C47A5c20dF0783dE52f55513598 -TESTING_OPT_L2_ERC20_TOKEN_BRIDGE=0x423702bC3Fb92f59Be440354456f0481934bF1f5 - -# ############################ -# Integration Testing -# ############################ - -TESTING_USE_DEPLOYED_CONTRACTS=true -TESTING_L1_TOKENS_HOLDER= - -# ############################ -# E2E Testing -# ############################ - -TESTING_PRIVATE_KEY= diff --git a/.env.wsteth.opt_mainnet b/.env.wsteth.opt_mainnet index 6bf3ae55..ed236c7e 100644 --- a/.env.wsteth.opt_mainnet +++ b/.env.wsteth.opt_mainnet @@ -22,7 +22,7 @@ ETHERSCAN_API_KEY_OPT= TOKEN=0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0 # Name of the network environments used by deployment scripts. -# Might be one of: "mainnet", "goerli". +# Might be one of: "mainnet", "sepolia". NETWORK=mainnet # Run deployment in the forking network instead of public ones diff --git a/.github/workflows/verify-bytecode.yml b/.github/workflows/verify-bytecode.yml index a9185fd4..55630fdd 100644 --- a/.github/workflows/verify-bytecode.yml +++ b/.github/workflows/verify-bytecode.yml @@ -49,9 +49,3 @@ jobs: file: artifacts-opt.json rpcUrl: ${{ secrets.OPTIMISM_RPC }} - - name: Verify bytecode of contracts on Arbitrum chain - uses: lidofinance/action-verify-bytecode@master - if: always() - with: - file: artifacts-arb.json - rpcUrl: ${{ secrets.ARBITRUM_RPC }} diff --git a/.solcover.js b/.solcover.js index 7554c821..108d686a 100644 --- a/.solcover.js +++ b/.solcover.js @@ -1,3 +1,3 @@ module.exports = { - skipFiles: ["stubs", "optimism/stubs", "proxy/stubs", "arbitrum/stubs"], + skipFiles: ["stubs", "optimism/stubs", "proxy/stubs"], }; diff --git a/README.md b/README.md index 5f9ca478..a623b4ce 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,9 @@ # Lido L2 -This project contains the implementations of the L2 ERC20 token bridges for Arbitrum and Optimism chains. The current solution allows transferring ERC20 tokens between L1 and L2 chains. +This project contains the implementations of the L2 ERC20 token bridge for Optimism chain. The current solution allows transferring ERC20 tokens between L1 and L2 chains. To retrieve more detailed info about the bridging process, see the specifications for certain chains: -- [Lido's Arbitrum Gateway](https://github.com/lidofinance/lido-l2/blob/main/contracts/arbitrum/README.md). - [Lido's Optimism Bridge](https://github.com/lidofinance/lido-l2/blob/main/contracts/optimism/README.md). ## Project setup @@ -43,11 +42,10 @@ Fill the newly created `.env` file with the required variables. See the [Project The configuration of the deployment scripts happens via the ENV variables. The following variables are required: - [`TOKEN`](#TOKEN) - address of the token to deploy a new bridge on the Ethereum chain. -- [`NETWORK`](#NETWORK) - name of the network environments used by deployment scripts. Allowed values: `mainnet`, `goerli`. +- [`NETWORK`](#NETWORK) - name of the network environments used by deployment scripts. Allowed values: `mainnet`, `sepolia`. - [`FORKING`](#FORKING) - run deployment in the forking network instead of real ones - [`ETH_DEPLOYER_PRIVATE_KEY`](#ETH_DEPLOYER_PRIVATE_KEY) - The private key of the deployer account in the Ethereum network is used during the deployment process. -- [`ARB_DEPLOYER_PRIVATE_KEY`](#ARB_DEPLOYER_PRIVATE_KEY) - The private key of the deployer account in the Arbitrum network is used during the deployment process. -- [`OPT_DEPLOYER_PRIVATE_KEY`](#ARB_DEPLOYER_PRIVATE_KEY) - The private key of the deployer account in the Optimism network is used during the deployment process. +- [`OPT_DEPLOYER_PRIVATE_KEY`](#OPT_DEPLOYER_PRIVATE_KEY) - The private key of the deployer account in the Optimism network is used during the deployment process. - [`L1_PROXY_ADMIN`](#L1_PROXY_ADMIN) - The address to grant admin rights of the `OssifiableProxy` on the L1 bridge - [`L1_BRIDGE_ADMIN`](#L1_BRIDGE_ADMIN) - Address to grant the `DEFAULT_ADMIN_ROLE` on the L1 bridge - [`L2_PROXY_ADMIN`](#L2_PROXY_ADMIN) - The address to grant admin rights of the `OssifiableProxy` on the L2 bridge @@ -68,14 +66,6 @@ The following ENV variables are optional and might be used to make an additional - [`L2_WITHDRAWALS_ENABLERS`](#L2_WITHDRAWALS_ENABLES) - array of addresses to grant `WITHDRAWALS_ENABLER_ROLE` on the L2 bridge. - [`L2_WITHDRAWALS_DISABLERS`](#L2_WITHDRAWALS_DISABLERS) - array of addresses to grant `WITHDRAWALS_DISABLER_ROLE` on the L2 bridge. -### Deploying Arbitrum gateway - -To run the deployment of the ERC20 token gateway for the Ethereum <-> Arbitrum chains use the following command: - -```bash -npm run arbitrum:deploy -``` - ### Deploying Optimism bridge To run the deployment of the ERC20 token gateway for the Ethereum <-> Optimism chains use the following command: @@ -92,40 +82,30 @@ To run unit tests use one of the following commands: ```bash -# Run tests for both Arbitrum and Optimism bridges +# Run tests for Optimism bridge npm run test:unit -# Run tests only for Arbitrum gateway -npm run arbitrum:test:unit - # Run tests only for Optimism bridge npm run optimism:test:unit ``` ### Integration tests -Before running integration tests, run the hardhat forked nodes in the standalone tabs corresponding to `TESTING_ARB_NETWORK` \ `TESTING_OPT_NETWORK` env variable or if it's not set use `mainnet` network. Example of the commands for the `mainnet` network: +Before running integration tests, run the hardhat forked nodes in the standalone tabs corresponding to `TESTING_OPT_NETWORK` env variable or if it's not set use `mainnet` network. Example of the commands for the `mainnet` network: ```bash -# Required to run both Arbitrum and Optimism integraton tests +# Required to run Optimism integraton tests npm run fork:eth:mainnet # Required to run Optimism integration tests npm run fork:opt:mainnet -# Required to run Arbitrum integration tests -npm run fork:arb:mainnet -``` - The integration tests might be run via the following commands: ```bash -# Run integration tests for both Arbitrum and Optimism bridges +# Run integration tests for Optimism bridge npm run test:integration -# Run integration tests for Arbitrum bridge -npm run arbitrum:test:integration - # Run integration tests for Optimism bridge npm run optimism:test:integration ``` @@ -138,17 +118,6 @@ TESTING_USE_DEPLOYED_CONTRACTS=true # Address of the account which has tokens to test TESTING_L1_TOKENS_HOLDER= -# Addresses of the Arbitrum gateway -TESTING_ARB_NETWORK= -TESTING_ARB_L1_TOKEN= -TESTING_ARB_L2_TOKEN= -TESTING_ARB_L1_ERC20_TOKEN_GATEWAY= -TESTING_ARB_L2_ERC20_TOKEN_GATEWAY= - -# Below addresses are not required when the gateway uses the default Arbitrum router -TESTING_ARB_L1_GATEWAY_ROUTER= -TESTING_ARB_L2_GATEWAY_ROUTER= - # Addresses of the Optimism bridge TESTING_OPT_NETWORK= TESTING_OPT_L1_TOKEN= @@ -163,17 +132,13 @@ E2E tests run on the real contracts deployed on the testnet networks. To run suc [`TESTING_PRIVATE_KEY`](#TESTING_PRIVATE_KEY) [`TESTING_OPT_LDO_HOLDER_PRIVATE_KEY`](#TESTING_OPT_LDO_HOLDER_PRIVATE_KEY) -[`TESTING_ARB_LDO_HOLDER_PRIVATE_KEY`](#TESTING_ARB_LDO_HOLDER_PRIVATE_KEY) To run E2E tests use the following commands: ```bash -# Run E2E tests for both Arbitrum and Optimism bridges +# Run E2E tests for Optimism bridge npm run test:e2e -# Run E2E tests for Arbitrum bridge -npm run arbitrum:test:e2e - # Run E2E tests for Optimism bridge npm run optimism:test:e2e ``` @@ -184,17 +149,6 @@ Additionally, tests might be run on the deployed contracts. To do it, set the fo # private key of the tester. It must have tokens for testing TESTING_PRIVATE_KEY= -# Addresses of the Arbitrum gateway -TESTING_ARB_NETWORK= -TESTING_ARB_L1_TOKEN= -TESTING_ARB_L2_TOKEN= -TESTING_ARB_L1_ERC20_TOKEN_GATEWAY= -TESTING_ARB_L2_ERC20_TOKEN_GATEWAY= - -# Below addresses are not required when the gateway uses the default Arbitrum router -TESTING_ARB_L1_GATEWAY_ROUTER= -TESTING_ARB_L2_GATEWAY_ROUTER= - # Addresses of the Optimism bridge TESTING_OPT_NETWORK= TESTING_OPT_L1_TOKEN= @@ -210,16 +164,6 @@ The acceptance tests might be run after the deployment to validate that the brid The following ENV variables must be set before the tests running: ```bash -# Addresses of the Arbitrum gateway -TESTING_ARB_L1_TOKEN= -TESTING_ARB_L2_TOKEN= -TESTING_ARB_L1_ERC20_TOKEN_GATEWAY= -TESTING_ARB_L2_ERC20_TOKEN_GATEWAY= - -# Below addresses are not required when the gateway uses the default Arbitrum router -TESTING_ARB_L1_GATEWAY_ROUTER= -TESTING_ARB_L2_GATEWAY_ROUTER= - # Addresses of the Optimism bridge TESTING_OPT_L1_TOKEN= TESTING_OPT_L2_TOKEN= @@ -232,9 +176,6 @@ To run the acceptance tests, use the following commands: ```bash # Optimism bridge npm run optimism:test:acceptance - -# Arbitrum bridge -npm run arbitrum:test:acceptance ``` ## Code Coverage @@ -255,31 +196,13 @@ The configuration of the project happens via set of ENV variables. The full list Address of the RPC node for **Mainnet** Ethereum network. -#### `RPC_ETH_GOERLI` - -Address of the RPC node for **Goerli** Ethereum network. - -#### `RPC_ARB_MAINNET` - -> **Warning** -> -> Please, don't use the default value for production deployments! The default RPC node might not be available or fail suddenly during the request. - -Address of the RPC node for **Mainnet** Arbitrum network. - -> Default value: `https://arb1.arbitrum.io/rpc` - -#### `RPC_ARB_GOERLI` - -Address of the RPC node for **Goerli** Arbitrum network. +#### `RPC_ETH_SEPOLIA` -> Default value: `https://goerli-rollup.arbitrum.io/rpc` +Address of the RPC node for **Sepolia** Ethereum network. -#### `RPC_OPT_GOERLI` +#### `RPC_OPT_SEPOLIA` -Address of the RPC node for **Goerli** Optimism network. - -> Default value: `https://goerli-rollup.arbitrum.io/rpc` +Address of the RPC node for **Sepolia** Optimism network. #### `RPC_OPT_MAINNET` @@ -300,9 +223,6 @@ Below variables are required for successfull verification of the contracts on bl API key from the [Etherscan](https://etherscan.io/) block explorer. See details here: https://info.etherscan.com/api-keys/ -#### `ETHERSCAN_API_KEY_ARB` - -API key from the [Arbiscan](https://arbiscan.io/) block explorer. #### `ETHERSCAN_API_KEY_OPT` @@ -310,7 +230,7 @@ API key from the [Optimistic Ethereum](https://optimistic.etherscan.io/) block e ### Bridge/Gateway Deployment -Below variables used in the Arbitrum/Optimism bridge deployment process. +Below variables used in the Optimism bridge deployment process. #### `TOKEN` @@ -320,7 +240,7 @@ Address of the token to deploy a new bridge on the Ethereum chain. > Default value: `mainnet` -Name of the network environments used by deployment scripts. Might be one of: `mainnet`, `goerli`. +Name of the network environments used by deployment scripts. Might be one of: `mainnet`, `sepolia`. #### `FORKING` @@ -332,10 +252,6 @@ Run deployment in the forking network instead of public ones The private key of the deployer account in the Ethereum network is used during the deployment process. -#### `ARB_DEPLOYER_PRIVATE_KEY` - -The private key of the deployer account in the Arbitrum network is used during the deployment process. - #### `OPT_DEPLOYER_PRIVATE_KEY` The private key of the deployer account in the Optimism network is used during the deployment process. @@ -440,49 +356,9 @@ The array of addresses to grant `WITHDRAWALS_DISABLER_ROLE` on L2 bridge/gateway The following variables are used in the process of the Integration & E2E testing. -#### `TESTING_ARB_NETWORK` - -Name of the network environments used for Arbitrum Integration & E2E testing. Might be one of: `mainnet`, `goerli`. - -#### `TESTING_ARB_L1_TOKEN` - -Address of the token to use in the Acceptance Integration & E2E (when `TESTING_USE_DEPLOYED_CONTRACTS` is set to true) testing of the bridging between Ethereum and Arbitrum networks. - -> Default value: `0x7AEE39c46f20135114e85A03C02aB4FE73fB8127` - -#### `TESTING_ARB_L2_TOKEN` - -Address of the token minted on L2 in the Acceptance Integration & E2E (when `TESTING_USE_DEPLOYED_CONTRACTS` is set to true) testing of the bridging between Ethereum and Arbitrum networks. - -> Default value: `0x775ede8029C117effce283b3391E420EacF3c85F` - -#### `TESTING_ARB_L1_ERC20_TOKEN_GATEWAY` - -Address of the L1 ERC20 token gateway used in the Acceptance Integration & E2E (when `TESTING_USE_DEPLOYED_CONTRACTS` is set to true) testing of the bridging between Ethereum and Arbitrum networks. - -> Default value: `0x0A7e12b563Ba623646a31a09F0182e8aD45D6cfD` - -#### `TESTING_ARB_L2_ERC20_TOKEN_GATEWAY` - -Address of the L2 ERC20 token gateway used in the Acceptance Integration & E2E (when `TESTING_USE_DEPLOYED_CONTRACTS` is set to true) testing of the bridging between Ethereum and Arbitrum networks. - -> Default value: `0x8c269989D839eE9DaEe64D57C8c41404DF87F722` - -#### `TESTING_ARB_L1_GATEWAY_ROUTER` - -Address of the L1 gateway router used in the Acceptance Integration & E2E (when `TESTING_USE_DEPLOYED_CONTRACTS` is set to true) testing of the bridging between Ethereum and Arbitrum networks. If not set, will be used default Arbitrum's L1 Gateway Router - -> Default value: `0xa2a8F940752aDc4A3278B63B96d56D72D2b075B1` - -#### `TESTING_ARB_L2_GATEWAY_ROUTER` - -Address of the L2 gateway router used in the Acceptance Integration & E2E (when `TESTING_USE_DEPLOYED_CONTRACTS` is set to true) testing of the bridging between Ethereum and Arbitrum networks. If not set, will be used default Arbitrum's L2 Gateway Router - -> Default value: `0x57f54f87C44d816f60b92864e23b8c0897D4d81D` - #### `TESTING_OPT_NETWORK` -Name of the network environments used for Optimism Integration & E2E testing. Might be one of: `mainnet`, `goerli`. +Name of the network environments used for Optimism Integration & E2E testing. Might be one of: `mainnet`, `sepolia`. #### `TESTING_OPT_L1_TOKEN` @@ -518,10 +394,6 @@ When set to `true` integration tests will use addresses of deployed contracts se When `TESTING_USE_DEPLOYED_CONTRACTS` is set to true, this address will be used as the holder of the tokens, bridged between L1 and L2. -#### `TESTING_ARB_GOV_BRIDGE_EXECUTOR` - -Address of the deployed Governance Bridge Executor in the Arbitrum network. If set, this contract will be used for integration tests of Governance Bridge. - #### `TESTING_OPT_GOV_BRIDGE_EXECUTOR` Address of the deployed Governance Bridge Executor in the Optimism network. If set, this contract will be used for integration tests of Governance Bridge. @@ -532,7 +404,7 @@ Address of the deployed Governance Bridge Executor in the Optimism network. If s The private key from the address which holds: -- Goerli and Arbitrum/Optimistic Goerli Ether to launch Arbitrum/Optimism E2E tests +- Sepolia and Optimistic Sepolia Ether to launch Optimism E2E tests The test Ether might be retrived via [Paradigm Faucet](https://faucet.paradigm.xyz/). @@ -540,6 +412,3 @@ The test Ether might be retrived via [Paradigm Faucet](https://faucet.paradigm.x The private key from the address which holds 50+% TLDO -#### `TESTING_ARB_LDO_HOLDER_PRIVATE_KEY` - -The private key from the address which holds 50+% TLDO diff --git a/abi/arbitrum/L1GatewayRouter.json b/abi/arbitrum/L1GatewayRouter.json deleted file mode 100644 index c3fd4bcf..00000000 --- a/abi/arbitrum/L1GatewayRouter.json +++ /dev/null @@ -1,362 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newDefaultGateway", - "type": "address" - } - ], - "name": "DefaultGatewayUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "l1Token", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "gateway", - "type": "address" - } - ], - "name": "GatewaySet", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "_userFrom", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "_userTo", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "gateway", - "type": "address" - } - ], - "name": "TransferRouted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "_from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "_to", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "_seqNum", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "name": "TxToL2", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newSource", - "type": "address" - } - ], - "name": "WhitelistSourceUpdated", - "type": "event" - }, - { - "inputs": [ - { "internalType": "address", "name": "l1ERC20", "type": "address" } - ], - "name": "calculateL2TokenAddress", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "counterpartGateway", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "defaultGateway", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "", "type": "address" }, - { "internalType": "address", "name": "", "type": "address" }, - { "internalType": "address", "name": "", "type": "address" }, - { "internalType": "uint256", "name": "", "type": "uint256" }, - { "internalType": "bytes", "name": "", "type": "bytes" } - ], - "name": "finalizeInboundTransfer", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "_token", "type": "address" } - ], - "name": "getGateway", - "outputs": [ - { "internalType": "address", "name": "gateway", "type": "address" } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "_token", "type": "address" }, - { "internalType": "address", "name": "_from", "type": "address" }, - { "internalType": "address", "name": "_to", "type": "address" }, - { "internalType": "uint256", "name": "_amount", "type": "uint256" }, - { "internalType": "bytes", "name": "_data", "type": "bytes" } - ], - "name": "getOutboundCalldata", - "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "inbox", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "_owner", "type": "address" }, - { - "internalType": "address", - "name": "_defaultGateway", - "type": "address" - }, - { "internalType": "address", "name": "", "type": "address" }, - { - "internalType": "address", - "name": "_counterpartGateway", - "type": "address" - }, - { "internalType": "address", "name": "_inbox", "type": "address" } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "", "type": "address" }], - "name": "l1TokenToGateway", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "_token", "type": "address" }, - { "internalType": "address", "name": "_to", "type": "address" }, - { "internalType": "uint256", "name": "_amount", "type": "uint256" }, - { "internalType": "uint256", "name": "_maxGas", "type": "uint256" }, - { "internalType": "uint256", "name": "_gasPriceBid", "type": "uint256" }, - { "internalType": "bytes", "name": "_data", "type": "bytes" } - ], - "name": "outboundTransfer", - "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "_token", "type": "address" }, - { "internalType": "address", "name": "_refundTo", "type": "address" }, - { "internalType": "address", "name": "_to", "type": "address" }, - { "internalType": "uint256", "name": "_amount", "type": "uint256" }, - { "internalType": "uint256", "name": "_maxGas", "type": "uint256" }, - { "internalType": "uint256", "name": "_gasPriceBid", "type": "uint256" }, - { "internalType": "bytes", "name": "_data", "type": "bytes" } - ], - "name": "outboundTransferCustomRefund", - "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "postUpgradeInit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "router", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newL1DefaultGateway", - "type": "address" - }, - { "internalType": "uint256", "name": "_maxGas", "type": "uint256" }, - { "internalType": "uint256", "name": "_gasPriceBid", "type": "uint256" }, - { - "internalType": "uint256", - "name": "_maxSubmissionCost", - "type": "uint256" - } - ], - "name": "setDefaultGateway", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "_gateway", "type": "address" }, - { "internalType": "uint256", "name": "_maxGas", "type": "uint256" }, - { "internalType": "uint256", "name": "_gasPriceBid", "type": "uint256" }, - { - "internalType": "uint256", - "name": "_maxSubmissionCost", - "type": "uint256" - }, - { - "internalType": "address", - "name": "_creditBackAddress", - "type": "address" - } - ], - "name": "setGateway", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "_gateway", "type": "address" }, - { "internalType": "uint256", "name": "_maxGas", "type": "uint256" }, - { "internalType": "uint256", "name": "_gasPriceBid", "type": "uint256" }, - { - "internalType": "uint256", - "name": "_maxSubmissionCost", - "type": "uint256" - } - ], - "name": "setGateway", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address[]", "name": "_token", "type": "address[]" }, - { "internalType": "address[]", "name": "_gateway", "type": "address[]" }, - { "internalType": "uint256", "name": "_maxGas", "type": "uint256" }, - { "internalType": "uint256", "name": "_gasPriceBid", "type": "uint256" }, - { - "internalType": "uint256", - "name": "_maxSubmissionCost", - "type": "uint256" - } - ], - "name": "setGateways", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "newOwner", "type": "address" } - ], - "name": "setOwner", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "bytes4", "name": "interfaceId", "type": "bytes4" } - ], - "name": "supportsInterface", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "newSource", "type": "address" } - ], - "name": "updateWhitelistSource", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "whitelist", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - } -] diff --git a/abi/arbitrum/L2GatewayRouter.json b/abi/arbitrum/L2GatewayRouter.json deleted file mode 100644 index c03fa729..00000000 --- a/abi/arbitrum/L2GatewayRouter.json +++ /dev/null @@ -1,244 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newDefaultGateway", - "type": "address" - } - ], - "name": "DefaultGatewayUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "l1Token", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "gateway", - "type": "address" - } - ], - "name": "GatewaySet", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "_userFrom", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "_userTo", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "gateway", - "type": "address" - } - ], - "name": "TransferRouted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "_from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "_to", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "_id", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "name": "TxToL1", - "type": "event" - }, - { - "inputs": [ - { "internalType": "address", "name": "l1ERC20", "type": "address" } - ], - "name": "calculateL2TokenAddress", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "counterpartGateway", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "defaultGateway", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "", "type": "address" }, - { "internalType": "address", "name": "", "type": "address" }, - { "internalType": "address", "name": "", "type": "address" }, - { "internalType": "uint256", "name": "", "type": "uint256" }, - { "internalType": "bytes", "name": "", "type": "bytes" } - ], - "name": "finalizeInboundTransfer", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "_token", "type": "address" } - ], - "name": "getGateway", - "outputs": [ - { "internalType": "address", "name": "gateway", "type": "address" } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "_token", "type": "address" }, - { "internalType": "address", "name": "_from", "type": "address" }, - { "internalType": "address", "name": "_to", "type": "address" }, - { "internalType": "uint256", "name": "_amount", "type": "uint256" }, - { "internalType": "bytes", "name": "_data", "type": "bytes" } - ], - "name": "getOutboundCalldata", - "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_counterpartGateway", - "type": "address" - }, - { - "internalType": "address", - "name": "_defaultGateway", - "type": "address" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "", "type": "address" }], - "name": "l1TokenToGateway", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "_l1Token", "type": "address" }, - { "internalType": "address", "name": "_to", "type": "address" }, - { "internalType": "uint256", "name": "_amount", "type": "uint256" }, - { "internalType": "bytes", "name": "_data", "type": "bytes" } - ], - "name": "outboundTransfer", - "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "_token", "type": "address" }, - { "internalType": "address", "name": "_to", "type": "address" }, - { "internalType": "uint256", "name": "_amount", "type": "uint256" }, - { "internalType": "uint256", "name": "_maxGas", "type": "uint256" }, - { "internalType": "uint256", "name": "_gasPriceBid", "type": "uint256" }, - { "internalType": "bytes", "name": "_data", "type": "bytes" } - ], - "name": "outboundTransfer", - "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "postUpgradeInit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "router", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newL2DefaultGateway", - "type": "address" - } - ], - "name": "setDefaultGateway", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address[]", "name": "_l1Token", "type": "address[]" }, - { "internalType": "address[]", "name": "_gateway", "type": "address[]" } - ], - "name": "setGateway", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/artifacts-arb.json b/artifacts-arb.json deleted file mode 100644 index d27f07ba..00000000 --- a/artifacts-arb.json +++ /dev/null @@ -1,28 +0,0 @@ -[ - { - "artifactPath": "artifacts/contracts/proxy/OssifiableProxy.sol/OssifiableProxy.json", - "sourcePath": "contracts/proxy/OssifiableProxy.sol", - "name": "L2ERC20TokenGateway proxy", - "address": "0x07D4692291B9E30E326fd31706f686f83f331B82" - }, - { - "artifactPath": "artifacts/contracts/arbitrum/L2ERC20TokenGateway.sol/L2ERC20TokenGateway.json", - "sourcePath": "contracts/arbitrum/L2ERC20TokenGateway.sol", - "name": "L2ERC20TokenGateway", - "address": "0xe75886DE20dF66827e321EfdB88726e6Baa4b0A7", - "txHash": "0xe99cd25baf61300dcf57466bead148dac28fd975076593a8874bbdc64973696d" - }, - { - "artifactPath": "artifacts/contracts/proxy/OssifiableProxy.sol/OssifiableProxy.json", - "sourcePath": "contracts/proxy/OssifiableProxy.sol", - "name": "WstETH ERC20Bridged proxy", - "address": "0x5979D7b546E38E414F7E9822514be443A4800529" - }, - { - "artifactPath": "artifacts/contracts/token/ERC20Bridged.sol/ERC20Bridged.json", - "sourcePath": "contracts/token/ERC20Bridged.sol", - "name": "WstETH ERC20Bridged", - "address": "0x0fBcbaEA96Ce0cF7Ee00A8c19c3ab6f5Dc8E1921", - "txHash": "0x517ea5c206473d2116324939ab42f93ca1079a6388c0db41684e926e36e1a411" - } -] diff --git a/artifacts-eth.json b/artifacts-eth.json index 24dd4b91..c6f6ab47 100644 --- a/artifacts-eth.json +++ b/artifacts-eth.json @@ -1,18 +1,4 @@ [ - { - "artifactPath": "artifacts/contracts/proxy/OssifiableProxy.sol/OssifiableProxy.json", - "sourcePath": "contracts/proxy/OssifiableProxy.sol", - "name": "L1ERC20TokenGateway proxy", - "address": "0x0F25c1DC2a9922304f2eac71DCa9B07E310e8E5a", - "txHash": "0x912fc5992f5a24c2ffe5e230ac51fcc4724cb3e4a23535b04eec34f99f77e3a8" - }, - { - "artifactPath": "artifacts/contracts/arbitrum/L1ERC20TokenGateway.sol/L1ERC20TokenGateway.json", - "sourcePath": "contracts/arbitrum/L1ERC20TokenGateway.sol", - "name": "L1ERC20TokenGateway", - "address": "0xc4E3ff0b5B106f88Fc64c43031BE8b076ee9F21C", - "txHash": "0xce43376cd317471806c6ac2a8efbd5dc6dcfb7201ba643e447f446e50354edcf" - }, { "artifactPath": "artifacts/contracts/proxy/OssifiableProxy.sol/OssifiableProxy.json", "sourcePath": "contracts/proxy/OssifiableProxy.sol", diff --git a/contracts/arbitrum/InterchainERC20TokenGateway.sol b/contracts/arbitrum/InterchainERC20TokenGateway.sol deleted file mode 100644 index 329f4c87..00000000 --- a/contracts/arbitrum/InterchainERC20TokenGateway.sol +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Lido -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity 0.8.10; - -import {BridgingManager} from "../BridgingManager.sol"; -import {BridgeableTokens} from "../BridgeableTokens.sol"; - -import {IInterchainTokenGateway} from "./interfaces/IInterchainTokenGateway.sol"; - -/// @author psirex -/// @notice The contract keeps logic shared among both L1 and L2 gateways, adding the methods for -/// bridging management: enabling and disabling withdrawals/deposits -abstract contract InterchainERC20TokenGateway is - BridgingManager, - BridgeableTokens, - IInterchainTokenGateway -{ - /// @notice Address of the router in the corresponding chain - address public immutable router; - - /// @inheritdoc IInterchainTokenGateway - address public immutable counterpartGateway; - - /// @param router_ Address of the router in the corresponding chain - /// @param counterpartGateway_ Address of the counterpart gateway used in the bridging process - /// @param l1Token_ Address of the bridged token in the Ethereum chain - /// @param l2Token_ Address of the token minted on the Arbitrum chain when token bridged - constructor( - address router_, - address counterpartGateway_, - address l1Token_, - address l2Token_ - ) BridgeableTokens(l1Token_, l2Token_) { - router = router_; - counterpartGateway = counterpartGateway_; - } - - /// @inheritdoc IInterchainTokenGateway - /// @dev The current implementation returns the l2Token address when passed l1Token_ equals - /// to l1Token declared in the contract and address(0) in other cases - function calculateL2TokenAddress(address l1Token_) - external - view - returns (address) - { - if (l1Token_ == l1Token) { - return l2Token; - } - return address(0); - } - - /// @inheritdoc IInterchainTokenGateway - function getOutboundCalldata( - address l1Token_, - address from_, - address to_, - uint256 amount_, - bytes memory // data_ - ) public pure returns (bytes memory) { - return - abi.encodeWithSelector( - IInterchainTokenGateway.finalizeInboundTransfer.selector, - l1Token_, - from_, - to_, - amount_, - "" - ); - } -} diff --git a/contracts/arbitrum/L1CrossDomainEnabled.sol b/contracts/arbitrum/L1CrossDomainEnabled.sol deleted file mode 100644 index 5a7b4e06..00000000 --- a/contracts/arbitrum/L1CrossDomainEnabled.sol +++ /dev/null @@ -1,104 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Lido -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity 0.8.10; - -import {IInbox} from "./interfaces/IInbox.sol"; -import {IBridge} from "./interfaces/IBridge.sol"; -import {IOutbox} from "./interfaces/IOutbox.sol"; - -/// @author psirex -/// @notice A helper contract to simplify Ethereum to Arbitrum communication process process -/// via Retryable Tickets -contract L1CrossDomainEnabled { - /// @notice Address of the Arbitrum's Inbox contract - IInbox public immutable inbox; - - /// @param inbox_ Address of the Arbitrum's Inbox contract - constructor(address inbox_) { - inbox = IInbox(inbox_); - } - - /// @dev Properties required to create RetryableTicket - /// @param maxGas Gas limit for immediate L2 execution attempt - /// @param callValue Call-value for L2 transaction - /// @param gasPriceBid L2 Gas price bid for immediate L2 execution attempt - /// @param maxSubmissionCost Amount of ETH allocated to pay for the base submission fee - struct CrossDomainMessageOptions { - uint256 maxGas; - uint256 callValue; - uint256 gasPriceBid; - uint256 maxSubmissionCost; - } - - /// @notice Creates a Retryable Ticket via Inbox.createRetryableTicket function using - /// the provided arguments - /// @param sender_ Address of the sender of the message - /// @param recipient_ Address of the recipient of the message on the L2 chain - /// @param data_ Data passed to the recipient_ in the message - /// @param msgOptions_ Instance of the `CrossDomainMessageOptions` struct - /// @return seqNum Unique id of created Retryable Ticket. - function sendCrossDomainMessage( - address sender_, - address recipient_, - bytes memory data_, - CrossDomainMessageOptions memory msgOptions_ - ) internal returns (uint256 seqNum) { - if (msgOptions_.maxSubmissionCost == 0) { - revert ErrorNoMaxSubmissionCost(); - } - - uint256 minEthValue = msgOptions_.callValue + - msgOptions_.maxSubmissionCost + - (msgOptions_.maxGas * msgOptions_.gasPriceBid); - - if (msg.value < minEthValue) { - revert ErrorETHValueTooLow(); - } - - seqNum = inbox.createRetryableTicket{value: msg.value}( - recipient_, - msgOptions_.callValue, - msgOptions_.maxSubmissionCost, - sender_, - sender_, - msgOptions_.maxGas, - msgOptions_.gasPriceBid, - data_ - ); - - emit TxToL2(sender_, recipient_, seqNum, data_); - } - - /// @notice Validates that transaction was initiated by the crossDomainAccount_ address from - /// the L2 chain - modifier onlyFromCrossDomainAccount(address crossDomainAccount_) { - address bridge = inbox.bridge(); - - // a message coming from the counterpart gateway was executed by the bridge - if (msg.sender != bridge) { - revert ErrorUnauthorizedBridge(); - } - - address l2ToL1Sender = IOutbox(IBridge(bridge).activeOutbox()) - .l2ToL1Sender(); - - // and the outbox reports that the L2 address of the sender is the counterpart gateway - if (l2ToL1Sender != crossDomainAccount_) { - revert ErrorWrongCrossDomainSender(); - } - _; - } - - event TxToL2( - address indexed from, - address indexed to, - uint256 indexed seqNum, - bytes data - ); - - error ErrorETHValueTooLow(); - error ErrorUnauthorizedBridge(); - error ErrorNoMaxSubmissionCost(); - error ErrorWrongCrossDomainSender(); -} diff --git a/contracts/arbitrum/L1ERC20TokenGateway.sol b/contracts/arbitrum/L1ERC20TokenGateway.sol deleted file mode 100644 index 1be951aa..00000000 --- a/contracts/arbitrum/L1ERC20TokenGateway.sol +++ /dev/null @@ -1,120 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Lido -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity 0.8.10; - -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; - -import {IL1TokenGateway, IInterchainTokenGateway} from "./interfaces/IL1TokenGateway.sol"; - -import {L1CrossDomainEnabled} from "./L1CrossDomainEnabled.sol"; -import {L1OutboundDataParser} from "./libraries/L1OutboundDataParser.sol"; -import {InterchainERC20TokenGateway} from "./InterchainERC20TokenGateway.sol"; - -/// @author psirex -/// @notice Contract implements ITokenGateway interface and with counterpart L2ERC20TokenGatewy -/// allows bridging registered ERC20 compatible tokens between Ethereum and Arbitrum chains -contract L1ERC20TokenGateway is - InterchainERC20TokenGateway, - L1CrossDomainEnabled, - IL1TokenGateway -{ - using SafeERC20 for IERC20; - - /// @param inbox_ Address of the Arbitrum’s Inbox contract in the L1 chain - /// @param router_ Address of the router in the L1 chain - /// @param counterpartGateway_ Address of the counterpart L2 gateway - /// @param l1Token_ Address of the bridged token in the L1 chain - /// @param l2Token_ Address of the token minted on the Arbitrum chain when token bridged - constructor( - address inbox_, - address router_, - address counterpartGateway_, - address l1Token_, - address l2Token_ - ) - InterchainERC20TokenGateway( - router_, - counterpartGateway_, - l1Token_, - l2Token_ - ) - L1CrossDomainEnabled(inbox_) - {} - - /// @inheritdoc IL1TokenGateway - function outboundTransfer( - address l1Token_, - address to_, - uint256 amount_, - uint256 maxGas_, - uint256 gasPriceBid_, - bytes calldata data_ - ) - external - payable - whenDepositsEnabled - onlyNonZeroAccount(to_) - onlySupportedL1Token(l1Token_) - returns (bytes memory) - { - (address from, uint256 maxSubmissionCost) = L1OutboundDataParser.decode( - router, - data_ - ); - - IERC20(l1Token_).safeTransferFrom(from, address(this), amount_); - - uint256 retryableTicketId = _sendOutboundTransferMessage( - from, - to_, - amount_, - CrossDomainMessageOptions({ - maxGas: maxGas_, - callValue: 0, - gasPriceBid: gasPriceBid_, - maxSubmissionCost: maxSubmissionCost - }) - ); - - emit DepositInitiated(l1Token, from, to_, retryableTicketId, amount_); - - return abi.encode(retryableTicketId); - } - - /// @inheritdoc IInterchainTokenGateway - function finalizeInboundTransfer( - address l1Token_, - address from_, - address to_, - uint256 amount_, - bytes calldata // data_ - ) - external - whenWithdrawalsEnabled - onlySupportedL1Token(l1Token_) - onlyFromCrossDomainAccount(counterpartGateway) - { - IERC20(l1Token_).safeTransfer(to_, amount_); - - // The current implementation doesn't support fast withdrawals, so we - // always use 0 for the exitNum argument in the event - emit WithdrawalFinalized(l1Token_, from_, to_, 0, amount_); - } - - function _sendOutboundTransferMessage( - address from_, - address to_, - uint256 amount_, - CrossDomainMessageOptions memory messageOptions - ) private returns (uint256) { - return - sendCrossDomainMessage( - from_, - counterpartGateway, - getOutboundCalldata(l1Token, from_, to_, amount_, ""), - messageOptions - ); - } -} diff --git a/contracts/arbitrum/L2CrossDomainEnabled.sol b/contracts/arbitrum/L2CrossDomainEnabled.sol deleted file mode 100644 index b3ec7fea..00000000 --- a/contracts/arbitrum/L2CrossDomainEnabled.sol +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Lido -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity 0.8.10; - -import {IArbSys} from "./interfaces/IArbSys.sol"; - -/// @author psirex -/// @notice A helper contract to simplify Arbitrum to Ethereum communication process -contract L2CrossDomainEnabled { - uint160 private constant ADDRESS_OFFSET = - uint160(0x1111000000000000000000000000000000001111); - - /// @notice Address of the Arbitrum’s ArbSys contract - IArbSys public immutable arbSys; - - /// @param arbSys_ Address of the Arbitrum’s ArbSys contract - constructor(address arbSys_) { - arbSys = IArbSys(arbSys_); - } - - /// @notice Sends the message to the Ethereum chain - /// @param sender_ Address of the sender of the message - /// @param recipient_ Address of the recipient of the message on the Ethereum chain - /// @param data_ Data passed to the recipient in the message - /// @return id Unique identifier for this L2-to-L1 transaction - function sendCrossDomainMessage( - address sender_, - address recipient_, - bytes memory data_ - ) internal returns (uint256 id) { - id = IArbSys(arbSys).sendTxToL1(recipient_, data_); - emit TxToL1(sender_, recipient_, id, data_); - } - - /// @dev L1 addresses are transformed durng l1 -> l2 calls - function applyL1ToL2Alias(address l1Address_) - private - pure - returns (address l1Address) - { - unchecked { - l1Address = address(uint160(l1Address_) + ADDRESS_OFFSET); - } - } - - /// @notice Validates that the sender address with applied Arbitrum's aliasing is equal to - /// the crossDomainAccount_ address - modifier onlyFromCrossDomainAccount(address crossDomainAccount_) { - if (msg.sender != applyL1ToL2Alias(crossDomainAccount_)) { - revert ErrorWrongCrossDomainSender(); - } - _; - } - - event TxToL1( - address indexed from, - address indexed to, - uint256 indexed id, - bytes data - ); - - error ErrorWrongCrossDomainSender(); -} diff --git a/contracts/arbitrum/L2ERC20TokenGateway.sol b/contracts/arbitrum/L2ERC20TokenGateway.sol deleted file mode 100644 index 5853d0ac..00000000 --- a/contracts/arbitrum/L2ERC20TokenGateway.sol +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Lido -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity 0.8.10; - -import {IERC20Bridged} from "../token/interfaces/IERC20Bridged.sol"; -import {IL2TokenGateway, IInterchainTokenGateway} from "./interfaces/IL2TokenGateway.sol"; - -import {L2CrossDomainEnabled} from "./L2CrossDomainEnabled.sol"; -import {L2OutboundDataParser} from "./libraries/L2OutboundDataParser.sol"; -import {InterchainERC20TokenGateway} from "./InterchainERC20TokenGateway.sol"; - -/// @author psirex -/// @notice Contract implements ITokenGateway interface and with counterpart L1ERC20TokenGateway -/// allows bridging registered ERC20 compatible tokens between Arbitrum and Ethereum chains -contract L2ERC20TokenGateway is - InterchainERC20TokenGateway, - L2CrossDomainEnabled, - IL2TokenGateway -{ - /// @param arbSys_ Address of the Arbitrum’s ArbSys contract in the L2 chain - /// @param router_ Address of the router in the L2 chain - /// @param counterpartGateway_ Address of the counterpart L1 gateway - /// @param l1Token_ Address of the bridged token in the L1 chain - /// @param l2Token_ Address of the token minted on the Arbitrum chain when token bridged - constructor( - address arbSys_, - address router_, - address counterpartGateway_, - address l1Token_, - address l2Token_ - ) - InterchainERC20TokenGateway( - router_, - counterpartGateway_, - l1Token_, - l2Token_ - ) - L2CrossDomainEnabled(arbSys_) - {} - - /// @inheritdoc IL2TokenGateway - function outboundTransfer( - address l1Token_, - address to_, - uint256 amount_, - uint256, // maxGas - uint256, // gasPriceBid - bytes calldata data_ - ) - external - whenWithdrawalsEnabled - onlySupportedL1Token(l1Token_) - returns (bytes memory res) - { - address from = L2OutboundDataParser.decode(router, data_); - - IERC20Bridged(l2Token).bridgeBurn(from, amount_); - - uint256 id = sendCrossDomainMessage( - from, - counterpartGateway, - getOutboundCalldata(l1Token_, from, to_, amount_, "") - ); - - // The current implementation doesn't support fast withdrawals, so we - // always use 0 for the exitNum argument in the event - emit WithdrawalInitiated(l1Token_, from, to_, id, 0, amount_); - - return abi.encode(id); - } - - /// @inheritdoc IInterchainTokenGateway - function finalizeInboundTransfer( - address l1Token_, - address from_, - address to_, - uint256 amount_, - bytes calldata - ) - external - whenDepositsEnabled - onlySupportedL1Token(l1Token_) - onlyFromCrossDomainAccount(counterpartGateway) - { - IERC20Bridged(l2Token).bridgeMint(to_, amount_); - - emit DepositFinalized(l1Token_, from_, to_, amount_); - } -} diff --git a/contracts/arbitrum/README.md b/contracts/arbitrum/README.md deleted file mode 100644 index cf76c5c1..00000000 --- a/contracts/arbitrum/README.md +++ /dev/null @@ -1,910 +0,0 @@ -# Lido's Arbitrum Gateway - -The document details implementation of the bridging of the ERC20 compatible tokens[^*] between Ethereum and Arbitrum chains via Arbitrum's “Canonical Bridge”. - -It's the first step of the Lido's integration into the Arbitrum protocol. The main goal of the current implementation is to be the strong foundation for the long-term goals of the Lido expansion in the Arbitrum chain. The long-run picture of the Lido's integration into L2s includes: - -- Bridging of Lido's tokens from L1 to L2 chains -- Instant ETH staking on L2 chains with receiving stETH/wstETH on the corresponding L2 immediately -- Keeping UX on L2 as close as possible to the UX on Ethereum mainnet - -At this point, the implementation must provide a scalable and reliable solution for Lido to bridge ERC20 compatible tokens between Arbitrum and Ethereum chain. - -[^*]: The current implementation might not support the non-standard functionality of the ERC20 tokens. For example, rebasable tokens or tokens with transfers fee will work incorrectly. In case your token implements some non-typical ERC20 logic, make sure it is compatible with the gateway before usage. - -## Arbitrum's Bridging Flow - -Arbitrum’s “Canonical Bridge” tokens-bridging architecture consists of three types of contracts: - -1. **Asset contracts**: these are the token contracts themselves, i.e., an ERC20 on L1 and it's counterpart on Arbitrum. -2. **Gateways**: Pairs of contracts (one on L1, one on L2) that implement a particular type of cross chain asset bridging. -3. **Routers**: Exactly two contracts - (one on L1, one on L2) that route each asset to its designated Gateway. - -All Ethereum to Arbitrum token transfers are initiated via the `L1GatewayRouter` contract. `L1GatewayRouter` is responsible for mapping L1 token addresses to `L1Gateway`, thus acting as an L1/L2 address oracle and ensuring that each token corresponds to only one gateway. The `L1Gateway` communicates to an `L2Gateway` (typically/expectedly via retryable tickets). - -Similarly, Arbitrum to Ethereum transfers are initiated via the `L2GatewayRouter` contract, which forwards calls the token's `L2Gateway`, which in turn communicates to its corresponding `L1Gateway` (typically/expectedly via sending messages to the Outbox.) - -To be compatible with Arbitrum's `GatewayRouter`, both L1 and L2 gateways must conform to the `ITokenGateway` interface. - -```solidity -interface ITokenGateway { - function calculateL2TokenAddress(address l1ERC20) - external - view - returns (address); - - function outboundTransfer( - address _token, - address _to, - uint256 _amount, - uint256 _maxGas, - uint256 _gasPriceBid, - bytes calldata _data - ) external returns (bytes memory); - - function getOutboundCalldata( - address _token, - address _from, - address _to, - uint256 _amount, - bytes memory _data - ) external view returns (bytes memory); - - function finalizeInboundTransfer( - address _token, - address _from, - address _to, - uint256 _amount, - bytes calldata _data - ) external virtual override; -} - -``` - -The general process of tokens bridging via Arbitrum's `GatewayRouter` consists of next steps: - -### Deposits - -1. A user calls `L1GatewayRouter.outboundTransfer()` (with `L1Token`'s L1 address as an argument). -2. `L1GatewayRouter` looks up `L1Token`'s gateway. -3. `L1GatewayRouter` calls `L1TokensGateway.outboundTransfer()`, forwarding the appropriate parameters. -4. `L1TokensGateway` escrows tokens and triggers `L2TokensGateway.finalizeInboundTransfer()` method on L2 (typically via a creation of a retryable ticket). -5. `finalizeInboundTransfer` mints the appropriate amount of tokens at the `L2Token` contract on L2. - -![](https://i.imgur.com/A8B1xgI.png) - -### Withdrawals - -1. On Arbitrum, a user calls `L2GatewayRouter.outboundTransfer()`, which in turn calls `outboundTransfer` on `L2Token`'s gateway (i.e., `L2TokensGateway`). -2. This burns `L2Token` tokens and calls [`ArbSys`](https://developer.offchainlabs.com/docs/arbsys) with an encoded message to `L1TokensGateway.finalizeInboundTransfer()`, which will be eventually executed on L1. -3. After the dispute window expires and the assertion with the user's transaction is confirmed, a user can call `Outbox.executeTransaction()`, which in turn calls the encoded `L1ERC20Gateway.finalizeInboundTransfer()` message, releasing the user's tokens from the `L1TokensGateway` contract's escrow. - -![](https://i.imgur.com/KOPguoa.png) - -The `L1GatewayRouter` allows registering custom gateways for certain tokens via `setGateways()` method, which might be called by the OffchainLabs team manually. - -The rest of the document provides a technical specification of the gateways Lido will use to transfer tokens between Arbitrum and Ethereum chains. - -## Lido's Gateways Implementation - -The current implementation of the gateways provides functionality to bridge the specified type of ERC20 compatible token between Ethereum and Arbitrum chains. Additionally, the bridge provides some administrative features, like the **temporary disabling of the deposits and withdrawals**. It's necessary when bridging must be disabled fast because of the malicious usage of the bridge or vulnerability in the contracts. Also, it might be helpful in the implementation upgrade process. - -The technical implementation focuses on the following requirements for the contracts: - -- **Scalability** - current implementation must provide the ability to be extended with new functionality in the future. -- **Simplicity** - implemented contracts must be clear, simple, and expressive for developers who will work with code in the future. -- **Gas efficiency** - implemented solution must be efficient in terms of gas costs for the end-user, but at the same time, it must not violate the previous requirement. - -A high-level overview of the proposed solution might be found in the below diagram: - -![](https://i.imgur.com/TPfEr29.png) - -- Libraries: - - [**`L1OutboundDataParser`**](#L1OutboundDataParser) - a helper library to parse data passed to `outboundTransfer()` of `L1ERC20TokenGateway`. - - [**`L2OutboundDataParser`**](#L2OutboundDataParser) - a helper library to parse data passed to `outboundTransfer()` of `L2ERC20TokenGateway`. -- Abstract Contracts: - - [_**`InterchainERC20TokenGateway`**_](#InterchainERC20TokenGateway) - an abstract contract that implements logic shared between L1 and L2 gateways. -- Contracts: - - [**`AccessControl`**](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/AccessControl.sol) - contract from the @openzeppelin package that allows children to implement role-based access. - - [**`BridgingManager`**](#BridgingManager) - contains administrative methods to retrieve and control the state of the bridging process. - - [**`BridgeableTokens`**](#BridgeableTokens) - contains the logic for validation of tokens used in the bridging process. - - [**`L1CrossDomainEnabled`**](#L1CrossDomainEnabled) - helper contract for contracts performing Ethereum to Arbitrum communication process via Retryable Tickets. - - [**`L1ERC20TokenGateway`**](#L1ERC20TokenGateway) - Ethereum's counterpart of the gateway to bridge registered ERC20 compatible tokens between Ethereum and Arbitrum chains. - - [**`L2CrossDomainEnabled`**](#L2Messenger) - helper contract to simplify Arbitrum to Ethereum communication process - - [**`L2ERC20TokenGateway`**](#L2ERC20TokenGateway) - Arbitrum's counterpart of the gateway to bridge registered ERC20 compatible tokens between Ethereum and Arbitrum chains - - [**`ERC20Bridged`**](#ERC20Bridged) - an implementation of the `ERC20` token with administrative methods to mint and burn tokens. - - [**`OssifiableProxy`**](#OssifiableProxy) - the ERC1967 proxy with extra admin functionality. - -## L1OutboundDataParser - -A helper library to parse data passed to `outboundTransfer()` of `L1ERC20TokenGateway`. - -### Functions - -#### `decode(address,bytes memory)` - -> **Visibility:**     `internal` -> -> **Mutability:**   `view` -> -> **Returns:**       `(address, uint256)` -> -> **Arguments:** -> -> - **`router_`** - an address of the Arbitrum's `L1GatewayRouter` -> - **`data_`** - bytes array encoded via the following rules: -> - If the `msg.sender` of the method is the `router_` address, `data_` must contain the result of the function call: `abi.encode(address from, abi.encode(uint256 maxSubmissionCost, bytes emptyData))`, where `emptyData` - is an empty bytes array. -> - In other cases, data must contain the result of the function call: `abi.encode(uint256 maxSubmissionCost, bytes emptyData)` where `emptyData` - is an empty bytes array. - -Decodes value contained in `data_` bytes array and returns decoded value: `(address from, uint256 maxSubmissionCost)`. Such encoding rules are required to be compatible with the `L1GatewaysRouter`. - -## L2OutboundDataParser - -A helper library to parse data passed to `outboundTransfer()` of `L2ERC20TokenGateway`. - -### Functions - -#### decode(address,bytes memory) - -> **Visibility:**     `internal` -> -> **Mutability:**   `view` -> -> **Returns**        `(address)` -> -> **Arguments:** -> -> - **`router_`** - an address of the Arbitrum's `L1GatewayRouter` -> - **`data_`** - bytes array encoded via the following rules: -> - If the `msg.sender` of the method is the `router_` address, `data_` must contain the result of the function call: `abi.encode(address from, bytes emptyData)`, where `emptyData` - is an empty bytes array. -> - In other cases, `data` must be empty bytes array. - -Decodes value contained in `data_` bytes array and returns decoded value: `(address from)`. Such encoding rules are required to be compatible with the `L2GatewaysRouter`. - -## BridgingManager - -- **inherits:** [`@openzeppelin/AccessControl`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/d4fb3a89f9d0a39c7ee6f2601d33ffbf30085322/contracts/access/AccessControl.sol) - -Contains administrative methods to retrieve and control the state of the bridging process. Allows to enable/disable withdrawals or deposits and check whether the gateway functionality is suspended or not. Allows granting standalone privileges to certain accounts to enable/disable deposits or withdrawals of the gateway. The rights to grant permissions have accounts with an admin role. - -### Constants - -- **DEPOSITS_ENABLER_ROLE** - a `bytes32` equal to a result of the `keccak256()` hashing of the string `"BridgingManager.DEPOSITS_ENABLER_ROLE"`. This role must be used when grants/revokes privileges to enable deposits. -- **DEPOSITS_DISABLER_ROLE** - a `bytes32` equal to a result of the `keccak256()` hashing of the string `"BridgingManager.DEPOSITS_DISABLER_ROLE"`. This role must be used when grants/revokes privileges to disable deposits. -- **WITHDRAWALS_ENABLER_ROLE** - a `bytes32` equal to a result of the `keccak256()` hashing of the string `"BridgingManager.WITHDRAWALS_ENABLER_ROLE"`. This role must be used when grants/revokes privileges to enable withdrawals. -- **WITHDRAWALS_DISABLER_ROLE** - a `bytes32` equal to a result of the `keccak256()` hashing of the string `"BridgingManager.WITHDRAWALS_DISABLER_ROLE"`. This role must be used when grants/revokes privileges to disable withdrawals. - -### Variables - -The contract uses the Unstructured Storage pattern to store the current state of the bridge using the struct `BridgingState`. `BridgingState` struct has the next type: - -```solidity= -struct BridgingState { - bool isInitialized; // Shows whether the contract is initialized or not. - bool isDepositsEnabled; // Stores the state of the deposits - bool isWithdrawalsEnabled; // Stores the state of the withdrawals -} -``` - -### Functions - -#### `initialize(address)` - -> **Visibility:**     `public` -> -> **Arguments:** -> -> - **`admin_`** - an address of the account to grant the `DEFAULT_ADMIN_ROLE` -> -> **Emits:** `RoleGranted(bytes32 indexed role, address indexed account, address indexed sender)` - -Initializes the contract to grant `DEFAULT_ADMIN_ROLE` to the `admin_` address. The method might be called only once. Reverts with error `ErrorAlreadyInitialized()` when called on the already initialized contract. Allows using this contract with the proxy pattern. - -#### `isDepositsEnabled()` - -> **Visibility:**     `public` -> -> **Mutability:**   `view` -> -> **Returns**        `(bool)` - -Returns whether the deposits enabled or not. - -#### `isWithdrawalsEnabled()` - -> **Visibility:**     `public` -> -> **Mutability:**   `view` -> -> **Returns**        `(bool)` - -Returns whether the withdrawals enabled or not. - -#### `enableDeposits()` - -> **Visibility:**     `external` -> -> **Modifiers:**    [`onlyRole(DEPOSITS_ENABLER_ROLE)`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/d4fb3a89f9d0a39c7ee6f2601d33ffbf30085322/contracts/access/AccessControl.sol#L69) -> -> **Emits:**           `DepositsEnabled(address account)` - -Enables the deposits if they are disabled. Reverts with the error `ErrorDepositsEnabled()` if deposits aren't enabled. Only accounts with the granted `DEPOSITS_ENABLER_ROLE` can call this method. - -#### `disableDeposits()` - -> **Visibility:**     `external` -> -> **Modifiers:**    [`whenDepositsEnabled`](#whenDepositsEnabled) [`onlyRole(DEPOSITS_DISABLER_ROLE)`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/d4fb3a89f9d0a39c7ee6f2601d33ffbf30085322/contracts/access/AccessControl.sol#L69) -> -> **Emits:**           `DepositsDisabled(address account)` - -Disables the deposits if they aren't disabled yet. Reverts with the error `ErrorDepositsDisabled()` if deposits have already disabled. Only accounts with the granted `DEPOSITS_DISABLER_ROLE` can call this method. - -#### `enableWithdrawals()` - -> **Visibility:**     `external` -> -> **Modifiers:**    [`onlyRole(WITHDRAWALS_ENABLER_ROLE)`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/d4fb3a89f9d0a39c7ee6f2601d33ffbf30085322/contracts/access/AccessControl.sol#L69) -> -> **Emits:**           `WithdrawalsEnabled(address account)` - -Enables the withdrawals if they are disabled. Reverts with the error `ErrorWithdrawalsEnabled()` if withdrawals are enabled. Only accounts with the granted `WITHDRAWALS_ENABLER_ROLE` can call this method. - -#### `disableWithdrawals()` - -> **Visibility:**     `external` -> -> **Modifiers:**    [`whenWithdrawalsEnabled`](#whenWithdrawalsEnabled)[`onlyRole(WITHDRAWALS_DISABLER_ROLE)`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/d4fb3a89f9d0a39c7ee6f2601d33ffbf30085322/contracts/access/AccessControl.sol#L69) -> -> **Emits:**           `WithdrawalsDisabled(address account)` - -Disables the withdrawals if they aren't disabled yet. Reverts with the error `ErrorWithdrawalsDisabled()` if withdrawals have already disabled. Only accounts with the granted `WITHDRAWALS_DISABLER_ROLE` can call this method. - -#### `_loadState()` - -> **Visibility:**     `private` -> -> **Mutability:**   `pure` -> -> **Returns**        `(BridgingState storage)` - -Loads and returns the `BridgingState` variable from the slot at address `keccak256("BridgingManager.bridgingState")`. - -### Modifiers - -#### `whenDepositsEnabled()` - -Validates that deposits are enabled. Reverts with the error `ErrorDepositsDisabled()` when called on contract with disabled deposits. - -#### `whenWithdrawalsEnabled()` - -Validates that withdrawals are enabled. Reverts with the error `ErrorWithdrawalsDisabled()` when called on contract with disabled withdrawals. - -## BridgeableTokens - -Contains the logic for validation of tokens used in the bridging process - -### Variables - -The contract keeps the addresses of L1/L2 tokens used in the bridging: - -- **`l1Token`** - an immutable address of the bridged token in the L1 chain -- **`l2Token`** - an immutable address of the token minted on the L2 chain when token bridged - -### Modifiers - -#### `onlySupportedL1Token(address l1Token_)` - -Validates that passed `l1Token_` is supported by the bridge. Reverts with error `ErrorUnsupportedL1Token()` when addresses mismatch. - -#### `onlySupportedL2Token(address l2Token_)` - -Validates that passed `l2Token_` is supported by the bridge. Reverts with error `ErrorUnsupportedL2Token()` when addresses mismatch. - -## InterchainERC20TokenGateway - -**Implements:** `IInterchainERC20TokenGateway` -**Inherits:** [`BridgingManager`](#BridgingManager) [`BridgeableTokens`](#BridgeableTokens) - -The contract keeps logic shared among both L1 and L2 gateways, adding the methods for bridging management: enabling and disabling withdrawals/deposits. - -### Variables - -The contract keeps the variables required by both L1/L2 gateways: - -- **`router`** - an address of the router in the corresponding chain -- **`counterpartGateway`** - an address of the counterpart gateway used in the bridging process - -All variables are declared as `immutable` to reduce transactions gas costs. - -### Functions - -#### `calculateL2TokenAddress(address)` - -> **Visibility:**     `external` -> -> **Mutability:**   `view` -> -> **Returns**        `(address)` -> -> **Arguments:** -> -> - **l1Token\_** - an address of the token on the Ethereum chain - -Returns an address of token, which will be minted on the Arbitrum chain, on `l1Token_` bridging. The current implementation returns the `l2Token` address when passed `l1Token_` equals to `l1Token` declared in the contract and `address(0)` in other cases. - -#### `getOutboundCalldata(address,address,address,uint256,bytes memory)` - -> **Visibility:**     `public` -> -> **Mutability:**   `view` -> -> **Returns**        `(bytes memory)` -> -> **Arguments:** -> -> - **`l1Token_`** - an address in the Ethereum chain of the token to bridge -> - **`from_`** - an address in the Ethereum chain of the account initiated bridging -> - **`to_`** - an address in the Ethereum chain of the recipient of the token on the corresponding chain -> - **`amount_`** - an amount of tokens to bridge -> - **`data_`** - Custom data to pass into finalizeInboundTransfer method. Unused, required to be compatible with @arbitrum/sdk package. - -Returns encoded transaction data to send into the corresponding gateway to finalize the tokens bridging process. The result of this method might be used to estimate the amount of ether required to pass to the `outboundTransfer()` method call. In the current implementation returns the transaction data of `finalizeInboundTransfer(token_, from_, to_, amount_)`. - -## L1CrossDomainEnabled - -A helper contract for contracts performing Ethereum to Arbitrum communication process via Retryable Tickets. - -### Variables - -The contract declares one immutable variable **`inbox_`** - an address of the Arbitrum's [`Inbox`](https://developer.offchainlabs.com/docs/sol_contract_docs/md_docs/arb-bridge-eth/bridge/inbox) contract - -### Functions - -#### `sendCrossDomainMessage(address, address, bytes memory, CrossDomainMessageOptions memory)` - -> **Visibility:**     `internal` -> -> **Returns**        `(uint256)` -> -> **Arguments**: -> -> - **`sender_`** - an address of the sender of the message. It's also the address to credit all excess ETH from gas and call-value on the Arbitrum chain. Call-value is refunded if the retryable ticket times out or is canceled. `sender_` is also the address with the right to cancel a Retryable Ticket. -> - **`recipient_`** - an address of the recipient of the message on the Arbitrum chain -> - **`data_`** - data passed to the `recipient_` in the message -> - **`msgOptions_`** - an instance of the `CrossDomainMessageOptions` struct. The `CrossDomainMessageOptions` struct has the following properties: -> - **`maxGas`** - gas limit for immediate L2 execution attempt (can be estimated via `NodeInterface.estimateRetryableTicket()`) -> - **`callValue`** - call-value for L2 transaction -> - **`gasPriceBid`** - L2 Gas price bid for immediate L2 execution attempt (queryable via standard `eth_gasPrice` RPC) -> - **`maxSubmissionCost`** - an amount of ETH allocated to pay for the base submission fee -> -> **Emits:** `TxToL2(address indexed from, address indexed to, uint256 indexed seqNum, bytes data)` - -Creates a Retryable Ticket via [`Inbox.createRetryableTicket`](https://github.com/OffchainLabs/arbitrum/blob/52356eeebc573de8c4dd571c8f1c2a6f5585f359/packages/arb-bridge-eth/contracts/bridge/Inbox.sol#L325) function using the provided arguments. Sends all passed ether with Retryable Ticket into Arbitrum chain. Reverts with error `ErrorETHValueTooLow()` if passed `msg.value` is less than `msgOptions_.callVaue + msgOptions_.maxSubmissionCost + (msgOptions_.maxGas * msgOptions_.gasPriceBid)` and with error `ErrorNoMaxSubmissionCost()` when `msgOptions_.maxSubmissionCost` is equal to 0. Returns a unique id of created Retryable Ticket. - -### Modifiers - -#### `onlyFromCrossDomainAccount(address crossDomainAccount_)` - -Validates that transaction was initiated by the `crossDomainAccount_` address from the L2 chain. Reverts with error `ErrorUnauthorizedBridge()` if called not by Arbitrum's bridge and with error `ErrorWrongCrossDomainSender()` if the transaction was sent not from the `crossDomainAccount_` address. - -## L1ERC20TokenGateway - -- **Inherits**: [`InterchainERC20TokenGateway`](#InterchainERC20TokenGateway) [`L1CrossDomainEnabled`](#L1CrossDomainEnabled) -- **Implements**: `IL1TokenGateway` - -Contract implements `ITokenGateway` interface and with counterpart `L2TokensGatewy` allows bridging registered ERC20 compatible tokens between Ethereum and Arbitrum chains. The contract is compatible with `L1GatewayRouter` and might be used to transfer tokens via the "canonical" Arbitrum's bridge. - -Additionally, the contract provides administrative methods to temporarily disable bridging from Ethereum to Arbitrum via the `BridgingManager` contract. - -### Functions - -#### `outboundTransfer(address,address,uint256,uint256, uint256,bytes calldata)` - -> **Visibility:**     `external` -> -> **Mutability:**   `payble` -> -> **Modifiers:**    [`whenDepositsEnabled()`](#whenDepositsEnabled) [`onlySupportedL1Token(l1Token_)`](#onlySupportedL1Tokenaddress-l1Token_) -> -> **Returns**        `(bytes memory)` -> -> **Arguments:** -> -> - **l1Token\_** - an address in the Ethereum chain of the token to bridge. It must be equal to the `l1Token` address. The method will be reverted with the error `ErrorUnsupportedL1Token()` if would be called with a different address. -> - **to\_** - an address of the recipient of the token on the corresponding chain -> - **amount\_** - an amount of tokens to bridge. The user has to approve spending of the `l1Token` for the gateway or the transaction will be reverted. -> - **maxGas\_** - a gas limit for immediate L2 execution attempt (can be estimated via `_NodeInterface.estimateRetryableTicket`). -> - **gasPriceBid\_** - an L2 gas price bid for immediate L2 execution attempt (queryable via standard eth\*gasPrice RPC). -> - **data** - stores an additional data required for the transaction. Data will be decoded via the `L1OutboundDataParser.decode()` method to retrieve the `maxSubmissionCost` value and `from` address, where `from` - contains an address of the sender, and `maxSubmissionCost` - is an amount of ETH allocated to pay for the base submission fee. -> -> **Emits:** `DepositInitiated(address l1Token, address indexed from, address indexed to, uint256 indexed sequenceNumber, uint256 amount)` - -Initiates the tokens bridging from the Ethereum into the Arbitrum chain. Escrows the `amount_` of `l1Token_` from the user on the address of the gateway and creates a Retryable Ticket via the `sendCrossDomainMessage()` method: - -```solidity= -sendCrossDomainMessage( - counterpartGateway, // recipient - getOutboundCalldata(l1Token, from, to, amount, ""), // data - CrossDomainMessageOptions({ - maxGas: maxGas, - callValue: 0, - gasPriceBid: gasPriceBid_, - refundAddress: from, - maxSubmissionCost: maxSubmissionCost - }) -) -``` - -Returns an encoded value of the id for created Retryable Ticket. Same value is used as `sequenceNumber` in `DepositInitiated` event. - -#### `finalizeInboundTransfer(address,address,address,uint256,bytes calldata)` - -> **Visibility:**     `internal` -> -> **Modifiers:**    [`whenWithdrawalsEnabled()`](#whenWithdrawalsEnabled) [`onlySupportedL1Token(l1Token_)`](#onlySupportedL1Tokenaddress-l1Token_) [`onlyFromCrossDomainAccount(counterpartGateway)`](#onlyFromCrossDomainAccountaddress-crossDomainAccount_) -> -> **Arguments:** -> -> - **`l1Token_`** - an address in the Ethereum chain of the token to withdraw -> - **`from_`** - an address of the account initiated bridging -> - **`to_`** - an address of the recipient of the tokens -> - **`amount_`** - an amount of tokens to withdraw -> - **`data_`** - unused variable, required to be compatible with `L1GatewayRouter` and `L2GatewayRouter` -> -> **Emits:** `WithdrawalFinalized(address l1Token, address indexed from, address indexed to, uint256 indexed exitNum, uint256 amount)` - -This method is called to finalize the withdrawal of the tokens from the L2 chain. It transfers the `amount_` of tokens from the gateway to the `to_` address via `safeTransfer()` method. - -**Note**: `exitNum` - always is equal to 0 in the `WithdrawalFinalized` event cause the current implementation doesn't support fast withdraws. To read more about fast withdrawals, see [Offchain Labs Docs](https://developer.offchainlabs.com/docs/withdrawals). - -## L2CrossDomainEnabled - -A helper contract to simplify Arbitrum to Ethereum communication process. - -### Variables - -The contract declares one immutable variable **`arbSys`** - an address of the Arbitrum's [`ArbSys`](https://developer.offchainlabs.com/docs/arbsys) contract - -### Functions - -#### `sendCrossDomainMessage(address,address,bytes memory)` - -> **Visibility:**     `internal` -> -> **Returns**        `(uint256)` -> -> **Arguments**: -> -> - **`sender_`** - an address of the sender of the message -> - **`recipient_`** - an address of the recipient of the message on the Ethereum chain -> - **`data_`** - Data passed to the `recipient_` in the message -> -> **Emits**: `event TxToL1(address indexed from, address indexed to, uint256 indexed id, bytes data)` - -Sends the message to the Ethereum chain via `ArbSys.sendTxToL1()` method. - -#### `applyL1ToL2Alias(address)` - -> **Visibility:**     `private` -> -> **Returns**        `(address)` -> -> **Arguments**: -> -> - **`l1Address_`** - an L1 address to apply aliasing - -Applies the [Arbitrum's L1 -> L2 aliasing](https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing) to the address. - -### Modifiers - -#### `onlyFromCrossDomainAccount(address crossDomainAccount_)` - -Validates that the `msg.sender` is equal to the `crossDomainAccount_` with applied [Arbitrum's aliasing](https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing). Reverts with the error `ErrorWrongCrossDomainSender()` if validation fails. - -## L2ERC20TokenGateway - -- **Inherits**: [`InterchainERC20TokenGateway`](#InterchainERC20TokenGateway) [`L2CrossDomainEnabled`](#L2CrossDomainEnabled) -- **Implements**: `IL2TokenGateway` - -Contract implements `ITokenGateway` interface and with counterpart `L1ERC20TokenGateway` allows bridging registered ERC20 compatible tokens between Arbitrum and Ethereum chains. The contract is compatible with `L2GatewayRouter` and might be used to transfer tokens via the “canonical” Arbitrum’s bridge. - -Additionally, the contract provides administrative methods to temporarily disable bridging from Arbitrum to Ethereum via the `BridgingManager` contract. - -### Functions - -#### `outboundTransfer(address,address,uint256,uint256, uint256,bytes memory)` - -> **Visibility:**     `external` -> -> **Modifiers:**    [`whenWithdrawalsEnabled()`](#whenWithdrawalsEnabled) [`onlySupportedL1Token(l1Token_)`](#onlySupportedL1Tokenaddress-l1Token_) -> -> **Returns**        `(bytes memory)` -> -> **Arguments:** -> -> - **l1Token\_** - an address in the Ethereum chain of the token to bridge. It must be equal to the `l1Token` address. The method will be reverted with the error `ErrorUnsupportedL1Token()` if would be called with a different address. -> - **to\_** - an address of the recipient of the token on the corresponding chain -> - **amount\_** - an amount of tokens to bridge. The user has to approve spending of the `l1Token` for the gateway or the transaction will be reverted. -> - **maxGas\_** - Doesn't used -> - **gasPriceBid\_** - Doesn't used -> - **data** - stores an additional data required for transaction. Data will be decoded via `L2OutboundDataParser.decode()` method to retrieve `from` address - an address of the sender. -> -> **Emits:** `WithdrawalInitiated(address l1Token, address indexed from, address indexed to, uint256 indexed l2ToL1Id, uint256 exitNum, uint256 amount)` - -Initiates the withdrawing process from the Arbitrum chain into the Ethereum chain. The method burns the `amount_` of `l2Token` on the `from_` account, sends message to the Ethereum chain via `sendCrossDomainMessage()` method: - -```solidity= -sendCrossDomainMessage( - counterpartGateway, - getOutboundCalldata(l1Token_, from_, to_, amount_, "") -); -``` - -Returns encoded value of the unique id for L2-to-L1 transaction. Same value is used as `l2ToL1Id` in the `WithdrawalInitiated` event. - -**Note**: `exitNum` - always is equal to 0 in the `WithdrawalInitiated` event cause the current implementation doesn't support fast withdraws. To read more about fast withdrawals, see [Offchain Labs Docs](https://developer.offchainlabs.com/docs/withdrawals). - -#### `finalizeInboundTransfer(address,address,address,uint256,bytes calldata)` - -> **Visibility:**     `internal` -> -> **Modifiers:**    [`whenDepositsEnabled()`](#whenDepositsEnabled) [`onlySupportedL1Token(l1Token_)`](#onlySupportedL1Tokenaddress-l1Token_) [`onlyFromCrossDomainAccount(counterpartGateway)`](#onlyFromCrossDomainAccountaddress-crossDomainAccount_1) -> -> **Arguments:** -> -> - **`l1Token_`** - an address in the Ethereum chain of the token to bridge -> - **`from_`** - an address of the account initiated bridging -> - **`to_`** - an address of the recipient of the tokens -> - **`amount_`** - an amount of tokens to bridge -> - **`data_`** - unused variable, required to be compatible with `L1GatewayRouter` and `L2GatewayRouter` -> -> **Emits:** `DepositFinalized(address indexed l1Token, address indexed from, address indexed to, uint256 amount)` - -This method is called on the finalizing of the bridging from the Ethereum chain. This method mints the `amount_` of `l2Token` token to the `to_` address. - -## `ERC20Metadata` - -Contains optional methods for the `ERC20` tokens. It uses the UnstructuredStorage pattern to store strings with name and symbol info. Might be used with the upgradable proxies. - -### Variables - -Contract declares `public` and `immutable` variable **`decimals`** of type `uint8`. - -The `name` and `symbol` info are stored in the structure: - -```solidity= -struct DynamicMetadata { - string name; - string symbol; -} -``` - -### Funcations - -#### `name()` - -> **Visibility:**     `external` -> -> **Mutability:**   `view` -> -> **Returns**        `(string memory)` - -Returns the name of the token. - -#### `symbol()` - -> **Visibility:**     `external` -> -> **Mutability:**   `view` -> -> **Returns**        `(string memory)` - -Returns the symbol of the token. - -#### `_setERC20MetadataName(string memory)` - -> **Visibility:**     `internal` -> -> **Arguments:** -> -> - **`name_`** - string with name of the token - -Sets the `name` of the token. Might be called only when the `name` is empty. - -#### `_setERC20MetadataSymbol(string memory)` - -> **Visibility:**     `internal` -> -> **Arguments:** -> -> - **`symbol_`** - string with symbol of the token - -Sets the `symbol` of the token. Might be called only when the `symbol` is empty. - -#### `_loadDynamicMetadata()` - -> **Visibility:**     `private` -> -> **Mutability:**   `pure` -> -> **Returns**        `(DynamicMetadata storage r)` - -Returns the reference to the slot with `DynamicMetadta` struct - -## `ERC20Core` - -- **Implements:** [`@openzeppelin/IERC20`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/d4fb3a89f9d0a39c7ee6f2601d33ffbf30085322/contracts/token/ERC20/IERC20.sol) - -Contains the required variables and logic of the `ERC20` token. The contract is a slightly modified version of the [`ERC20`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/d4fb3a89f9d0a39c7ee6f2601d33ffbf30085322/contracts/token/ERC20/ERC20.sol) contract from the OpenZeppelin package. - -### Variables - -Contract declares the following variables to store state of the token: - -- **`uint256 public totalSupply`** - the total supply of the token -- **`mapping(address => uint256) public balanceOf`** - stores balances of the token holders -- **`mapping(address => mapping(address => uint256)) public allowance`** - stores allowances of the token holders - -### Functions - -#### `approve(address,uint256)` - -> **Visibility:**     `external` -> -> **Returns**        `(bool)` -> -> **Arguments:** -> -> - **`spender_`** - an address of the tokens spender -> - **`amount_`** - a number of tokens to allow to spend -> -> **Emits:** `Approval(address indexed owner, address indexed spender, uint256 value)` - -Allows _spender to withdraw from the `msg.sender` account multiple times, up to the `amount_`. If this function is called again it overwrites the current allowance with `amount\_`. Returns a `bool` value indicating whether the operation succeeded. - -#### `transfer(address,uint256)` - -> **Visibility:**     `external` -> -> **Returns**        `(bool)` -> -> **Arguments:** -> -> - **`to_`** - an address of the recipient of the tokens -> - **`amount_`** - a number of tokens to transfer -> -> **Emits:** `Transfer(address indexed from, address indexed to, uint256 value)` - -Transfers `amount` of tokens from sender to `to` account. -Returns a `bool` value indicating whether the operation succeeded. - -#### `transferFrom(address,address,uint256)` - -> **Visibility:**     `external` -> -> **Returns**        `(bool)` -> -> **Arguments:** -> -> - **`from_`** - an address to transfer tokens from -> - **`to_`** - an address of the recipient of the tokens -> - **`amount_`** - a number of tokens to transfer -> -> **Emits:** `Transfer(address indexed from, address indexed to, uint256 value)` `Approval(address indexed owner, address indexed spender, uint256 value)` - -Transfers `amount` of token from the `from_` account to `to_` using the allowance mechanism. `amount_` is then deducted from the caller's allowance. Returns a `bool` value indicating whether the operation succeed. - -#### `increaseAllowance(address,uint256)` - -> **Visibility:**     `external` -> -> **Returns**        `(bool)` -> -> **Arguments:** -> -> - **`spender_`** - an address of the tokens spender -> - **`addedValue_`** - a number to increase allowance -> -> **Emits:** `Approval(address indexed owner, address indexed spender, uint256 value)` - -Atomically increases the allowance granted to `spender` by the caller. Returns a `bool` value indicating whether the operation succeed. - -#### `decreaseAllowance(address,uint256)` - -> **Visibility:**     `external` -> -> **Returns**        `(bool)` -> -> **Arguments:** -> -> - **`spender_`** - an address of the tokens spender -> - **`subtractedValue_`** - a number to decrease allowance -> -> **Emits:** `Approval(address indexed owner, address indexed spender, uint256 value)` - -Atomically decreases the allowance granted to `spender` by the caller. Returns a `bool` value indicating whether the operation succeed. - -## `ERC20Bridged` - -**Implements:** [`IERC20Bridged`](https://github.com/lidofinance/lido-l2/blob/main/contracts/token/interfaces/IERC20Bridged.sol) -**Inherits:** [`ERC20Metadata`](#ERC20Metadata) [`ERC20Core`](#ERC20CoreLogic) - -Inherits the `ERC20` default functionality that allows the bridge to mint and burn tokens. - -### Variables - -Contract declares an immutable variable **`bridge`** which can mint/burn the token. - -### Functions - -#### `mint(address,uint256)` - -> **Visibility:**     `external` -> -> **Modifiers:**    [`onlyBridge`](#onlybridge) -> -> **Arguments:** -> -> - **`account_`** - an address of the tokens recipient -> - **`amount_`** - a number to mint -> -> **Emits:** `Transfer(address indexed from, address indexed to, uint256 value)` - -Mints the `amount_` of tokens to the `account_`. The method might be called only by the bridge. Reverts with the error `ErrorNotBridge()` when called not by bridge. - -#### `burn(address,uint256)` - -> **Visibility:**     `external` -> -> **Modifiers:**    [`onlyBridge`](#onlybridge) -> -> **Arguments:** -> -> - **`account_`** - an address of the tokens recipient -> - **`amount_`** - a number to burn -> -> **Emits:** `Transfer(address indexed from, address indexed to, uint256 value)` - -Destroys the `amount_` of tokens from the `account_`. The method might be called only by the bridge. Reverts with the error `ErrorNotBridge()` when called not by bridge. - -### Modifiers - -#### `onlyBridge()` - -Validates that the `msg.sender` of the method is the `bridge`. Reverts with error `ErrorNotBridge()` in other cases. - -## `OssifiableProxy` - -- **Inherits:** [`@openzeppelin/ERC1967Proxy`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/d4fb3a89f9d0a39c7ee6f2601d33ffbf30085322/contracts/proxy/ERC1967/ERC1967Proxy.sol) - -Extends the [`ERC1967Proxy`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/d4fb3a89f9d0a39c7ee6f2601d33ffbf30085322/contracts/proxy/ERC1967/ERC1967Proxy.sol) contract from the OpenZeppelin package and adds some admin methods. In contrast to [`UUPSUpgradableProxy`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/d4fb3a89f9d0a39c7ee6f2601d33ffbf30085322/contracts/proxy/utils/UUPSUpgradeable.sol), it doesn't increase the inheritance chain of the implementation contracts. And allows saving one extra `SLOAD` operation on every user request in contrast to [`TransparentUpgradeableProxy`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/d4fb3a89f9d0a39c7ee6f2601d33ffbf30085322/contracts/proxy/transparent/TransparentUpgradeableProxy.sol). But adding any external methods to the `ERC1967Proxy` creates the risk of selectors clashing, as described in the OpenZepplin [proxies docs](https://docs.openzeppelin.com/upgrades-plugins/1.x/proxies#transparent-proxies-and-function-clashes). To avoid the risk of clashing, the implementation upgrade process must contain a step with a search of the collisions between proxy and implementation. - -### Functions - -#### `proxy__getAdmin()` - -> **Visibility:**     `external` -> -> **Mutability:**   `view` -> -> **Returns**        `(address)` - -Returns the admin of the proxy. - -#### `proxy__getImplementation()` - -> **Visibility:**     `external` -> -> **Mutability:**   `view` -> -> **Returns**        `(address)` - -Returns the address of the implementation. - -#### `proxy__getIsOssified()` - -> **Visibility:**     `external` -> -> **Mutability:**   `view` -> -> **Returns**        `(bool)` - -Returns whether the proxy is ossified or not. - -#### `proxy__ossify()` - -> **Visibility:**     `external` -> -> **Modifiers:**    [`onlyAdmin`](#onlyAdmin) -> -> **Emits:**           `AdminChanged(address previousAdmin, address newAdmin)` - -Allows to transfer admin rights to zero address and prevent future upgrades of the proxy. - -#### `proxy__changeAdmin(address)` - -> **Visibility:**     `external` -> -> **Modifiers:**    [`onlyAdmin`](#onlyAdmin) -> -> **Arguments:** -> -> - **`newAdmin_`** - an address of the new admin. Must not be zero address. -> -> **Emits:** `AdminChanged(address previousAdmin, address newAdmin)` - -Changes the admin of the proxy. Reverts with message "ERC1967: new admin is the zero address" if `newAdmin_` is zero address. - -#### `proxy__upgradeTo(address)` - -> **Visibility:**     `external` -> -> **Modifiers:**    [`onlyAdmin`](#onlyAdmin) -> -> **Arguments:** -> -> - **`newImplementation_`** - an address of the new implementation. Must be a contract. -> -> **Emits:** `Upgraded(address indexed implementation)` - -Upgrades the implementation of the proxy. Reverts with the error "ERC1967: new implementation is not a contract" if the `newImplementation_` is not a contract. - -#### `proxy__upgradeToAndCall(address,bytes memory,bool)` - -> **Visibility:**     `external` -> -> **Modifiers:**    [`onlyAdmin`](#onlyAdmin) -> -> **Arguments:** -> -> - **`newImplementation_`** - an address of the new implementation. Must be a contract. -> - **`setupCalldata_`** - a data to pass into setup call after implementation upgrade. -> - **`forceCall_`** - forces make delegate call to the implementation even with empty `setupCalldata_` -> -> **Emits:** `Upgraded(address indexed implementation)` - -Upgrades the implementation of the proxy with an additional setup call. Reverts with the error "ERC1967: new implementation is not a contract" if the `newImplementation_` is not a contract. If `setupCalldata_.length` equals zero setup step will be skipped, if forceCall is false. - -### Modifiers - -#### `onlyAdmin()` - -Validates that that proxy is not ossified and that method is called by the admin of the proxy. Reverts with error `ErrorProxyIsOssified()` when called on ossified contract and with error `ErrorNotAdmin()` when called not by admin. - -## Deployment Process - -To reduce the gas costs for users, contracts `L1ERC20TokenGateway`, `L2ERC20TokenGateway`, and `L2TokensToken` use immutable variables as much as possible. But some of those variables are cross-referred. For example, `L1ERC20TokenGateway` has reference to `L2ERC20TokenGateway` and vice versa. As we use proxies, we can deploy proxies at first and stub the implementation with an empty contract. Then deploy actual implementations with addresses of deployed proxies and then upgrade proxies with new implementations. For stub might be used next contract: - -``` -pragma solidity ^0.8.0; -contract EmptyContract {} -``` - -Another option - pre-calculate the future address of the deployed contract offchain and deployed the implementation using pre-calculated addresses. But it is less fault-tolerant than the solution with an implementation stub. - -## Integration Risks - -As an additional link in the tokens flow chain, the Arbitrum and gateways possibly add points of failure. Below are the main risks of the current integration: - -### Minting of uncollateralized `L2Token` - -Such an attack might happen if an attacker obtains the right to call `L2ERC20TokenGateway.finalizeOutboundTransfer()` directly to mint uncollateralized L2Token. In such a scenario, an attacker can mint tokens on L2 and initiate withdrawal of those tokens. - -The best way to detect such an attack is an offchain monitoring of the minting and depositing/withdrawal events. Based on such events might be tracked following stats: - -- `l1GatewayBalance` - a total number of locked tokens on the L1 gateway -- `l2TokenTotalSupply` - total number of minted L2 tokens -- `l2TokenNotWithdrawn` - total number of burned L2 tokens which aren't withdrawn from the L1 gateway - -At any time following invariant must be sutisfied: `l1GatewayBalance == l2TokenTotalSupply + l2TokenNotWithdrawn`. - -In the case of invariant violation, Lido will have a dispute period to suspend L1 and L2 gateways. Paused gateways forbid minting of L2Token and withdrawing of minted tokens till the resolution of the issue. - -### Attack on fraud-proof system - -Such an attack might be seeking to take control over validators or abuse the fraud-proof system to submit incorrect state root. In such a case, the proposed incorrect block will be subject to a dispute period. Lido may run its validator with a "watchtower" strategy, which will ring the alarm when an invalid block is proposed. When it happens, the gateway must be suspended to protect users from potential funds lost till the resolution of the issue. - -### Attack on `L1GatewaysRouter` - -Theoretical situation, when an attacker takes control over `L1GatewaysRouter` and replaces an address of the gateway responsible for token bridging on some malicious contract. It potentially allows to steal the tokens transferred after the gateway substitution. To react to such an attack fastly, Lido has to monitor the `GatewaySet` event with the address of the Lido token. In case such an event was emitted, the Offchain Labs Team must be reached out to investigate the details and fix an issue asap to minimize the damage. diff --git a/contracts/arbitrum/interfaces/IArbSys.sol b/contracts/arbitrum/interfaces/IArbSys.sol deleted file mode 100644 index f7221e8a..00000000 --- a/contracts/arbitrum/interfaces/IArbSys.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Lido -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity 0.8.10; - -/// @title Precompiled contract that exists in every Arbitrum chain at address(100), -/// 0x0000000000000000000000000000000000000064. Exposes a variety of system-level functionality -interface IArbSys { - /// @notice Send a transaction to L1 - /// @param destination_ Recipient address on L1 - /// @param calldataForL1_ (optional) Calldata for L1 contract call - /// @return Unique identifier for this L2-to-L1 transaction - function sendTxToL1(address destination_, bytes calldata calldataForL1_) - external - payable - returns (uint256); -} diff --git a/contracts/arbitrum/interfaces/IBridge.sol b/contracts/arbitrum/interfaces/IBridge.sol deleted file mode 100644 index 4b6e8a42..00000000 --- a/contracts/arbitrum/interfaces/IBridge.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Lido -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity 0.8.10; - -interface IBridge { - function activeOutbox() external view returns (address); -} diff --git a/contracts/arbitrum/interfaces/IInbox.sol b/contracts/arbitrum/interfaces/IInbox.sol deleted file mode 100644 index 372182ec..00000000 --- a/contracts/arbitrum/interfaces/IInbox.sol +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Lido -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity >=0.4.21; - -interface IInbox { - /// @notice Put an message in the L2 inbox that can be reexecuted for some fixed amount of time - /// if it reverts all msg.value will deposited to callValueRefundAddress on L2 - /// @param destAddr_ Destination L2 contract address - /// @param arbTxCallValue_ Call value for retryable L2 message - /// @param maxSubmissionCost_ Max gas deducted from user's L2 balance to cover base submission fee - /// @param submissionRefundAddress_ maxGas x gasprice - execution cost gets credited here on L2 balance - /// @param valueRefundAddress_ l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled - /// @param maxGas_ Max gas deducted from user's L2 balance to cover L2 execution - /// @param gasPriceBid_ Price bid for L2 execution - /// @param data_ ABI encoded data of L2 message - /// @return unique id for retryable transaction (keccak256(requestID, uint(0) ) - function createRetryableTicket( - address destAddr_, - uint256 arbTxCallValue_, - uint256 maxSubmissionCost_, - address submissionRefundAddress_, - address valueRefundAddress_, - uint256 maxGas_, - uint256 gasPriceBid_, - bytes calldata data_ - ) external payable returns (uint256); - - /// @notice Returns address of the Arbitumr's bridge - function bridge() external view returns (address); -} diff --git a/contracts/arbitrum/interfaces/IInterchainTokenGateway.sol b/contracts/arbitrum/interfaces/IInterchainTokenGateway.sol deleted file mode 100644 index 0915eac5..00000000 --- a/contracts/arbitrum/interfaces/IInterchainTokenGateway.sol +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Lido -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity 0.8.10; - -/// @author psirex -/// @notice Keeps logic shared among both L1 and L2 gateways. -interface IInterchainTokenGateway { - /// @notice Finalizes the bridging of the tokens between chains - /// @param l1Token_ Address in the L1 chain of the token to withdraw - /// @param from_ Address of the account initiated withdrawing - /// @param to_ Address of the recipient of the tokens - /// @param amount_ Amount of tokens to withdraw - /// @param data_ Additional data required for the transaction - function finalizeInboundTransfer( - address l1Token_, - address from_, - address to_, - uint256 amount_, - bytes calldata data_ - ) external; - - /// @notice Calculates address of token, which will be minted on the Arbitrum chain, - /// on l1Token_ bridging - /// @param l1Token_ Address of the token on the Ethereum chain - /// @return Address of the token minted on the L2 on bridging - function calculateL2TokenAddress(address l1Token_) - external - view - returns (address); - - /// @notice Returns address of the counterpart gateway used in the bridging process - function counterpartGateway() external view returns (address); - - /// @notice Returns encoded transaction data to send into the counterpart gateway to finalize - /// the tokens bridging process. - /// @param l1Token_ Address in the Ethereum chain of the token to bridge - /// @param from_ Address of the account initiated bridging in the current chain - /// @param to_ Address of the recipient of the token in the counterpart chain - /// @param amount_ Amount of tokens to bridge - /// @param data_ Custom data to pass into finalizeInboundTransfer method - /// @return Encoded transaction data of finalizeInboundTransfer call - function getOutboundCalldata( - address l1Token_, - address from_, - address to_, - uint256 amount_, - bytes memory data_ - ) external view returns (bytes memory); -} diff --git a/contracts/arbitrum/interfaces/IL1TokenGateway.sol b/contracts/arbitrum/interfaces/IL1TokenGateway.sol deleted file mode 100644 index 2ec88be5..00000000 --- a/contracts/arbitrum/interfaces/IL1TokenGateway.sol +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Lido -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity 0.8.10; - -import {IInterchainTokenGateway} from "./IInterchainTokenGateway.sol"; - -/// @author psirex -/// @notice L1 part of the tokens bridge compatible with Arbitrum's GatewayRouter -interface IL1TokenGateway is IInterchainTokenGateway { - /// @notice Initiates the tokens bridging from the Ethereum into the Arbitrum chain - /// @param l1Token_ Address in the L1 chain of the token to bridge - /// @param to_ Address of the recipient of the token on the corresponding chain - /// @param amount_ Amount of tokens to bridge - /// @param maxGas_ Gas limit for immediate L2 execution attempt - /// @param gasPriceBid_ L2 gas price bid for immediate L2 execution attempt - /// @param data_ Additional data required for the transaction - function outboundTransfer( - address l1Token_, - address to_, - uint256 amount_, - uint256 maxGas_, - uint256 gasPriceBid_, - bytes calldata data_ - ) external payable returns (bytes memory); - - event DepositInitiated( - address l1Token, - address indexed from, - address indexed to, - uint256 indexed sequenceNumber, - uint256 amount - ); - - event WithdrawalFinalized( - address l1Token, - address indexed from, - address indexed to, - uint256 indexed exitNum, - uint256 amount - ); -} diff --git a/contracts/arbitrum/interfaces/IL2TokenGateway.sol b/contracts/arbitrum/interfaces/IL2TokenGateway.sol deleted file mode 100644 index 182e157b..00000000 --- a/contracts/arbitrum/interfaces/IL2TokenGateway.sol +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Lido -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity 0.8.10; - -import {IInterchainTokenGateway} from "./IInterchainTokenGateway.sol"; - -/// @author psirex -/// @notice L2 part of the tokens bridge compatible with Arbitrum's GatewayRouter -interface IL2TokenGateway is IInterchainTokenGateway { - /// @notice Initiates the withdrawing process from the Arbitrum chain into the Ethereum chain - /// @param l1Token_ Address in the L1 chain of the token to withdraw - /// @param to_ Address of the recipient of the token on the corresponding chain - /// @param amount_ Amount of tokens to bridge - /// @param data_ Additional data required for transaction - function outboundTransfer( - address l1Token_, - address to_, - uint256 amount_, - uint256 maxGas_, - uint256 gasPriceBid_, - bytes calldata data_ - ) external returns (bytes memory); - - event DepositFinalized( - address indexed l1Token, - address indexed from, - address indexed to, - uint256 amount - ); - - event WithdrawalInitiated( - address l1Token, - address indexed from, - address indexed to, - uint256 indexed l2ToL1Id, - uint256 exitNum, - uint256 amount - ); -} diff --git a/contracts/arbitrum/interfaces/IOutbox.sol b/contracts/arbitrum/interfaces/IOutbox.sol deleted file mode 100644 index 02fe1d64..00000000 --- a/contracts/arbitrum/interfaces/IOutbox.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Lido -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity 0.8.10; - -interface IOutbox { - function l2ToL1Sender() external view returns (address); -} diff --git a/contracts/arbitrum/libraries/L1OutboundDataParser.sol b/contracts/arbitrum/libraries/L1OutboundDataParser.sol deleted file mode 100644 index 03c99b8b..00000000 --- a/contracts/arbitrum/libraries/L1OutboundDataParser.sol +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Lido -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity 0.8.10; - -/// @author psirex -/// @notice A helper library to parse data passed to outboundTransfer() of L1TokensGateway -library L1OutboundDataParser { - /// @dev Decodes value contained in data_ bytes array and returns it - /// @param router_ Address of the Arbitrum’s L1GatewayRouter - /// @param data_ Data encoded for the outboundTransfer() method - /// @return Decoded (from, maxSubmissionCost) values - function decode(address router_, bytes memory data_) - internal - view - returns (address, uint256) - { - if (msg.sender != router_) { - return (msg.sender, _parseSubmissionCostData(data_)); - } - (address from, bytes memory extraData) = abi.decode( - data_, - (address, bytes) - ); - return (from, _parseSubmissionCostData(extraData)); - } - - /// @dev Extracts the maxSubmissionCost value from the outboundTransfer() data - function _parseSubmissionCostData(bytes memory data_) - private - pure - returns (uint256) - { - (uint256 maxSubmissionCost, bytes memory extraData) = abi.decode( - data_, - (uint256, bytes) - ); - if (extraData.length != 0) { - revert ExtraDataNotEmpty(); - } - return maxSubmissionCost; - } - - error ExtraDataNotEmpty(); -} diff --git a/contracts/arbitrum/libraries/L2OutboundDataParser.sol b/contracts/arbitrum/libraries/L2OutboundDataParser.sol deleted file mode 100644 index f10acf90..00000000 --- a/contracts/arbitrum/libraries/L2OutboundDataParser.sol +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Lido -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity 0.8.10; - -/// @author psirex -/// @notice A helper library to parse data passed to outboundTransfer() of L2ERC20TokenGateway -library L2OutboundDataParser { - /// @dev Decodes value contained in data_ bytes array and returns it - /// @param router_ Address of the Arbitrum’s L2GatewayRouter - /// @param data_ Data encoded for the outboundTransfer() method - /// @return from_ address of the sender - function decode(address router_, bytes memory data_) - internal - view - returns (address from_) - { - bytes memory extraData; - if (msg.sender == router_) { - (from_, extraData) = abi.decode(data_, (address, bytes)); - } else { - (from_, extraData) = (msg.sender, data_); - } - if (extraData.length != 0) { - revert ExtraDataNotEmpty(); - } - } - - error ExtraDataNotEmpty(); -} diff --git a/contracts/arbitrum/stubs/ArbSysStub.sol b/contracts/arbitrum/stubs/ArbSysStub.sol deleted file mode 100644 index 5315414b..00000000 --- a/contracts/arbitrum/stubs/ArbSysStub.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Lido -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity 0.8.10; - -contract ArbSysStub { - uint256 public l2ToL1TxId; - - function setl2ToL1TxId(uint256 l2ToL1TxId_) public { - l2ToL1TxId = l2ToL1TxId_; - } - - function sendTxToL1(address recipient, bytes calldata data) - external - payable - returns (uint256) - { - l2ToL1TxId += 1; - emit CreateL2ToL1Tx(recipient, data); - return l2ToL1TxId; - } - - event CreateL2ToL1Tx(address recipient, bytes data); -} diff --git a/contracts/arbitrum/stubs/BridgeStub.sol b/contracts/arbitrum/stubs/BridgeStub.sol deleted file mode 100644 index 9498e68e..00000000 --- a/contracts/arbitrum/stubs/BridgeStub.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Lido -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity 0.8.10; - -import {IBridge} from "../interfaces/IBridge.sol"; - -contract BridgeStub is IBridge { - address public activeOutbox; - - constructor(address activeOutbox_) payable { - activeOutbox = activeOutbox_; - } - - function setOutbox(address outbox_) external { - activeOutbox = outbox_; - } -} diff --git a/contracts/arbitrum/stubs/InboxStub.sol b/contracts/arbitrum/stubs/InboxStub.sol deleted file mode 100644 index 7cd5e884..00000000 --- a/contracts/arbitrum/stubs/InboxStub.sol +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Lido -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity 0.8.10; - -import {IInbox} from "../interfaces/IInbox.sol"; - -contract InboxStub is IInbox { - uint256 public retryableTicketId; - address public immutable bridge; - - constructor(address bridge_) { - bridge = bridge_; - } - - function setRetryableTicketId(uint256 retryableTicketId_) public { - retryableTicketId = retryableTicketId_; - } - - function createRetryableTicket( - address destAddr, - uint256 arbTxCallValue, - uint256 maxSubmissionCost, - address submissionRefundAddress, - address valueRefundAddress, - uint256 maxGas, - uint256 gasPriceBid, - bytes calldata data - ) external payable returns (uint256) { - emit CreateRetryableTicketCalled( - msg.value, - destAddr, - arbTxCallValue, - maxSubmissionCost, - submissionRefundAddress, - valueRefundAddress, - maxGas, - gasPriceBid, - data - ); - return retryableTicketId; - } - - event CreateRetryableTicketCalled( - uint256 value, - address destAddr, - uint256 arbTxCallValue, - uint256 maxSubmissionCost, - address submissionRefundAddress, - address valueRefundAddress, - uint256 maxGas, - uint256 gasPriceBid, - bytes data - ); -} diff --git a/contracts/arbitrum/stubs/OutboxStub.sol b/contracts/arbitrum/stubs/OutboxStub.sol deleted file mode 100644 index 4278af8c..00000000 --- a/contracts/arbitrum/stubs/OutboxStub.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Lido -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity 0.8.10; - -import {IOutbox} from "../interfaces/IOutbox.sol"; - -contract OutboxStub is IOutbox { - address public l2ToL1Sender; - - function setL2ToL1Sender(address l2ToL1Sender_) external { - l2ToL1Sender = l2ToL1Sender_; - } -} diff --git a/hardhat.config.ts b/hardhat.config.ts index ed47221c..83cac4bd 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -15,15 +15,6 @@ dotenv.config(); const config: HardhatUserConfig = { solidity: { compilers: [ - { - version: "0.6.11", - settings: { - optimizer: { - enabled: true, - runs: 100, - }, - }, - }, { version: "0.8.10", settings: { @@ -52,22 +43,6 @@ const config: HardhatUserConfig = { url: "http://localhost:8545", }, - // Arbitrum Public Chains - arb_mainnet: { - url: env.string("RPC_ARB_MAINNET", ""), - }, - arb_sepolia: { - url: env.string("RPC_ARB_SEPOLIA", ""), - }, - - // Arbitrum Fork Chains - arb_mainnet_fork: { - url: "http://localhost:8546", - }, - arb_sepolia_fork: { - url: "http://localhost:8546", - }, - // Optimism Public Chains opt_mainnet: { url: env.string("RPC_OPT_MAINNET", ""), @@ -92,7 +67,6 @@ const config: HardhatUserConfig = { apiKey: { mainnet: env.string("ETHERSCAN_API_KEY_ETH", ""), sepolia: env.string("ETHERSCAN_API_KEY_ETH", ""), - arbitrumOne: env.string("ETHERSCAN_API_KEY_ARB", ""), optimisticEthereum: env.string("ETHERSCAN_API_KEY_OPT", ""), "opt_sepolia": env.string("ETHERSCAN_API_KEY_OPT", ""), }, @@ -120,7 +94,6 @@ const config: HardhatUserConfig = { externalArtifacts: [ "./interfaces/**/*.json", "./utils/optimism/artifacts/*.json", - "./utils/arbitrum/artifacts/*.json", ], }, mocha: { diff --git a/interfaces/arbitrum/Bridge.json b/interfaces/arbitrum/Bridge.json deleted file mode 100644 index fbbbd6f5..00000000 --- a/interfaces/arbitrum/Bridge.json +++ /dev/null @@ -1,265 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "outbox", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "destAddr", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "BridgeCallTriggered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "inbox", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "enabled", - "type": "bool" - } - ], - "name": "InboxToggle", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "messageIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "beforeInboxAcc", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "address", - "name": "inbox", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint8", - "name": "kind", - "type": "uint8" - }, - { - "indexed": false, - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "messageDataHash", - "type": "bytes32" - } - ], - "name": "MessageDelivered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "outbox", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "enabled", - "type": "bool" - } - ], - "name": "OutboxToggle", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "inputs": [], - "name": "activeOutbox", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "name": "allowedInboxList", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "inbox", "type": "address" } - ], - "name": "allowedInboxes", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "name": "allowedOutboxList", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "outbox", "type": "address" } - ], - "name": "allowedOutboxes", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "uint8", "name": "kind", "type": "uint8" }, - { "internalType": "address", "name": "sender", "type": "address" }, - { - "internalType": "bytes32", - "name": "messageDataHash", - "type": "bytes32" - } - ], - "name": "deliverMessageToInbox", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "destAddr", "type": "address" }, - { "internalType": "uint256", "name": "amount", "type": "uint256" }, - { "internalType": "bytes", "name": "data", "type": "bytes" } - ], - "name": "executeCall", - "outputs": [ - { "internalType": "bool", "name": "success", "type": "bool" }, - { "internalType": "bytes", "name": "returnData", "type": "bytes" } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "name": "inboxAccs", - "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "messageCount", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "inbox", "type": "address" }, - { "internalType": "bool", "name": "enabled", "type": "bool" } - ], - "name": "setInbox", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "outbox", "type": "address" }, - { "internalType": "bool", "name": "enabled", "type": "bool" } - ], - "name": "setOutbox", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "newOwner", "type": "address" } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/interfaces/arbitrum/IMessageProvider.json b/interfaces/arbitrum/IMessageProvider.json deleted file mode 100644 index a4ae9c5c..00000000 --- a/interfaces/arbitrum/IMessageProvider.json +++ /dev/null @@ -1,21 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "messageNum", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "InboxMessageDelivered", - "type": "event" - } -] diff --git a/interfaces/arbitrum/Inbox.json b/interfaces/arbitrum/Inbox.json deleted file mode 100644 index 9c224494..00000000 --- a/interfaces/arbitrum/Inbox.json +++ /dev/null @@ -1,328 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "messageNum", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "InboxMessageDelivered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "messageNum", - "type": "uint256" - } - ], - "name": "InboxMessageDeliveredFromOrigin", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bool", - "name": "enabled", - "type": "bool" - } - ], - "name": "PauseToggled", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bool", - "name": "enabled", - "type": "bool" - } - ], - "name": "RewriteToggled", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newSource", - "type": "address" - } - ], - "name": "WhitelistSourceUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "bridge", - "outputs": [ - { "internalType": "contract IBridge", "name": "", "type": "address" } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "destAddr", "type": "address" }, - { "internalType": "uint256", "name": "l2CallValue", "type": "uint256" }, - { - "internalType": "uint256", - "name": "maxSubmissionCost", - "type": "uint256" - }, - { - "internalType": "address", - "name": "excessFeeRefundAddress", - "type": "address" - }, - { - "internalType": "address", - "name": "callValueRefundAddress", - "type": "address" - }, - { "internalType": "uint256", "name": "maxGas", "type": "uint256" }, - { "internalType": "uint256", "name": "gasPriceBid", "type": "uint256" }, - { "internalType": "bytes", "name": "data", "type": "bytes" } - ], - "name": "createRetryableTicket", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "destAddr", "type": "address" }, - { "internalType": "uint256", "name": "l2CallValue", "type": "uint256" }, - { - "internalType": "uint256", - "name": "maxSubmissionCost", - "type": "uint256" - }, - { - "internalType": "address", - "name": "excessFeeRefundAddress", - "type": "address" - }, - { - "internalType": "address", - "name": "callValueRefundAddress", - "type": "address" - }, - { "internalType": "uint256", "name": "maxGas", "type": "uint256" }, - { "internalType": "uint256", "name": "gasPriceBid", "type": "uint256" }, - { "internalType": "bytes", "name": "data", "type": "bytes" } - ], - "name": "createRetryableTicketNoRefundAliasRewrite", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "maxSubmissionCost", - "type": "uint256" - } - ], - "name": "depositEth", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract IBridge", - "name": "_bridge", - "type": "address" - }, - { "internalType": "address", "name": "_whitelist", "type": "address" } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "isCreateRetryablePaused", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "isMaster", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "pauseCreateRetryables", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "uint256", "name": "maxGas", "type": "uint256" }, - { "internalType": "uint256", "name": "gasPriceBid", "type": "uint256" }, - { "internalType": "address", "name": "destAddr", "type": "address" }, - { "internalType": "uint256", "name": "amount", "type": "uint256" }, - { "internalType": "bytes", "name": "data", "type": "bytes" } - ], - "name": "sendContractTransaction", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "uint256", "name": "maxGas", "type": "uint256" }, - { "internalType": "uint256", "name": "gasPriceBid", "type": "uint256" }, - { "internalType": "address", "name": "destAddr", "type": "address" }, - { "internalType": "bytes", "name": "data", "type": "bytes" } - ], - "name": "sendL1FundedContractTransaction", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "uint256", "name": "maxGas", "type": "uint256" }, - { "internalType": "uint256", "name": "gasPriceBid", "type": "uint256" }, - { "internalType": "uint256", "name": "nonce", "type": "uint256" }, - { "internalType": "address", "name": "destAddr", "type": "address" }, - { "internalType": "bytes", "name": "data", "type": "bytes" } - ], - "name": "sendL1FundedUnsignedTransaction", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "bytes", "name": "messageData", "type": "bytes" } - ], - "name": "sendL2Message", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "bytes", "name": "messageData", "type": "bytes" } - ], - "name": "sendL2MessageFromOrigin", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "uint256", "name": "maxGas", "type": "uint256" }, - { "internalType": "uint256", "name": "gasPriceBid", "type": "uint256" }, - { "internalType": "uint256", "name": "nonce", "type": "uint256" }, - { "internalType": "address", "name": "destAddr", "type": "address" }, - { "internalType": "uint256", "name": "amount", "type": "uint256" }, - { "internalType": "bytes", "name": "data", "type": "bytes" } - ], - "name": "sendUnsignedTransaction", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "shouldRewriteSender", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "startRewriteAddress", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "stopRewriteAddress", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "unpauseCreateRetryables", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "destAddr", "type": "address" }, - { "internalType": "uint256", "name": "l2CallValue", "type": "uint256" }, - { - "internalType": "uint256", - "name": "maxSubmissionCost", - "type": "uint256" - }, - { - "internalType": "address", - "name": "excessFeeRefundAddress", - "type": "address" - }, - { - "internalType": "address", - "name": "callValueRefundAddress", - "type": "address" - }, - { "internalType": "uint256", "name": "maxGas", "type": "uint256" }, - { "internalType": "uint256", "name": "gasPriceBid", "type": "uint256" }, - { "internalType": "bytes", "name": "data", "type": "bytes" } - ], - "name": "unsafeCreateRetryableTicket", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "newSource", "type": "address" } - ], - "name": "updateWhitelistSource", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "whitelist", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - } -] diff --git a/package-lock.json b/package-lock.json index cfddd6b4..f0518138 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,6 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@arbitrum/sdk": "3.1.6", "@eth-optimism/sdk": "3.2.0", "@ethersproject/providers": "^5.6.8", "@lidofinance/evm-script-decoder": "^0.2.2", @@ -58,22 +57,6 @@ "node": ">=0.10.0" } }, - "node_modules/@arbitrum/sdk": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/@arbitrum/sdk/-/sdk-3.1.6.tgz", - "integrity": "sha512-wY7RHmvY26yc/OuwpJY+kjgAmUJZDGDXaQxfSQTp2t6sSFO+8oFFVsKIthBCY2RpDGFUVTGpRjCUEXiuJ6/SFA==", - "dependencies": { - "@ethersproject/address": "^5.0.8", - "@ethersproject/bignumber": "^5.1.1", - "@ethersproject/bytes": "^5.0.8", - "ethers": "^5.1.0" - }, - "engines": { - "node": ">=v11", - "npm": "please-use-yarn", - "yarn": ">= 1.0.0" - } - }, "node_modules/@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -24823,17 +24806,6 @@ "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", "dev": true }, - "@arbitrum/sdk": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/@arbitrum/sdk/-/sdk-3.1.6.tgz", - "integrity": "sha512-wY7RHmvY26yc/OuwpJY+kjgAmUJZDGDXaQxfSQTp2t6sSFO+8oFFVsKIthBCY2RpDGFUVTGpRjCUEXiuJ6/SFA==", - "requires": { - "@ethersproject/address": "^5.0.8", - "@ethersproject/bignumber": "^5.1.1", - "@ethersproject/bytes": "^5.0.8", - "ethers": "^5.1.0" - } - }, "@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", diff --git a/package.json b/package.json index 820a38ee..0207de90 100644 --- a/package.json +++ b/package.json @@ -12,18 +12,8 @@ "test:integration": "hardhat test ./test/**/*.integration.test.ts", "fork:eth:mainnet": "hardhat node:fork eth_mainnet 8545", "fork:eth:sepolia": "hardhat node:fork eth_sepolia 8545", - "fork:arb:sepolia": "hardhat node:fork arb_sepolia 8546", - "fork:arb:mainnet": "hardhat node:fork arb_mainnet 8546", "fork:opt:sepolia": "hardhat node:fork opt_sepolia 9545", "fork:opt:mainnet": "hardhat node:fork opt_mainnet 9545", - "arbitrum:deploy": "ts-node --files ./scripts/arbitrum/deploy-gateway.ts", - "arbitrum:finalize-message": "ts-node --files ./scripts/arbitrum/finalize-message.ts", - "arbitrum:test:e2e": "hardhat test ./test/arbitrum/*.e2e.test.ts", - "arbitrum:test:unit": "hardhat test ./test/arbitrum/*.unit.test.ts", - "arbitrum:test:integration": "hardhat test ./test/arbitrum/*.integration.test.ts", - "arbitrum:test:acceptance": "hardhat test ./test/arbitrum/*.acceptance.test.ts", - "arbitrum:test:executor": "hardhat test ./test/bridge-executor/arbitrum.integration.test.ts", - "arbitrum:test:launch": "REVERT=false hardhat test ./test/arbitrum/{_launch.test.ts,bridging.integration.test.ts}", "optimism:deploy": "ts-node --files ./scripts/optimism/deploy-bridge.ts", "optimism:finalize-message": "ts-node --files ./scripts/optimism/finalize-message.ts", "optimism:test:e2e": "hardhat test ./test/optimism/*.e2e.test.ts", @@ -69,7 +59,6 @@ "typescript": "^4.6.3" }, "dependencies": { - "@arbitrum/sdk": "3.1.6", "@eth-optimism/sdk": "3.2.0", "@ethersproject/providers": "^5.6.8", "@lidofinance/evm-script-decoder": "^0.2.2", diff --git a/scripts/arbitrum/deploy-gateway-routers.ts b/scripts/arbitrum/deploy-gateway-routers.ts deleted file mode 100644 index ef48beea..00000000 --- a/scripts/arbitrum/deploy-gateway-routers.ts +++ /dev/null @@ -1,28 +0,0 @@ -import arbitrum from "../../utils/arbitrum"; -import env from "../../utils/env"; -import network from "../../utils/network"; -import prompt from "../../utils/prompt"; - -async function main() { - const networkName = env.network(); - - const [ethDeployer, arbDeployer] = network - .multichain(["eth", "arb"], networkName) - .getSigners(env.privateKey(), { forking: env.forking() }); - - const [l1DeployScript, l2DeployScript] = await arbitrum - .deployment(networkName, { logger: console }) - .gatewayRouterDeployScript(ethDeployer, arbDeployer); - - l1DeployScript.print(); - l2DeployScript.print(); - await prompt.proceed(); - - await l1DeployScript.run(); - await l2DeployScript.run(); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); diff --git a/scripts/arbitrum/deploy-gateway.ts b/scripts/arbitrum/deploy-gateway.ts deleted file mode 100644 index cebe3dbd..00000000 --- a/scripts/arbitrum/deploy-gateway.ts +++ /dev/null @@ -1,77 +0,0 @@ -import env from "../../utils/env"; -import prompt from "../../utils/prompt"; -import network from "../../utils/network"; -import arbitrum from "../../utils/arbitrum"; -import deployment from "../../utils/deployment"; -import { BridgingManagement } from "../../utils/bridging-management"; - -async function main() { - const networkName = env.network(); - const [ethDeployer] = network - .multichain(["eth", "arb"], networkName) - .getSigners(env.privateKey(), { forking: env.forking() }); - - const [, arbDeployer] = network - .multichain(["eth", "arb"], networkName) - .getSigners(env.string("ARB_DEPLOYER_PRIVATE_KEY"), { - forking: env.forking(), - }); - - const deploymentConfig = deployment.loadMultiChainDeploymentConfig(); - - const [l1DeployScript, l2DeployScript] = await arbitrum - .deployment(networkName, { logger: console }) - .erc20TokenGatewayDeployScript( - deploymentConfig.token, - { - deployer: ethDeployer, - admins: { - proxy: deploymentConfig.l1.proxyAdmin, - bridge: ethDeployer.address, - }, - }, - { - deployer: arbDeployer, - admins: { - proxy: deploymentConfig.l2.proxyAdmin, - bridge: arbDeployer.address, - }, - } - ); - - await deployment.printMultiChainDeploymentConfig( - "Deploy Arbitrum Gateway", - ethDeployer, - arbDeployer, - deploymentConfig, - l1DeployScript, - l2DeployScript - ); - - await prompt.proceed(); - - await l1DeployScript.run(); - await l2DeployScript.run(); - - const l1ERC20TokenGatewayProxyDeployStepIndex = 1; - const l1BridgingManagement = new BridgingManagement( - l1DeployScript.getContractAddress(l1ERC20TokenGatewayProxyDeployStepIndex), - ethDeployer, - { logger: console } - ); - - const l2ERC20TokenGatewayProxyDeployStepIndex = 3; - const l2BridgingManagement = new BridgingManagement( - l2DeployScript.getContractAddress(l2ERC20TokenGatewayProxyDeployStepIndex), - arbDeployer, - { logger: console } - ); - - await l1BridgingManagement.setup(deploymentConfig.l1); - await l2BridgingManagement.setup(deploymentConfig.l2); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); diff --git a/scripts/arbitrum/finalize-message.ts b/scripts/arbitrum/finalize-message.ts deleted file mode 100644 index 5eb83975..00000000 --- a/scripts/arbitrum/finalize-message.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { L2ToL1MessageStatus, L2TransactionReceipt } from "@arbitrum/sdk"; -import env from "../../utils/env"; -import network from "../../utils/network"; - -async function main() { - const networkName = env.network(); - const ethArbNetwork = network.multichain(["eth", "arb"], networkName); - - const [ethProvider, arbProvider] = ethArbNetwork.getProviders({ - forking: false, - }); - const [ethSigner] = ethArbNetwork.getSigners(env.privateKey(), { - forking: false, - }); - - const l2TxHash = env.string("TX_HASH"); - - console.log("Tx hash:", l2TxHash); - - const receipt = await arbProvider.getTransactionReceipt(l2TxHash); - - if (!receipt) { - throw new Error( - `Receipt for tx ${l2TxHash} not found on "${networkName}" network` - ); - } - console.log(`Receipt for tx found!`); - - const l2Receipt = new L2TransactionReceipt(receipt); - - const messages = await l2Receipt.getL2ToL1Messages(ethSigner, arbProvider); - - const l2ToL1Msg = messages[0]; - - const status = await l2ToL1Msg.status(arbProvider); - if (status === L2ToL1MessageStatus.EXECUTED) { - console.log(`Message already executed! Nothing else to do here`); - return; - } - - const timeToWaitMs = 1000 * 60; - const [estimatedConfirmationBlock, currentBlock] = await Promise.all([ - l2ToL1Msg.getFirstExecutableBlock(arbProvider), - ethProvider.getBlockNumber(), - ]); - - if (estimatedConfirmationBlock) { - console.log( - `Estimated block number tx will be confirmed: ${estimatedConfirmationBlock.toString()}` - ); - console.log(`Current block number is ${currentBlock}`); - } - console.log("Waiting for the outbox entry to be created..."); - - await l2ToL1Msg.waitUntilReadyToExecute(arbProvider, timeToWaitMs); - console.log("Outbox entry exists! Trying to execute now"); - - const res = await l2ToL1Msg.execute(arbProvider); - const rec = await res.wait(); - console.log("Done! Your transaction is executed", rec); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); diff --git a/scripts/arbitrum/update-ethereum-executor.ts b/scripts/arbitrum/update-ethereum-executor.ts deleted file mode 100644 index e4407706..00000000 --- a/scripts/arbitrum/update-ethereum-executor.ts +++ /dev/null @@ -1,161 +0,0 @@ -import env from "../../utils/env"; -import network from "../../utils/network"; -import lido from "../../utils/lido"; -import arbitrum from "../../utils/arbitrum"; -import { GovBridgeExecutor__factory } from "../../typechain"; -import { assert } from "chai"; -import { L1ToL2MessageStatus } from "@arbitrum/sdk"; -import prompt from "../../utils/prompt"; -import { ethers } from "hardhat"; - -// Set address of the bridge executor to run the script -const GOV_BRIDGE_EXECUTOR = ""; - -async function main() { - const isForking = env.forking(); - const networkName = env.network(); - const ethArbNetwork = network.multichain(["eth", "arb"], networkName); - - const [l1LDOHolder] = ethArbNetwork.getSigners( - env.string("TESTING_ARB_LDO_HOLDER_PRIVATE_KEY"), - { forking: isForking } - ); - const [, arbRunner] = ethArbNetwork.getSigners(env.privateKey(), { - forking: isForking, - }); - - const govBridgeExecutor = GovBridgeExecutor__factory.connect( - GOV_BRIDGE_EXECUTOR, - arbRunner - ); - - const newEthExecutorLidoDAO = lido(networkName, l1LDOHolder); - const oldEthExecutorLidoDAO = lido( - networkName === "mainnet" ? "mainnet_test" : networkName, - l1LDOHolder - ); - const prevEthGovExecutorAddress = - await govBridgeExecutor.getEthereumGovernanceExecutor(); - - assert.equal( - oldEthExecutorLidoDAO.agent.address.toLocaleLowerCase(), - prevEthGovExecutorAddress.toLowerCase(), - `${oldEthExecutorLidoDAO.agent.address} is not current ethereumGovernanceExecutor` - ); - - console.log(` · Is forking: ${isForking}`); - console.log(` · Network Name: ${networkName}`); - console.log( - ` · Prev Ethereum Governance Executor: ${prevEthGovExecutorAddress}` - ); - console.log( - ` · New Ethereum Governance Executor: ${newEthExecutorLidoDAO.agent.address}` - ); - console.log(` · LDO Holder: ${l1LDOHolder.address}`); - console.log(` · LDO Holder ETH balance: ${await l1LDOHolder.getBalance()}`); - console.log(` · L2 tx runner: ${arbRunner.address}`); - console.log(` · L2 tx runner ETH balance: ${await arbRunner.getBalance()}`); - - await prompt.proceed(); - - console.log(`Preparing the voting tx...`); - - const arbAddresses = arbitrum.addresses(networkName); - - // Prepare data for Governance Bridge Executor - const executorCalldata = await govBridgeExecutor.interface.encodeFunctionData( - "queue", - [ - [GOV_BRIDGE_EXECUTOR], - [0], - ["updateEthereumGovernanceExecutor(address)"], - [ - ethers.utils.defaultAbiCoder.encode( - ["address"], - [newEthExecutorLidoDAO.agent.address] - ), - ], - [false], - ] - ); - - const { callvalue, calldata } = await arbitrum - .messaging(networkName, { forking: isForking }) - .prepareRetryableTicketTx({ - calldata: executorCalldata, - recipient: GOV_BRIDGE_EXECUTOR, - refundAddress: l1LDOHolder.address, - sender: oldEthExecutorLidoDAO.agent.address, - }); - - const txTransfer = await l1LDOHolder.sendTransaction({ - to: oldEthExecutorLidoDAO.agent.address, - value: callvalue, - }); - - await txTransfer.wait(); - - const createVoteTx = await oldEthExecutorLidoDAO.createVote( - l1LDOHolder, - "Update ethereumGovernanceExecutor on Arbitrum Governance Bridge Executor", - { - address: oldEthExecutorLidoDAO.agent.address, - signature: "execute(address,uint256,bytes)", - decodedCallData: [arbAddresses.Inbox, callvalue, calldata], - } - ); - - console.log("Creating voting to update ethereumGovernanceExecutor..."); - await createVoteTx.wait(); - console.log(`Vote was created!`); - - const votesCount = await oldEthExecutorLidoDAO.voting.votesLength(); - const voteId = votesCount.sub(1); - - console.log(`New vote id ${voteId.toString()}`); - console.log(`Voting for and executing the vote...`); - - const voteAndExecuteTx = await oldEthExecutorLidoDAO.voteAndExecute( - l1LDOHolder, - voteId, - true - ); - const executeTxReceipt = await voteAndExecuteTx.wait(); - - console.log(`Vote ${voteId.toString()} was executed!`); - - console.log("Waiting for L2 transaction..."); - const { status } = await arbitrum - .messaging(networkName, { forking: isForking }) - .waitForL2Message(executeTxReceipt.transactionHash); - - console.log(`Message delivered to L2`); - - assert.equal( - status, - L1ToL2MessageStatus.REDEEMED, - `L2 retryable txn failed with status ${L1ToL2MessageStatus[status]}` - ); - console.log("Task was queued on L2!"); - - console.log("Executing the queued task..."); - // execute task on L2 - const tasksCount = await govBridgeExecutor.getActionsSetCount(); - const targetTaskId = tasksCount.toNumber() - 1; - - const tx = await govBridgeExecutor.execute(targetTaskId); - await tx.wait(); - console.log("Task executed on L2!"); - - const ethereumGovernanceExecutor = - await govBridgeExecutor.getEthereumGovernanceExecutor(); - - console.log( - `New ethereum governance executor is: ${ethereumGovernanceExecutor}` - ); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); diff --git a/test/arbitrum/L1ERC20TokensGateway.unit.test.ts b/test/arbitrum/L1ERC20TokensGateway.unit.test.ts deleted file mode 100644 index fa997e5d..00000000 --- a/test/arbitrum/L1ERC20TokensGateway.unit.test.ts +++ /dev/null @@ -1,940 +0,0 @@ -import hre, { ethers } from "hardhat"; -import { wei } from "../../utils/wei"; -import { - BridgeStub__factory, - ERC20BridgedStub__factory, - InboxStub__factory, - L1ERC20TokenGateway__factory, - L2ERC20TokenGateway__factory, - OssifiableProxy__factory, - OutboxStub__factory, - EmptyContractStub__factory, -} from "../../typechain"; -import { assert } from "chai"; -import { unit } from "../../utils/testing"; - -unit("Arbitrum :: L1ERC20TokensGateway", ctxFactory) - .test("l1Token() ", async (ctx) => { - assert.equal( - await ctx.l1TokensGateway.l1Token(), - ctx.stubs.l1Token.address - ); - }) - - .test("l2Token()", async (ctx) => { - assert.equal( - await ctx.l1TokensGateway.l2Token(), - ctx.stubs.l2Token.address - ); - }) - - .test("counterpartGateway()", async (ctx) => { - assert.equal( - await ctx.l1TokensGateway.counterpartGateway(), - ctx.stubs.l2TokensGateway.address - ); - }) - - .test("router()", async (ctx) => { - assert.equal( - await ctx.l1TokensGateway.router(), - ctx.stubs.l1Router.address - ); - }) - - .test("calculateL2TokenAddress() :: correct l1Token", async (ctx) => { - const actualL2TokenAddress = - await ctx.l1TokensGateway.calculateL2TokenAddress( - ctx.stubs.l1Token.address - ); - assert.equal(actualL2TokenAddress, ctx.stubs.l2Token.address); - }) - - .test("calculateL2TokenAddress() :: incorrect l1Token", async (ctx) => { - const wrongAddress = ctx.accounts.stranger.address; - const actualL2TokenAddress = - await ctx.l1TokensGateway.calculateL2TokenAddress(wrongAddress); - assert.equal(actualL2TokenAddress, hre.ethers.constants.AddressZero); - }) - - .test("getOutboundCalldata()", async (ctx) => { - const [sender, recipient] = await hre.ethers.getSigners(); - const amount = wei`1.5 ether`; - const actualCalldata = await ctx.l1TokensGateway.getOutboundCalldata( - ctx.stubs.l1Token.address, - sender.address, - recipient.address, - amount, - "0x" - ); - - const expectedCalldata = - ctx.stubs.l2TokensGateway.interface.encodeFunctionData( - "finalizeInboundTransfer", - [ - ctx.stubs.l1Token.address, - sender.address, - recipient.address, - amount, - "0x", - ] - ); - - assert.equal(actualCalldata, expectedCalldata); - }) - - .test("outboundTransfer() :: deposits are disabled", async (ctx) => { - // validate deposits are disabled - assert.isFalse(await ctx.l1TokensGateway.isDepositsEnabled()); - - const [sender, recipient] = await hre.ethers.getSigners(); - const amount = wei`1.2 ether`; - const maxGas = wei`1000 gwei`; - const gasPriceBid = wei`2000 gwei`; - const maxSubmissionCost = wei`11_000 gwei`; - const data = encodeSenderOutboundTransferData(maxSubmissionCost); - - // validate deposit reverts with error ErrorDepositsDisabled() - await assert.revertsWith( - ctx.l1TokensGateway - .connect(sender) - .outboundTransfer( - ctx.stubs.l1Token.address, - recipient.address, - amount, - maxGas, - gasPriceBid, - data - ), - "ErrorDepositsDisabled()" - ); - }) - - .test("outboundTransfer() :: wrong l1Token address", async (ctx) => { - const [sender, recipient, wrongAddress] = await hre.ethers.getSigners(); - const amount = wei`1.2 ether`; - const maxGas = wei`1000 gwei`; - const gasPriceBid = wei`2000 gwei`; - const maxSubmissionCost = wei`11_000 gwei`; - const data = encodeSenderOutboundTransferData(maxSubmissionCost); - - const { - l1TokensGateway, - accounts: { deployer }, - } = ctx; - - // initialize gateway - await l1TokensGateway.initialize(deployer.address); - - // validate gateway was initialized - assert.isTrue(await l1TokensGateway.isInitialized()); - - // grant DEPOSITS_ENABLER_ROLE to the l1Deployer to enable deposits - await l1TokensGateway.grantRole( - await l1TokensGateway.DEPOSITS_ENABLER_ROLE(), - deployer.address - ); - - // enable deposits - await l1TokensGateway.enableDeposits(); - - // validate deposits was enabled - assert.isTrue(await l1TokensGateway.isDepositsEnabled()); - - await assert.revertsWith( - l1TokensGateway - .connect(sender) - .outboundTransfer( - wrongAddress.address, - recipient.address, - amount, - maxGas, - gasPriceBid, - data - ), - "ErrorUnsupportedL1Token()" - ); - }) - - .test("outboundTransfer() :: max submission cost is zero", async (ctx) => { - const { - l1TokensGateway, - stubs: { l1Token, inbox }, - accounts: { deployer }, - } = ctx; - - // initialize gateway - await l1TokensGateway.initialize(deployer.address); - - // validate gateway was initialized - assert.isTrue(await l1TokensGateway.isInitialized()); - - // grant DEPOSITS_ENABLER_ROLE to the l1Deployer to enable deposits - await l1TokensGateway.grantRole( - await l1TokensGateway.DEPOSITS_ENABLER_ROLE(), - deployer.address - ); - - // enable deposits - await l1TokensGateway.enableDeposits(); - - // validate deposits was enabled - assert.isTrue(await l1TokensGateway.isDepositsEnabled()); - - const [sender, recipient] = await hre.ethers.getSigners(); - const amount = wei`1.2 ether`; - const maxGas = wei`1000 gwei`; - const gasPriceBid = wei`2000 gwei`; - const maxSubmissionCost = wei`0 wei`; - const value = wei`3000 gwei`; - const data = encodeSenderOutboundTransferData(maxSubmissionCost); - - // set allowance for l1TokensGateway before transfer - await l1Token.connect(sender).approve(l1TokensGateway.address, amount); - - const retryableTicketId = 13; - await inbox.setRetryableTicketId(retryableTicketId); - - assert.equalBN(await inbox.retryableTicketId(), retryableTicketId); - - // initiate outbound transfer - await assert.revertsWith( - l1TokensGateway - .connect(sender) - .outboundTransfer( - l1Token.address, - recipient.address, - amount, - maxGas, - gasPriceBid, - data, - { value } - ), - "ErrorNoMaxSubmissionCost()" - ); - }) - - .test("outboundTransfer() :: ETH value too low", async (ctx) => { - const { - l1TokensGateway, - stubs: { l1Token, inbox }, - accounts: { deployer }, - } = ctx; - - // initialize gateway - await l1TokensGateway.initialize(deployer.address); - - // validate gateway was initialized - assert.isTrue(await l1TokensGateway.isInitialized()); - - // grant DEPOSITS_ENABLER_ROLE to the l1Deployer to enable deposits - await l1TokensGateway.grantRole( - await l1TokensGateway.DEPOSITS_ENABLER_ROLE(), - deployer.address - ); - - // enable deposits - await l1TokensGateway.enableDeposits(); - - // validate deposits was enabled - assert.isTrue(await l1TokensGateway.isDepositsEnabled()); - - const [sender, recipient] = await hre.ethers.getSigners(); - const amount = wei`1.2 ether`; - const maxGas = wei`100_000`; - const gasPriceBid = wei`2 gwei`; - const maxSubmissionCost = wei`50_000 gwei`; - const value = wei`200_000 gwei`; - const data = encodeSenderOutboundTransferData(maxSubmissionCost); - - // set allowance for l1TokensGateway before transfer - await l1Token.connect(sender).approve(l1TokensGateway.address, amount); - - const retryableTicketId = 13; - await inbox.setRetryableTicketId(retryableTicketId); - - assert.equalBN(await inbox.retryableTicketId(), retryableTicketId); - - // initiate outbound transfer - await assert.revertsWith( - l1TokensGateway - .connect(sender) - .outboundTransfer( - l1Token.address, - recipient.address, - amount, - maxGas, - gasPriceBid, - data, - { value } - ), - "ErrorETHValueTooLow()" - ); - }) - - .test("outboundTransfer() :: extra data not empty", async (ctx) => { - const { - l1TokensGateway, - stubs: { l1Token }, - accounts: { deployer, l1RouterAsEOA }, - } = ctx; - - // initialize gateway - await l1TokensGateway.initialize(deployer.address); - - // validate gateway was initialized - assert.isTrue(await l1TokensGateway.isInitialized()); - - // grant DEPOSITS_ENABLER_ROLE to the l1Deployer to enable deposits - await l1TokensGateway.grantRole( - await l1TokensGateway.DEPOSITS_ENABLER_ROLE(), - deployer.address - ); - - // enable deposits - await l1TokensGateway.enableDeposits(); - - // validate deposits was enabled - assert.isTrue(await l1TokensGateway.isDepositsEnabled()); - - const [sender, recipient] = await hre.ethers.getSigners(); - const amount = wei`1.2 ether`; - const maxGas = wei`1000 gwei`; - const gasPriceBid = wei`2000 gwei`; - const maxSubmissionCost = wei`11_000 gwei`; - const value = wei`3000 gwei`; - const data = encodeRouterOutboundTransferData( - sender.address, - maxSubmissionCost, - "0xdeadbeef" - ); - - // initiate outbound transfer - await assert.revertsWith( - l1TokensGateway - .connect(l1RouterAsEOA) - .outboundTransfer( - l1Token.address, - recipient.address, - amount, - maxGas, - gasPriceBid, - data, - { value } - ), - "ExtraDataNotEmpty()" - ); - }) - - .test("outboundTransfer() :: ETH value too low", async (ctx) => { - const { - l1TokensGateway, - stubs: { l1Token, inbox }, - accounts: { deployer }, - } = ctx; - - // initialize gateway - await l1TokensGateway.initialize(deployer.address); - - // validate gateway was initialized - assert.isTrue(await l1TokensGateway.isInitialized()); - - // grant DEPOSITS_ENABLER_ROLE to the l1Deployer to enable deposits - await l1TokensGateway.grantRole( - await l1TokensGateway.DEPOSITS_ENABLER_ROLE(), - deployer.address - ); - - // enable deposits - await l1TokensGateway.enableDeposits(); - - // validate deposits was enabled - assert.isTrue(await l1TokensGateway.isDepositsEnabled()); - - const [sender, recipient] = await hre.ethers.getSigners(); - const amount = wei`1.2 ether`; - const maxGas = wei`100_000`; - const gasPriceBid = wei`2 gwei`; - const maxSubmissionCost = wei`50_000 gwei`; - const value = wei`200_000 gwei`; - const data = encodeSenderOutboundTransferData(maxSubmissionCost); - - // set allowance for l1TokensGateway before transfer - await l1Token.connect(sender).approve(l1TokensGateway.address, amount); - - const retryableTicketId = 13; - await inbox.setRetryableTicketId(retryableTicketId); - - assert.equalBN(await inbox.retryableTicketId(), retryableTicketId); - - // initiate outbound transfer - await assert.revertsWith( - l1TokensGateway - .connect(sender) - .outboundTransfer( - l1Token.address, - recipient.address, - amount, - maxGas, - gasPriceBid, - data, - { value } - ), - "ErrorETHValueTooLow()" - ); - }) - - .test("outboundTransfer() :: called by router", async (ctx) => { - const { - l1TokensGateway, - stubs: { l1Token, inbox, l2TokensGateway }, - accounts: { deployer, sender, recipient, l1RouterAsEOA }, - } = ctx; - - // initialize gateway - await l1TokensGateway.initialize(deployer.address); - - // validate gateway was initialized - assert.isTrue(await l1TokensGateway.isInitialized()); - - // grant DEPOSITS_ENABLER_ROLE to the l1Deployer to enable deposits - await l1TokensGateway.grantRole( - await l1TokensGateway.DEPOSITS_ENABLER_ROLE(), - deployer.address - ); - - // enable deposits - await l1TokensGateway.enableDeposits(); - - // validate deposits was enabled - assert.isTrue(await l1TokensGateway.isDepositsEnabled()); - - const amount = wei`1.2 ether`; - const maxGas = wei`100_000`; - const gasPriceBid = wei`2 gwei`; - const maxSubmissionCost = wei`50_000 gwei`; - const value = wei`250_000 gwei`; - const data = encodeRouterOutboundTransferData( - sender.address, - maxSubmissionCost - ); - - const retryableTicketId = 7; - await inbox.setRetryableTicketId(retryableTicketId); - - assert.equalBN(await inbox.retryableTicketId(), retryableTicketId); - - const senderBalanceBefore = await l1Token.balanceOf(sender.address); - - // set allowance for l1TokensGateway before transfer - await l1Token.connect(sender).approve(l1TokensGateway.address, amount); - - // call tx locally to check return value - assert.equal( - await l1TokensGateway - .connect(l1RouterAsEOA) - .callStatic.outboundTransfer( - l1Token.address, - recipient.address, - amount, - maxGas, - gasPriceBid, - data, - { value } - ), - hre.ethers.utils.defaultAbiCoder.encode(["uint256"], [retryableTicketId]) - ); - - // initiate outbound transfer - const tx = await l1TokensGateway - .connect(l1RouterAsEOA) - .outboundTransfer( - l1Token.address, - recipient.address, - amount, - maxGas, - gasPriceBid, - data, - { value } - ); - - // validate DepositInitiated event was emitted - await assert.emits(l1TokensGateway, tx, "DepositInitiated", [ - l1Token.address, - sender.address, - recipient.address, - retryableTicketId, - amount, - ]); - - const expectedCalldata = l2TokensGateway.interface.encodeFunctionData( - "finalizeInboundTransfer", - [l1Token.address, sender.address, recipient.address, amount, "0x"] - ); - - // validate TxToL2 was emitted - await assert.emits(l1TokensGateway, tx, "TxToL2", [ - sender.address, - l2TokensGateway.address, - retryableTicketId, - expectedCalldata, - ]); - - // validate CreateRetryableTicketCalled event was emitted - await assert.emits(inbox, tx, "CreateRetryableTicketCalled", [ - value, - l2TokensGateway.address, - 0, - maxSubmissionCost, - sender.address, - sender.address, - maxGas, - gasPriceBid, - expectedCalldata, - ]); - - // validate balance of the sender decreased - assert.equalBN( - await l1Token.balanceOf(sender.address), - senderBalanceBefore.sub(amount) - ); - - // validate balance of the gateway increased - assert.equalBN(await l1Token.balanceOf(l1TokensGateway.address), amount); - }) - - .test("outboundTransfer() :: called by sender", async (ctx) => { - const { - l1TokensGateway, - stubs: { l1Token, inbox, l2TokensGateway }, - accounts: { deployer }, - } = ctx; - - // initialize gateway - await l1TokensGateway.initialize(deployer.address); - - // validate gateway was initialized - assert.isTrue(await l1TokensGateway.isInitialized()); - - // grant DEPOSITS_ENABLER_ROLE to the l1Deployer to enable deposits - await l1TokensGateway.grantRole( - await l1TokensGateway.DEPOSITS_ENABLER_ROLE(), - deployer.address - ); - - // enable deposits - await l1TokensGateway.enableDeposits(); - - // validate deposits was enabled - assert.isTrue(await l1TokensGateway.isDepositsEnabled()); - - const [sender, recipient] = await hre.ethers.getSigners(); - const amount = wei`1.2 ether`; - const maxGas = wei`100_000`; - const gasPriceBid = wei`2 gwei`; - const maxSubmissionCost = wei`50_000 gwei`; - const value = wei`250_000 gwei`; - const data = encodeSenderOutboundTransferData(maxSubmissionCost); - - const senderBalanceBefore = await l1Token.balanceOf(sender.address); - - // set allowance for l1TokensGateway before transfer - await l1Token.connect(sender).approve(l1TokensGateway.address, amount); - - const retryableTicketId = 13; - await inbox.setRetryableTicketId(retryableTicketId); - - assert.equalBN(await inbox.retryableTicketId(), retryableTicketId); - - // initiate outbound transfer - const tx = await l1TokensGateway - .connect(sender) - .outboundTransfer( - l1Token.address, - recipient.address, - amount, - maxGas, - gasPriceBid, - data, - { value } - ); - - // validate DepositInitiated event was emitted - await assert.emits(l1TokensGateway, tx, "DepositInitiated", [ - l1Token.address, - sender.address, - recipient.address, - retryableTicketId, - amount, - ]); - - const expectedCalldata = l2TokensGateway.interface.encodeFunctionData( - "finalizeInboundTransfer", - [l1Token.address, sender.address, recipient.address, amount, "0x"] - ); - - // validate TxToL2 was emitted - await assert.emits(l1TokensGateway, tx, "TxToL2", [ - sender.address, - l2TokensGateway.address, - retryableTicketId, - expectedCalldata, - ]); - - // validate CreateRetryableTicketCalled event was emitted - await assert.emits(inbox, tx, "CreateRetryableTicketCalled", [ - value, - l2TokensGateway.address, - 0, - maxSubmissionCost, - sender.address, - sender.address, - maxGas, - gasPriceBid, - expectedCalldata, - ]); - - // validate balance of the sender decreased - assert.equalBN( - await l1Token.balanceOf(sender.address), - senderBalanceBefore.sub(amount) - ); - - // validate balance of the gateway increased - assert.equalBN(await l1Token.balanceOf(l1TokensGateway.address), amount); - }) - - .test("finalizeInboundTransfer() :: withdrawals disabled", async (ctx) => { - const { - l1TokensGateway, - accounts: { deployer, bridgeAsEOA, sender, recipient }, - stubs: { l1Token }, - } = ctx; - - // initialize gateway - await l1TokensGateway.initialize(deployer.address); - - // validate gateway was initialized - assert.isTrue(await l1TokensGateway.isInitialized()); - - // validate withdrawals disabled - assert.isFalse(await l1TokensGateway.isWithdrawalsEnabled()); - - await assert.revertsWith( - l1TokensGateway - .connect(bridgeAsEOA) - .finalizeInboundTransfer( - l1Token.address, - sender.address, - recipient.address, - wei`10 ether`, - "0x" - ), - "ErrorWithdrawalsDisabled()" - ); - }) - .test("finalizeInboundTransfer() :: unauthorized bridge", async (ctx) => { - const { - l1TokensGateway, - accounts: { deployer, stranger, sender, recipient }, - stubs: { l1Token }, - } = ctx; - - // initialize gateway - await l1TokensGateway.initialize(deployer.address); - - // validate gateway was initialized - assert.isTrue(await l1TokensGateway.isInitialized()); - - // grant WITHDRAWALS_ENABLER_ROLE to the l1Deployer to enable withdrawals - await l1TokensGateway.grantRole( - await l1TokensGateway.WITHDRAWALS_ENABLER_ROLE(), - deployer.address - ); - - // enable withdrawals - await l1TokensGateway.enableWithdrawals(); - - // validate withdrawals were enabled - assert.isTrue(await l1TokensGateway.isWithdrawalsEnabled()); - - // validate that stranger address is not counterpartGateway - assert.notEqual( - await l1TokensGateway.counterpartGateway(), - stranger.address - ); - - // validate gateway reverts with ErrorUnauthorizedBridge() - await assert.revertsWith( - l1TokensGateway - .connect(stranger) - .finalizeInboundTransfer( - l1Token.address, - sender.address, - recipient.address, - wei`10 ether`, - "0x" - ), - "ErrorUnauthorizedBridge()" - ); - }) - - .test( - "finalizeInboundTransfer() :: wrong cross domain sender", - async (ctx) => { - const { - l1TokensGateway, - accounts: { deployer, stranger, sender, recipient, bridgeAsEOA }, - stubs: { l1Token, outbox }, - } = ctx; - - // initialize gateway - await l1TokensGateway.initialize(deployer.address); - - // validate gateway was initialized - assert.isTrue(await l1TokensGateway.isInitialized()); - - // grant WITHDRAWALS_ENABLER_ROLE to the l1Deployer to enable withdrawals - await l1TokensGateway.grantRole( - await l1TokensGateway.WITHDRAWALS_ENABLER_ROLE(), - deployer.address - ); - - // enable withdrawals - await l1TokensGateway.enableWithdrawals(); - - // validate withdrawals were enabled - assert.isTrue(await l1TokensGateway.isWithdrawalsEnabled()); - - // validate that stranger address is not counterpartGateway - assert.notEqual( - await l1TokensGateway.counterpartGateway(), - stranger.address - ); - - // prepare OutboxStub to return wrong gateway address - await outbox.setL2ToL1Sender(stranger.address); - - // validate gateway reverts with ErrorWrongCrossDomainSender() - await assert.revertsWith( - l1TokensGateway - .connect(bridgeAsEOA) - .finalizeInboundTransfer( - l1Token.address, - sender.address, - recipient.address, - wei`10 ether`, - "0x" - ), - "ErrorWrongCrossDomainSender()" - ); - } - ) - - .test("finalizeInboundTransfer() :: wrong token", async (ctx) => { - const { - l1TokensGateway, - accounts: { stranger, sender, recipient, deployer, bridgeAsEOA }, - } = ctx; - const wrongTokenAddress = stranger.address; - - // initialize gateway - await l1TokensGateway.initialize(deployer.address); - - // validate gateway was initialized - assert.isTrue(await l1TokensGateway.isInitialized()); - - // grant WITHDRAWALS_ENABLER_ROLE to the l1Deployer to enable withdrawals - await l1TokensGateway.grantRole( - await l1TokensGateway.WITHDRAWALS_ENABLER_ROLE(), - deployer.address - ); - - // enable withdrawals - await l1TokensGateway.enableWithdrawals(); - - // validate withdrawals were enabled - assert.isTrue(await l1TokensGateway.isWithdrawalsEnabled()); - - // validate gateway reverts with ErrorUnsupportedL1Token() - await assert.revertsWith( - l1TokensGateway - .connect(bridgeAsEOA) - .finalizeInboundTransfer( - wrongTokenAddress, - sender.address, - recipient.address, - wei`10 ether`, - "0x" - ), - "ErrorUnsupportedL1Token()" - ); - }) - - .test("finalizeInboundTransfer() :: works as expected", async (ctx) => { - const { - l1TokensGateway, - accounts: { sender, recipient, deployer, bridgeAsEOA }, - stubs: { l1Token }, - } = ctx; - - // initialize gateway - await l1TokensGateway.initialize(deployer.address); - - // validate gateway was initialized - assert.isTrue(await l1TokensGateway.isInitialized()); - - // grant WITHDRAWALS_ENABLER_ROLE to the l1Deployer to enable withdrawals - await l1TokensGateway.grantRole( - await l1TokensGateway.WITHDRAWALS_ENABLER_ROLE(), - deployer.address - ); - - // enable withdrawals - await l1TokensGateway.enableWithdrawals(); - - // validate withdrawals were enabled - assert.isTrue(await l1TokensGateway.isWithdrawalsEnabled()); - - // transfer l1Tokens to l1TokensGateway - const initialL1GatewayBalance = wei`10_000 ether`; - await l1Token.transfer(l1TokensGateway.address, initialL1GatewayBalance); - - // validate l1TokensGateway has enough amount of tokens - assert.equal( - await l1Token.balanceOf(l1TokensGateway.address).then(wei.fromBigNumber), - initialL1GatewayBalance - ); - - const amount = wei`10 ether`; - - const tx = await l1TokensGateway - .connect(bridgeAsEOA) - .finalizeInboundTransfer( - l1Token.address, - sender.address, - recipient.address, - amount, - "0x" - ); - - // validate WithdrawalFinalized was emitted - assert.emits(l1TokensGateway, tx, "WithdrawalFinalized", [ - l1Token.address, - sender.address, - recipient.address, - 0, - amount, - ]); - - // validate tokens were transferred to recipient - assert.equalBN(await l1Token.balanceOf(recipient.address), amount); - - // validate balance of the l1TokensGateway was decreased - assert.equalBN( - await l1Token.balanceOf(l1TokensGateway.address), - wei.toBigNumber(initialL1GatewayBalance).sub(amount) - ); - }) - - .run(); - -async function ctxFactory() { - const [deployer, stranger, sender, recipient] = await hre.ethers.getSigners(); - const outboxStub = await new OutboxStub__factory(deployer).deploy(); - const bridgeStub = await new BridgeStub__factory(deployer).deploy( - outboxStub.address, - { value: wei.toBigNumber(wei`1 ether`) } - ); - const inboxStub = await new InboxStub__factory(deployer).deploy( - bridgeStub.address - ); - const l1RouterStub = await new EmptyContractStub__factory(deployer).deploy({ - value: wei.toBigNumber(wei`1 ether`), - }); - const l2TokensGatewayStub = await new EmptyContractStub__factory( - deployer - ).deploy(); - - await outboxStub.setL2ToL1Sender(l2TokensGatewayStub.address); - await hre.network.provider.request({ - method: "hardhat_impersonateAccount", - params: [bridgeStub.address], - }); - const l2TokenStub = await new EmptyContractStub__factory(deployer).deploy(); - const l1TokenStub = await new ERC20BridgedStub__factory(deployer).deploy( - "ERC20 Mock", - "ERC20" - ); - await l1TokenStub.transfer(sender.address, wei`100 ether`); - - const l1TokensGatewayImpl = await new L1ERC20TokenGateway__factory( - deployer - ).deploy( - inboxStub.address, - l1RouterStub.address, - l2TokensGatewayStub.address, - l1TokenStub.address, - l2TokenStub.address - ); - const l1TokensGatewayProxy = await new OssifiableProxy__factory( - deployer - ).deploy(l1TokensGatewayImpl.address, deployer.address, "0x"); - - await hre.network.provider.request({ - method: "hardhat_impersonateAccount", - params: [l1RouterStub.address], - }); - const l1RouterAsEOA = await hre.ethers.getSigner(l1RouterStub.address); - - return { - accounts: { - deployer, - stranger, - sender, - recipient, - bridgeAsEOA: await ethers.getSigner(bridgeStub.address), - l1RouterAsEOA, - }, - stubs: { - inbox: inboxStub, - outbox: outboxStub, - bridge: bridgeStub, - l1Token: l1TokenStub, - l2Token: l2TokenStub, - l1Router: l1RouterStub, - l2TokensGateway: L2ERC20TokenGateway__factory.connect( - l2TokensGatewayStub.address, - deployer - ), - }, - l1TokensGateway: L1ERC20TokenGateway__factory.connect( - l1TokensGatewayProxy.address, - deployer - ), - }; -} - -function encodeSenderOutboundTransferData(maxSubmissionCost: string) { - return hre.ethers.utils.defaultAbiCoder.encode( - ["uint256", "bytes"], - [maxSubmissionCost, "0x"] - ); -} - -function encodeRouterOutboundTransferData( - sender: string, - maxSubmissionCost: string, - extraData = "0x" -) { - return hre.ethers.utils.defaultAbiCoder.encode( - ["address", "bytes"], - [ - sender, - hre.ethers.utils.defaultAbiCoder.encode( - ["uint256", "bytes"], - [maxSubmissionCost, extraData] - ), - ] - ); -} diff --git a/test/arbitrum/L2ERC20TokensGateway.unit.test.ts b/test/arbitrum/L2ERC20TokensGateway.unit.test.ts deleted file mode 100644 index 81fb6068..00000000 --- a/test/arbitrum/L2ERC20TokensGateway.unit.test.ts +++ /dev/null @@ -1,663 +0,0 @@ -import hre, { ethers } from "hardhat"; -import { wei } from "../../utils/wei"; -import { - ERC20BridgedStub__factory, - L1ERC20TokenGateway__factory, - L2ERC20TokenGateway__factory, - OssifiableProxy__factory, - EmptyContractStub__factory, -} from "../../typechain"; -import { assert } from "chai"; -import testing, { unit } from "../../utils/testing"; -import { ArbSysStub__factory } from "../../typechain/factories/ArbSysStub__factory"; - -unit("Arbitrum :: L2ERC20TokensGateway", ctxFactory) - .test("l1Token()", async (ctx) => { - assert.equal( - await ctx.l2TokensGateway.l1Token(), - ctx.stubs.l1Token.address - ); - }) - - .test("l2Token()", async (ctx) => { - assert.equal( - await ctx.l2TokensGateway.l2Token(), - ctx.stubs.l2Token.address - ); - }) - - .test("counterpartGateway()", async (ctx) => { - assert.equal( - await ctx.l2TokensGateway.counterpartGateway(), - ctx.stubs.l1TokensGateway.address - ); - }) - - .test("router() ", async (ctx) => { - assert.equal( - await ctx.l2TokensGateway.router(), - ctx.stubs.l2Router.address - ); - }) - - .test("calculateL2TokenAddress() :: correct l1Token address", async (ctx) => { - const actualL2TokenAddress = - await ctx.l2TokensGateway.calculateL2TokenAddress( - ctx.stubs.l1Token.address - ); - assert.equal(actualL2TokenAddress, ctx.stubs.l2Token.address); - }) - - .test( - "calculateL2TokenAddress() :: incorrect l1Token address", - async (ctx) => { - const wrongAddress = ctx.accounts.stranger.address; - const actualL2TokenAddress = - await ctx.l2TokensGateway.calculateL2TokenAddress(wrongAddress); - assert.equal(actualL2TokenAddress, hre.ethers.constants.AddressZero); - } - ) - - .test("getOutboundCalldata()", async (ctx) => { - const { - l2TokensGateway, - stubs: { l1Token, l1TokensGateway }, - accounts: { sender, recipient }, - } = ctx; - const amount = wei`1.5 ether`; - const actualCalldata = await l2TokensGateway.getOutboundCalldata( - l1Token.address, - sender.address, - recipient.address, - amount, - "0x" - ); - - const expectedCalldata = l1TokensGateway.interface.encodeFunctionData( - "finalizeInboundTransfer", - [l1Token.address, sender.address, recipient.address, amount, "0x"] - ); - - assert.equal(actualCalldata, expectedCalldata); - }) - - .test("outboundTransfer() :: withdrawals are disabled", async (ctx) => { - const { - l2TokensGateway, - accounts: { sender, recipient }, - } = ctx; - // validate deposits are disabled - assert.isFalse(await l2TokensGateway.isDepositsEnabled()); - - const amount = wei`1.2 ether`; - const maxGas = wei`1000 gwei`; - const gasPriceBid = wei`2000 gwei`; - const maxSubmissionCost = wei`11_000 gwei`; - const data = encodeOutboundTransferData(maxSubmissionCost); - - // validate deposit reverts with error ErrorWithdrawalsDisabled() - await assert.revertsWith( - l2TokensGateway - .connect(sender) - .outboundTransfer( - ctx.stubs.l1Token.address, - recipient.address, - amount, - maxGas, - gasPriceBid, - data - ), - "ErrorWithdrawalsDisabled()" - ); - }) - - .test("outboundTransfer() :: wrong l1Token address", async (ctx) => { - const amount = wei`1.2 ether`; - const maxGas = wei`1000 gwei`; - const gasPriceBid = wei`2000 gwei`; - const maxSubmissionCost = wei`11_000 gwei`; - const data = encodeOutboundTransferData(maxSubmissionCost); - - const { - l2TokensGateway, - accounts: { deployer, sender, recipient }, - stubs: { l2Token: wrongAddress }, - } = ctx; - - // initialize gateway - await l2TokensGateway.initialize(deployer.address); - - // validate gateway was initialized - assert.isTrue(await l2TokensGateway.isInitialized()); - - // grant WITHDRAWALS_ENABLER_ROLE to the l1Deployer to enable deposits - await l2TokensGateway.grantRole( - await l2TokensGateway.WITHDRAWALS_ENABLER_ROLE(), - deployer.address - ); - - // enable deposits - await l2TokensGateway.enableWithdrawals(); - - // validate deposits was enabled - assert.isTrue(await l2TokensGateway.isWithdrawalsEnabled()); - - await assert.revertsWith( - l2TokensGateway - .connect(sender) - .outboundTransfer( - wrongAddress.address, - recipient.address, - amount, - maxGas, - gasPriceBid, - data - ), - "ErrorUnsupportedL1Token()" - ); - }) - - .test("outboundTransfer() :: extra data not empty", async (ctx) => { - const { - l2TokensGateway, - stubs: { l1Token }, - accounts: { deployer }, - } = ctx; - - // initialize gateway - await l2TokensGateway.initialize(deployer.address); - - // validate gateway was initialized - assert.isTrue(await l2TokensGateway.isInitialized()); - - // grant WITHDRAWALS_ENABLER_ROLE to the l1Deployer to enable deposits - await l2TokensGateway.grantRole( - await l2TokensGateway.WITHDRAWALS_ENABLER_ROLE(), - deployer.address - ); - - // enable deposits - await l2TokensGateway.enableWithdrawals(); - - // validate deposits was enabled - assert.isTrue(await l2TokensGateway.isWithdrawalsEnabled()); - - const [sender, recipient] = await hre.ethers.getSigners(); - const amount = wei`1.2 ether`; - const maxGas = wei`1000 gwei`; - const gasPriceBid = wei`2000 gwei`; - const data = "0xdeadbeaf"; - - // initiate outbound transfer - await assert.revertsWith( - l2TokensGateway - .connect(sender) - .outboundTransfer( - l1Token.address, - recipient.address, - amount, - maxGas, - gasPriceBid, - data - ), - "ExtraDataNotEmpty()" - ); - }) - - .test("outboundTransfer() :: called by router", async (ctx) => { - const { - l2TokensGateway, - stubs: { l1Token, arbSys, l1TokensGateway }, - accounts: { deployer, l2RouterAsEOA }, - } = ctx; - - // initialize gateway - await l2TokensGateway.initialize(deployer.address); - - // validate gateway was initialized - assert.isTrue(await l2TokensGateway.isInitialized()); - - // grant WITHDRAWALS_ENABLER_ROLE to the l1Deployer to enable deposits - await l2TokensGateway.grantRole( - await l2TokensGateway.WITHDRAWALS_ENABLER_ROLE(), - deployer.address - ); - - // enable deposits - await l2TokensGateway.enableWithdrawals(); - - // validate deposits was enabled - assert.isTrue(await l2TokensGateway.isWithdrawalsEnabled()); - - const l2ToL1Id = 10; - - // set l2ToL1Id value in ArbSysStub - await arbSys.setl2ToL1TxId(l2ToL1Id); - - // validate value was set - assert.equalBN(await arbSys.l2ToL1TxId(), l2ToL1Id); - - const [sender, recipient] = await hre.ethers.getSigners(); - const amount = wei`1.2 ether`; - const maxGas = wei`1000 gwei`; - const gasPriceBid = wei`2000 gwei`; - const data = hre.ethers.utils.defaultAbiCoder.encode( - ["address", "bytes"], - [sender.address, "0x"] - ); - - // initiate outbound transfer - const tx = await l2TokensGateway - .connect(l2RouterAsEOA) - .outboundTransfer( - l1Token.address, - recipient.address, - amount, - maxGas, - gasPriceBid, - data - ); - - const expectedCalldata = - ctx.stubs.l1TokensGateway.interface.encodeFunctionData( - "finalizeInboundTransfer", - [l1Token.address, sender.address, recipient.address, amount, "0x"] - ); - - // validate TxToL1 event was emitted - await assert.emits(l2TokensGateway, tx, "TxToL1", [ - sender.address, - l1TokensGateway.address, - l2ToL1Id + 1, - expectedCalldata, - ]); - - // validate DepositInitiated event was emitted - await assert.emits(l2TokensGateway, tx, "WithdrawalInitiated", [ - l1Token.address, - sender.address, - recipient.address, - l2ToL1Id + 1, - 0, - amount, - ]); - - // validate CreateL2ToL1Tx event was emitted - await assert.emits(arbSys, tx, "CreateL2ToL1Tx", [ - l1TokensGateway.address, - expectedCalldata, - ]); - }) - - .test("outboundTransfer() :: called by sender", async (ctx) => { - const { - l2TokensGateway, - stubs: { l1Token, arbSys, l1TokensGateway }, - accounts: { deployer }, - } = ctx; - - // initialize gateway - await l2TokensGateway.initialize(deployer.address); - - // validate gateway was initialized - assert.isTrue(await l2TokensGateway.isInitialized()); - - // grant WITHDRAWALS_ENABLER_ROLE to the l1Deployer to enable deposits - await l2TokensGateway.grantRole( - await l2TokensGateway.WITHDRAWALS_ENABLER_ROLE(), - deployer.address - ); - - // enable deposits - await l2TokensGateway.enableWithdrawals(); - - // validate deposits was enabled - assert.isTrue(await l2TokensGateway.isWithdrawalsEnabled()); - - const l2ToL1Id = 10; - - // set l2ToL1Id value in ArbSysStub - await arbSys.setl2ToL1TxId(l2ToL1Id); - - // validate value was set - assert.equalBN(await arbSys.l2ToL1TxId(), l2ToL1Id); - - const [sender, recipient] = await hre.ethers.getSigners(); - const amount = wei`1.2 ether`; - const maxGas = wei`1000 gwei`; - const gasPriceBid = wei`2000 gwei`; - const data = "0x"; - - // call tx locally to check return value - assert.equal( - await l2TokensGateway - .connect(sender) - .callStatic.outboundTransfer( - l1Token.address, - recipient.address, - amount, - maxGas, - gasPriceBid, - data - ), - hre.ethers.utils.defaultAbiCoder.encode(["uint256"], [l2ToL1Id + 1]) - ); - - // initiate outbound transfer - const tx = await l2TokensGateway - .connect(sender) - .outboundTransfer( - l1Token.address, - recipient.address, - amount, - maxGas, - gasPriceBid, - data - ); - - const expectedCalldata = - ctx.stubs.l1TokensGateway.interface.encodeFunctionData( - "finalizeInboundTransfer", - [l1Token.address, sender.address, recipient.address, amount, "0x"] - ); - - // validate TxToL1 event was emitted - await assert.emits(l2TokensGateway, tx, "TxToL1", [ - sender.address, - l1TokensGateway.address, - l2ToL1Id + 1, - expectedCalldata, - ]); - - // validate DepositInitiated event was emitted - await assert.emits(l2TokensGateway, tx, "WithdrawalInitiated", [ - l1Token.address, - sender.address, - recipient.address, - l2ToL1Id + 1, - 0, - amount, - ]); - - // validate CreateL2ToL1Tx event was emitted - await assert.emits(arbSys, tx, "CreateL2ToL1Tx", [ - l1TokensGateway.address, - expectedCalldata, - ]); - }) - - .test("finalizeInboundTransfer() :: deposits disabled", async (ctx) => { - const { - l2TokensGateway, - accounts: { deployer, l1TokensGatewayAliasedEOA, sender, recipient }, - stubs: { l1Token }, - } = ctx; - - // initialize gateway - await l2TokensGateway.initialize(deployer.address); - - // validate gateway was initialized - assert.isTrue(await l2TokensGateway.isInitialized()); - - // validate withdrawals disabled - assert.isFalse(await l2TokensGateway.isWithdrawalsEnabled()); - - await assert.revertsWith( - l2TokensGateway - .connect(l1TokensGatewayAliasedEOA) - .finalizeInboundTransfer( - l1Token.address, - sender.address, - recipient.address, - wei`10 ether`, - "0x" - ), - "ErrorDepositsDisabled()" - ); - }) - - .test("finalizeInboundTransfer() :: wrong token", async (ctx) => { - const { - l2TokensGateway, - accounts: { - stranger, - sender, - recipient, - deployer, - l1TokensGatewayAliasedEOA, - }, - } = ctx; - const wrongTokenAddress = stranger.address; - - // initialize gateway - await l2TokensGateway.initialize(deployer.address); - - // validate gateway was initialized - assert.isTrue(await l2TokensGateway.isInitialized()); - - // grant DEPOSITS_ENABLER_ROLE to the l1Deployer to enable withdrawals - await l2TokensGateway.grantRole( - await l2TokensGateway.DEPOSITS_ENABLER_ROLE(), - deployer.address - ); - - // enable withdrawals - await l2TokensGateway.enableDeposits(); - - // validate withdrawals were enabled - assert.isTrue(await l2TokensGateway.isDepositsEnabled()); - - // validate gateway reverts with error ErrorUnsupportedL1Token() - await assert.revertsWith( - l2TokensGateway - .connect(l1TokensGatewayAliasedEOA) - .finalizeInboundTransfer( - wrongTokenAddress, - sender.address, - recipient.address, - wei`10 ether`, - "0x" - ), - "ErrorUnsupportedL1Token()" - ); - }) - - .test("finalizeInboundTransfer() :: not counterpart gateway", async (ctx) => { - const { - l2TokensGateway, - accounts: { deployer, stranger, sender, recipient }, - stubs: { l1Token }, - } = ctx; - - // initialize gateway - await l2TokensGateway.initialize(deployer.address); - - // validate gateway was initialized - assert.isTrue(await l2TokensGateway.isInitialized()); - - // grant DEPOSITS_ENABLER_ROLE to the l1Deployer to enable withdrawals - await l2TokensGateway.grantRole( - await l2TokensGateway.DEPOSITS_ENABLER_ROLE(), - deployer.address - ); - - // enable withdrawals - await l2TokensGateway.enableDeposits(); - - // validate withdrawals were enabled - assert.isTrue(await l2TokensGateway.isDepositsEnabled()); - - // validate that stranger address is not counterpartGateway - assert.notEqual( - await l2TokensGateway.counterpartGateway(), - stranger.address - ); - - // validate gateway reverts with error ErrorWrongCrossDomainSender() - await assert.revertsWith( - l2TokensGateway - .connect(stranger) - .finalizeInboundTransfer( - l1Token.address, - sender.address, - recipient.address, - wei`10 ether`, - "0x" - ), - "ErrorWrongCrossDomainSender()" - ); - }) - - .test("finalizeInboundTransfer() :: works as expected", async (ctx) => { - const { - l2TokensGateway, - accounts: { sender, recipient, deployer, l1TokensGatewayAliasedEOA }, - stubs: { l1Token, l2Token }, - } = ctx; - - // initialize gateway - await l2TokensGateway.initialize(deployer.address); - - // validate gateway was initialized - assert.isTrue(await l2TokensGateway.isInitialized()); - - // grant WITHDRAWALS_ENABLER_ROLE to the l1Deployer to enable withdrawals - await l2TokensGateway.grantRole( - await l2TokensGateway.DEPOSITS_ENABLER_ROLE(), - deployer.address - ); - - // enable withdrawals - await l2TokensGateway.enableDeposits(); - - // validate withdrawals were enabled - assert.isTrue(await l2TokensGateway.isDepositsEnabled()); - - // transfer l2Tokens to l2TokensGateway - const initialL2GatewayBalance = wei`10_000 ether`; - await l2Token.transfer(l2TokensGateway.address, initialL2GatewayBalance); - - // validate l1TokensGateway has enough amount of tokens - assert.equal( - await l2Token.balanceOf(l2TokensGateway.address).then(wei.fromBigNumber), - initialL2GatewayBalance - ); - - const amount = wei`10 ether`; - - const tx = await l2TokensGateway - .connect(l1TokensGatewayAliasedEOA) - .finalizeInboundTransfer( - l1Token.address, - sender.address, - recipient.address, - wei`10 ether`, - "0x" - ); - - // validate DepositFinalized was emitted - await assert.emits(l2TokensGateway, tx, "DepositFinalized", [ - l1Token.address, - sender.address, - recipient.address, - amount, - ]); - - // validate tokens were minted to recipient - assert.equalBN(await l2Token.balanceOf(recipient.address), amount); - }) - - .run(); - -async function ctxFactory() { - const [deployer, stranger, sender, recipient] = await hre.ethers.getSigners(); - const l2RouterStub = await new EmptyContractStub__factory(deployer).deploy({ - value: wei.toBigNumber(wei`1 ether`), - }); - const l1TokensGatewayStub = await new EmptyContractStub__factory( - deployer - ).deploy({ value: wei.toBigNumber(wei`1 ether`) }); - await hre.network.provider.request({ - method: "hardhat_impersonateAccount", - params: [l1TokensGatewayStub.address], - }); - const l2TokenStub = await new ERC20BridgedStub__factory(deployer).deploy( - "L2Token stub", - "L2ERC20" - ); - const l1TokenStub = await new ERC20BridgedStub__factory(deployer).deploy( - "ERC20 Mock", - "ERC20" - ); - - const arbSysStub = await new ArbSysStub__factory(deployer).deploy(); - const l2TokensGatewayImpl = await new L2ERC20TokenGateway__factory( - deployer - ).deploy( - arbSysStub.address, // the default address of the - l2RouterStub.address, - l1TokensGatewayStub.address, - l1TokenStub.address, - l2TokenStub.address - ); - const l2TokensGatewayProxy = await new OssifiableProxy__factory( - deployer - ).deploy(l2TokensGatewayImpl.address, deployer.address, "0x"); - - const l1TokensGatewayAliasedEOAAddress = testing.accounts.applyL1ToL2Alias( - l1TokensGatewayStub.address - ); - - await hre.network.provider.request({ - method: "hardhat_impersonateAccount", - params: [l1TokensGatewayAliasedEOAAddress], - }); - - const l1TokensGatewayAliasedEOA = await hre.ethers.getSigner( - l1TokensGatewayAliasedEOAAddress - ); - - await testing.setBalance( - l1TokensGatewayAliasedEOA.address, - wei.toBigNumber(wei`1 ether`) - ); - - await hre.network.provider.request({ - method: "hardhat_impersonateAccount", - params: [l2RouterStub.address], - }); - const l2RouterAsEOA = await hre.ethers.getSigner(l2RouterStub.address); - - return { - accounts: { - deployer, - stranger, - sender, - recipient, - l2RouterAsEOA, - l1TokensGatewayEOA: await ethers.getSigner(l1TokensGatewayStub.address), - l1TokensGatewayAliasedEOA, - }, - stubs: { - arbSys: arbSysStub, - l1Token: l1TokenStub, - l2Token: l2TokenStub, - l2Router: l2RouterStub, - l1TokensGateway: L1ERC20TokenGateway__factory.connect( - l1TokensGatewayStub.address, - deployer - ), - }, - l2TokensGateway: L2ERC20TokenGateway__factory.connect( - l2TokensGatewayProxy.address, - deployer - ), - }; -} - -function encodeOutboundTransferData(maxSubmissionCost: string) { - return hre.ethers.utils.defaultAbiCoder.encode( - ["uint256", "bytes"], - [maxSubmissionCost, "0x"] - ); -} diff --git a/test/arbitrum/_launch.test.ts b/test/arbitrum/_launch.test.ts deleted file mode 100644 index e5711360..00000000 --- a/test/arbitrum/_launch.test.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { assert } from "chai"; - -import env from "../../utils/env"; -import arbitrum from "../../utils/arbitrum"; -import { L1ERC20TokenBridge__factory } from "../../typechain"; -import { wei } from "../../utils/wei"; -import testing, { scenario } from "../../utils/testing"; -import { BridgingManagerRole } from "../../utils/bridging-management"; - -const REVERT = env.bool("REVERT", true); - -scenario("Arbitrum :: Launch integration test", ctx) - .after(async (ctx) => { - if (REVERT) { - await ctx.l1Provider.send("evm_revert", [ctx.snapshot.l1]); - await ctx.l2Provider.send("evm_revert", [ctx.snapshot.l2]); - } else { - console.warn( - "Revert is skipped! Forked node restart might be required for repeated launches!" - ); - } - }) - - .step("Enable deposits", async (ctx) => { - const { l1ERC20TokenGateway } = ctx; - assert.isFalse(await l1ERC20TokenGateway.isDepositsEnabled()); - - await l1ERC20TokenGateway.enableDeposits(); - assert.isTrue(await l1ERC20TokenGateway.isDepositsEnabled()); - }) - - .step("Renounce role", async (ctx) => { - const { l1ERC20TokenGateway, l1DevMultisig } = ctx; - assert.isTrue( - await l1ERC20TokenGateway.hasRole( - BridgingManagerRole.DEPOSITS_ENABLER_ROLE.hash, - await l1DevMultisig.getAddress() - ) - ); - - await l1ERC20TokenGateway.renounceRole( - BridgingManagerRole.DEPOSITS_ENABLER_ROLE.hash, - await l1DevMultisig.getAddress() - ); - assert.isFalse( - await l1ERC20TokenGateway.hasRole( - BridgingManagerRole.DEPOSITS_ENABLER_ROLE.hash, - await l1DevMultisig.getAddress() - ) - ); - }) - - .run(); - -async function ctx() { - const networkName = env.network("TESTING_ARB_NETWORK", "mainnet"); - const { l1Provider, l2Provider, l1ERC20TokenGateway } = await arbitrum - .testing(networkName) - .getIntegrationTestSetup(); - - const hasDeployedContracts = testing.env.USE_DEPLOYED_CONTRACTS(false); - const l1DevMultisig = hasDeployedContracts - ? await testing.impersonate(testing.env.L1_DEV_MULTISIG(), l1Provider) - : testing.accounts.deployer(l1Provider); - - const l1Snapshot = await l1Provider.send("evm_snapshot", []); - const l2Snapshot = await l2Provider.send("evm_snapshot", []); - - await testing.setBalance( - await l1DevMultisig.getAddress(), - wei.toBigNumber(wei`1 ether`) - ); - - const l1ERC20TokenGatewayImpl = L1ERC20TokenBridge__factory.connect( - l1ERC20TokenGateway.address, - l1DevMultisig - ); - - return { - l1Provider, - l2Provider, - l1DevMultisig, - l1ERC20TokenGateway: l1ERC20TokenGatewayImpl, - snapshot: { - l1: l1Snapshot, - l2: l2Snapshot, - }, - }; -} diff --git a/test/arbitrum/bridging-native.e2e.test.ts b/test/arbitrum/bridging-native.e2e.test.ts deleted file mode 100644 index 6e56499b..00000000 --- a/test/arbitrum/bridging-native.e2e.test.ts +++ /dev/null @@ -1,205 +0,0 @@ -import { assert } from "chai"; -import { ERC20Mintable } from "../../typechain"; -import env from "../../utils/env"; -import { wei } from "../../utils/wei"; -import { - getL2Network, - L1ToL2MessageStatus, - L1TransactionReceipt, -} from "@arbitrum/sdk"; -import { scenario } from "../../utils/testing"; -import arbitrum from "../../utils/arbitrum"; -import { ethers } from "hardhat"; - -async function ctxFactory() { - const networkName = env.network("TESTING_ARB_NETWORK", "sepolia"); - const testingSetup = await arbitrum.testing(networkName).getE2ETestSetup(); - - const l2Network = await getL2Network(testingSetup.l2Provider); - - // replace gateway router addresses with test - l2Network.tokenBridge.l1GatewayRouter = testingSetup.l1GatewayRouter.address; - l2Network.tokenBridge.l2GatewayRouter = testingSetup.l2GatewayRouter.address; - - return { - ...testingSetup, - messaging: arbitrum.messaging(networkName, { - forking: false, - customAddresses: { - L1GatewayRouter: testingSetup.l1GatewayRouter.address, - L2GatewayRouter: testingSetup.l2GatewayRouter.address, - }, - }), - l2Network, - depositAmount: wei`0.025 ether`, - withdrawalAmount: wei`0.025 ether`, - }; -} - -scenario("Arbitrum :: Bridging E2E test natively", ctxFactory) - .step("Validate tester has required amount of L1 token", async (ctx) => { - const { l1Token, l1Tester, depositAmount } = ctx; - const balanceBefore = await l1Token.balanceOf(l1Tester.address); - if (balanceBefore.lt(depositAmount)) { - try { - await (l1Token as ERC20Mintable).mint(l1Tester.address, depositAmount); - } catch {} - } - const balanceAfter = await l1Token.balanceOf(l1Tester.address); - assert.isTrue( - balanceAfter.gte(depositAmount), - "Tester has not enough L1 token" - ); - }) - - .step("Set allowance for L1ERC20TokenGateway to deposit", async (ctx) => { - const { l1Tester, l1Token, depositAmount, l1ERC20TokenGateway } = ctx; - - const allowanceTxResponse = await l1Token - .connect(l1Tester) - .approve(l1ERC20TokenGateway.address, wei.toBigNumber(depositAmount)); - - await allowanceTxResponse.wait(); - - assert.equalBN( - await l1Token.allowance(l1Tester.address, l1ERC20TokenGateway.address), - depositAmount - ); - }) - - .step("Deposit tokens to L2 via L1ERC20Gateway", async (ctx) => { - const { - l1Tester, - l1Token, - l2Tester, - l2Token, - depositAmount, - l1ERC20TokenGateway, - l2ERC20TokenGateway, - } = ctx; - const l1ERC20TokenGatewayBalanceBefore = await l1Token.balanceOf( - ctx.l1ERC20TokenGateway.address - ); - const testerL1TokenBalanceBefore = await l1Token.balanceOf( - l1Tester.address - ); - const testerL2TokenBalanceBefore = await l2Token.balanceOf( - l2Tester.address - ); - - // To estimate params required for L1 -> L2 retryable ticket creation - // we need to know which message will be send on L2 - const finalizeInboundTransferCalldata = - await l1ERC20TokenGateway.getOutboundCalldata( - l1Token.address, - l1Tester.address, - l1Tester.address, - wei.toBigNumber(depositAmount), - "0x" - ); - - const { callvalue, gasPriceBid, maxGas, maxSubmissionCost } = - await ctx.messaging.getRetryableTicketSendParams({ - callvalue: 0, - sender: l1ERC20TokenGateway.address, - recipient: l2ERC20TokenGateway.address, - calldata: finalizeInboundTransferCalldata, - refundAddress: l2Tester.address, - }); - - const maxSubmissionCostEncoded = ethers.utils.defaultAbiCoder.encode( - ["uint256", "bytes"], - [maxSubmissionCost, "0x"] - ); - - const depositTxResponse = await l1ERC20TokenGateway - .connect(l1Tester) - .outboundTransfer( - l1Token.address, - l1Tester.address, - depositAmount, - maxGas, - gasPriceBid, - maxSubmissionCostEncoded, - { value: callvalue } - ); - - const depositL1Receipt = await depositTxResponse.wait(); - - assert.equalBN( - await l1Token.balanceOf(l1Tester.address), - testerL1TokenBalanceBefore.sub(depositAmount) - ); - - assert.equalBN( - await l1Token.balanceOf(ctx.l1ERC20TokenGateway.address), - l1ERC20TokenGatewayBalanceBefore.add(depositAmount) - ); - - const l1TxReceipt = new L1TransactionReceipt(depositL1Receipt); - - const [message] = await l1TxReceipt.getL1ToL2Messages(l2Tester); - - const { status } = await message.waitForStatus(); - - if (status === L1ToL2MessageStatus.FUNDS_DEPOSITED_ON_L2) { - console.warn( - `Auto redeem for tx ${l1TxReceipt.transactionHash} failed. Redeeming it manually...` - ); - const redeemResponse = await message.redeem({ gasLimit: 300_000 }); - await redeemResponse.wait(); - console.log("Tx was redeemed"); - } else if (status === L1ToL2MessageStatus.REDEEMED) { - console.log("Tx was auto redeemed"); - } else { - assert.isTrue( - false, - `L2 retryable txn failed with status ${L1ToL2MessageStatus[status]}` - ); - } - - assert.equalBN( - await l2Token.balanceOf(l2Tester.address), - testerL2TokenBalanceBefore.add(depositAmount) - ); - }) - - .step("Withdraw tokens from L2 via L2ERC20Gateway", async (ctx) => { - const { - l2Token, - l1Tester, - l2Tester, - l1Token, - withdrawalAmount, - l2ERC20TokenGateway, - } = ctx; - - const testerL2TokenBalanceBefore = await l2Token.balanceOf( - l2Tester.address - ); - - const withdrawTxResponse = await l2ERC20TokenGateway.outboundTransfer( - l1Token.address, - l1Tester.address, - withdrawalAmount, - wei`0`, - wei`0`, - "0x" - ); - - const withdrawRec = await withdrawTxResponse.wait(); - - console.log(`Token withdrawal initiated: ${withdrawRec.transactionHash}`); - - assert.equalBN( - await l2Token.balanceOf(l2Tester.address), - testerL2TokenBalanceBefore.sub(withdrawalAmount) - ); - }) - - .step( - "L2 -> L1 transactions takes much time and must be redeemed manually", - async () => {} - ) - - .run(); diff --git a/test/arbitrum/bridging-router.e2e.test.ts b/test/arbitrum/bridging-router.e2e.test.ts deleted file mode 100644 index fc7fcc76..00000000 --- a/test/arbitrum/bridging-router.e2e.test.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { assert } from "chai"; -import { ERC20Mintable } from "../../typechain"; -import env from "../../utils/env"; -import { wei } from "../../utils/wei"; -import { Erc20Bridger, getL2Network, L1ToL2MessageStatus } from "@arbitrum/sdk"; -import { scenario } from "../../utils/testing"; -import arbitrum from "../../utils/arbitrum"; - -async function ctxFactory() { - const networkName = env.network("TESTING_ARB_NETWORK", "sepolia"); - const testingSetup = await arbitrum.testing(networkName).getE2ETestSetup(); - - const l2Network = await getL2Network(testingSetup.l2Provider); - - // replace gateway router addresses with test - l2Network.tokenBridge.l1GatewayRouter = testingSetup.l1GatewayRouter.address; - l2Network.tokenBridge.l2GatewayRouter = testingSetup.l2GatewayRouter.address; - - return { - ...testingSetup, - l2Network, - erc20Bridge: new Erc20Bridger(l2Network), - depositAmount: wei`0.025 ether`, - withdrawalAmount: wei`0.025 ether`, - }; -} - -scenario("Arbitrum :: Bridging E2E test via router", ctxFactory) - .step( - "Check test environment is set correctly", - async ({ erc20Bridge, l1Token, ...ctx }) => { - assert.equal( - await erc20Bridge.getL1GatewayAddress(l1Token.address, ctx.l1Provider), - ctx.l1ERC20TokenGateway.address - ); - assert.equal( - await erc20Bridge.getL2GatewayAddress(l1Token.address, ctx.l2Provider), - ctx.l2ERC20TokenGateway.address - ); - } - ) - - .step("Validate tester has required amount of L1 token", async (ctx) => { - const { l1Token, l1Tester, depositAmount } = ctx; - const balanceBefore = await l1Token.balanceOf(l1Tester.address); - if (balanceBefore.lt(depositAmount)) { - try { - await (l1Token as ERC20Mintable).mint(l1Tester.address, depositAmount); - } catch {} - } - const balanceAfter = await l1Token.balanceOf(l1Tester.address); - assert.isTrue( - balanceAfter.gte(depositAmount), - "Tester has not enough L1 token" - ); - }) - - .step("Set allowance for L1ERC20TokenGateway to deposit", async (ctx) => { - const { l1Tester, l1Token, depositAmount, l1ERC20TokenGateway } = ctx; - - const allowanceTxResponse = await ctx.erc20Bridge.approveToken({ - l1Signer: l1Tester, - erc20L1Address: l1Token.address, - amount: wei.toBigNumber(depositAmount), - }); - - await allowanceTxResponse.wait(); - - assert.equalBN( - await l1Token.allowance(l1Tester.address, l1ERC20TokenGateway.address), - depositAmount - ); - }) - - .step("Deposit tokens to L2 via L1GatewayRouter", async (ctx) => { - const { l1Tester, l1Token, l2Tester, l2Token, depositAmount } = ctx; - const l1ERC20TokenGatewayBalanceBefore = await l1Token.balanceOf( - ctx.l1ERC20TokenGateway.address - ); - const testerL1TokenBalanceBefore = await l1Token.balanceOf( - l1Tester.address - ); - const testerL2TokenBalanceBefore = await l2Token.balanceOf( - l2Tester.address - ); - - const depositTxResponse = await ctx.erc20Bridge.deposit({ - amount: wei.toBigNumber(depositAmount), - erc20L1Address: l1Token.address, - l1Signer: l1Tester, - l2Provider: ctx.l2Provider, - }); - - const depositL1Receipt = await depositTxResponse.wait(); - - assert.equalBN( - await l1Token.balanceOf(l1Tester.address), - testerL1TokenBalanceBefore.sub(depositAmount) - ); - - assert.equalBN( - await l1Token.balanceOf(ctx.l1ERC20TokenGateway.address), - l1ERC20TokenGatewayBalanceBefore.add(depositAmount) - ); - - const l2Result = await depositL1Receipt.waitForL2(l2Tester.provider); - - assert.isTrue( - l2Result.complete, - `L2 message failed: status ${L1ToL2MessageStatus[l2Result.status]}` - ); - - assert.equalBN( - await l2Token.balanceOf(l2Tester.address), - testerL2TokenBalanceBefore.add(depositAmount) - ); - }) - - .step("Withdraw tokens from L2 via L2GatewayRouter", async (ctx) => { - const { l2Token, l2Tester, l1Token, erc20Bridge, withdrawalAmount } = ctx; - const testerL2TokenBalanceBefore = await l2Token.balanceOf( - l2Tester.address - ); - - const withdrawTxResponse = await erc20Bridge.withdraw({ - l2Signer: l2Tester, - erc20l1Address: l1Token.address, - destinationAddress: l2Tester.address, - amount: wei.toBigNumber(withdrawalAmount), - }); - const withdrawRec = await withdrawTxResponse.wait(); - console.log(`Token withdrawal initiated: ${withdrawRec.transactionHash}`); - - assert.equalBN( - await l2Token.balanceOf(l2Tester.address), - testerL2TokenBalanceBefore.sub(withdrawalAmount) - ); - }) - - .step( - "L2 -> L1 transactions takes much time and must be redeemed manually", - async () => {} - ) - - .run(); diff --git a/test/arbitrum/bridging.integration.test.ts b/test/arbitrum/bridging.integration.test.ts deleted file mode 100644 index 00dab003..00000000 --- a/test/arbitrum/bridging.integration.test.ts +++ /dev/null @@ -1,504 +0,0 @@ -import { assert } from "chai"; -import { ethers } from "hardhat"; - -import env from "../../utils/env"; -import { wei } from "../../utils/wei"; -import arbitrum from "../../utils/arbitrum"; -import arbitrumAddresses from "../../utils/arbitrum/addresses"; -import testing, { scenario } from "../../utils/testing"; -import { - OutboxStub__factory, - BridgeStub__factory, - IMessageProvider__factory, -} from "../../typechain"; - -scenario("Arbitrum :: Bridging integration test", ctx) - .after(async (ctx) => { - await ctx.l1Provider.send("evm_revert", [ctx.snapshot.l1]); - await ctx.l2Provider.send("evm_revert", [ctx.snapshot.l2]); - }) - - .step("Activate Bridging on L1", async (ctx) => { - const { l1ERC20TokenGateway } = ctx; - const { l1BridgeAdmin } = ctx.accounts; - - const isDepositsEnabled = await l1ERC20TokenGateway.isDepositsEnabled(); - - if (!isDepositsEnabled) { - await l1ERC20TokenGateway.connect(l1BridgeAdmin).enableDeposits(); - } else { - console.log("L1 deposits already enabled"); - } - - const isWithdrawalsEnabled = - await l1ERC20TokenGateway.isWithdrawalsEnabled(); - - if (!isWithdrawalsEnabled) { - await l1ERC20TokenGateway.connect(l1BridgeAdmin).enableWithdrawals(); - } else { - console.log("L1 withdrawals already enabled"); - } - - assert.isTrue(await l1ERC20TokenGateway.isDepositsEnabled()); - assert.isTrue(await l1ERC20TokenGateway.isWithdrawalsEnabled()); - }) - - .step("Activate Bridging on L2", async (ctx) => { - const { l2ERC20TokenGateway } = ctx; - const { l2BridgeAdmin } = ctx.accounts; - - const isDepositsEnabled = await l2ERC20TokenGateway.isDepositsEnabled(); - - if (!isDepositsEnabled) { - await l2ERC20TokenGateway.connect(l2BridgeAdmin).enableDeposits(); - } else { - console.log("L2 deposits already enabled"); - } - - const isWithdrawalsEnabled = - await l2ERC20TokenGateway.isWithdrawalsEnabled(); - - if (!isWithdrawalsEnabled) { - await l2ERC20TokenGateway.connect(l2BridgeAdmin).enableWithdrawals(); - } else { - console.log("L2 withdrawals already enabled"); - } - - assert.isTrue(await l2ERC20TokenGateway.isDepositsEnabled()); - assert.isTrue(await l2ERC20TokenGateway.isWithdrawalsEnabled()); - }) - - .step( - "Set L1ERC20TokenGateway for new token in L1GatewayRouter", - async (ctx) => { - const { l1ERC20TokenGateway, l1Token, l1GatewayRouter } = ctx; - const { l1GatewayRouterAdmin } = ctx.accounts; - const { maxGas, gasPriceBid, maxSubmissionCost, callValue } = - ctx.constants; - - await l1GatewayRouter - .connect(l1GatewayRouterAdmin) - .setGateways( - [l1Token.address], - [l1ERC20TokenGateway.address], - maxGas, - gasPriceBid, - maxSubmissionCost, - { value: callValue } - ); - - assert.equal( - await l1GatewayRouter.getGateway(l1Token.address), - l1ERC20TokenGateway.address - ); - } - ) - - .step( - "Set L2ERC20TokenGateway for new token in L2GatewayRouter", - async (ctx) => { - const { l1Token, l2GatewayRouter, l2ERC20TokenGateway } = ctx; - const { l1GatewayRouterAliased } = ctx.accounts; - - await l2GatewayRouter - .connect(l1GatewayRouterAliased) - .setGateway([l1Token.address], [l2ERC20TokenGateway.address]); - - assert.equal( - await l2GatewayRouter.getGateway(l1Token.address), - l2ERC20TokenGateway.address - ); - } - ) - - .step("L1 -> L2 deposit via L1GatewayRouter", async (ctx) => { - const { accountA, accountB } = ctx.accounts; - const { l1Token, l1ERC20TokenGateway } = ctx; - const { - depositAmount, - outbdoundTransferData, - maxGas, - gasPriceBid, - callValue, - } = ctx.constants; - - await l1Token - .connect(accountA.l1Signer) - .approve(l1ERC20TokenGateway.address, depositAmount); - - const accountABalanceBefore = await l1Token.balanceOf(accountA.address); - const l1ERC20TokenGatewayBalanceBefore = await l1Token.balanceOf( - l1ERC20TokenGateway.address - ); - - const tx = await ctx.l1GatewayRouter - .connect(accountA.l1Signer) - .outboundTransfer( - l1Token.address, - accountB.address, - depositAmount, - maxGas, - gasPriceBid, - outbdoundTransferData, - { value: callValue } - ); - - const receipt = await tx.wait(); - - const messageProviderInterface = - IMessageProvider__factory.createInterface(); - const inboxMessageDeliveredTopic = messageProviderInterface.getEventTopic( - "InboxMessageDelivered" - ); - const messageDeliveredLog = receipt.logs.find( - (l) => l.topics[0] === inboxMessageDeliveredTopic - ); - if (!messageDeliveredLog) { - throw new Error("InboxMessageDelivered message wasn't fired"); - } - const messageDeliveredEvent = - messageProviderInterface.parseLog(messageDeliveredLog); - - // Validate that message data were passed correctly. - // Inbox contract uses the abi.encodePackedValue(), so it's an overhead - // to parse all data of the event when we only need the last one - assert.isTrue( - messageDeliveredEvent.args.data.endsWith( - ctx.constants.finalizeInboundTransferCalldata.deposit.slice(2) - ) - ); - - assert.equalBN( - await l1Token.balanceOf(accountA.address), - accountABalanceBefore.sub(depositAmount) - ); - - assert.equalBN( - await l1Token.balanceOf(l1ERC20TokenGateway.address), - l1ERC20TokenGatewayBalanceBefore.add(depositAmount) - ); - }) - - .step("Finalize deposit on L2", async (ctx) => { - const { depositAmount } = ctx.constants; - const { l1Token, l2Token, l2ERC20TokenGateway } = ctx; - const { accountA, accountB, l1ERC20TokenGatewayAliased } = ctx.accounts; - - const l2TokenSupplyBefore = await l2Token.totalSupply(); - const accountBBalanceBefore = await l2Token.balanceOf(accountB.address); - - const tx = await l1ERC20TokenGatewayAliased.sendTransaction({ - to: l2ERC20TokenGateway.address, - data: ctx.constants.finalizeInboundTransferCalldata.deposit, - }); - - await assert.emits(l2Token, tx, "Transfer", [ - ethers.constants.AddressZero, - accountB.address, - depositAmount, - ]); - - await assert.emits(l2ERC20TokenGateway, tx, "DepositFinalized", [ - l1Token.address, - accountA.address, - accountB.address, - depositAmount, - ]); - - assert.equalBN( - await l2Token.totalSupply(), - l2TokenSupplyBefore.add(depositAmount) - ); - assert.equalBN( - await l2Token.balanceOf(accountB.address), - accountBBalanceBefore.add(depositAmount) - ); - }) - - .step("L2 -> L1 withdrawal via L2GatewayRouter", async (ctx) => { - const { accountA, accountB } = ctx.accounts; - const { l1Token, arbSys, l2ERC20TokenGateway, l2Token } = ctx; - const { withdrawalAmount } = ctx.constants; - - const l2TokenSupplyBefore = await l2Token.totalSupply(); - const accountBBalanceBefore = await l2Token.balanceOf(accountB.address); - - const prevL2ToL1TxId = await arbSys.l2ToL1TxId(); - const tx = await ctx.l2GatewayRouter - .connect(accountB.l2Signer) - ["outboundTransfer(address,address,uint256,bytes)"]( - l1Token.address, - accountA.address, - withdrawalAmount, - "0x" - ); - - await assert.emits(ctx.l2Token, tx, "Transfer", [ - accountB.address, - ethers.constants.AddressZero, - withdrawalAmount, - ]); - - await assert.emits(arbSys, tx, "CreateL2ToL1Tx", [ - ctx.l1ERC20TokenGateway.address, - ctx.constants.finalizeInboundTransferCalldata.withdraw, - ]); - - await assert.emits(l2ERC20TokenGateway, tx, "WithdrawalInitiated", [ - l1Token.address, - accountB.address, - accountA.address, - prevL2ToL1TxId.add(1), - 0, - withdrawalAmount, - ]); - - assert.equalBN( - await l2Token.totalSupply(), - l2TokenSupplyBefore.sub(withdrawalAmount) - ); - assert.equalBN( - await l2Token.balanceOf(accountB.address), - accountBBalanceBefore.sub(withdrawalAmount) - ); - }) - - .step("Finalize withdrawal on L1", async (ctx) => { - const { accountA, accountB } = ctx.accounts; - const { withdrawalAmount } = ctx.constants; - const { - l1OutboxStub, - l1Provider, - l1Token, - l1ERC20TokenGateway, - l1Bridge, - l1BridgeStub, - } = ctx; - - const accountABalanceBefore = await l1Token.balanceOf(accountA.address); - const l1ERC20TokenGatewayBalanceBefore = await l1Token.balanceOf( - l1ERC20TokenGateway.address - ); - - const [bridgeCodeBefore, bridgeStubCode] = await Promise.all([ - l1Provider.send("eth_getCode", [l1Bridge.address]), - l1Provider.send("eth_getCode", [l1BridgeStub.address]), - ]); - - await l1Provider.send("hardhat_setCode", [ - l1Bridge.address, - bridgeStubCode, - ]); - const bridgeCodeAfter = await l1Provider.send("eth_getCode", [ - l1Bridge.address, - ]); - - const l1BridgeEOA = await testing.impersonate(l1Bridge.address, l1Provider); - - await l1Bridge.setOutbox(l1OutboxStub.address); - - assert.equal(bridgeStubCode, bridgeCodeAfter); - assert.notEqual(bridgeCodeBefore, bridgeCodeAfter); - - const tx = await l1BridgeEOA.sendTransaction({ - to: l1ERC20TokenGateway.address, - data: ctx.constants.finalizeInboundTransferCalldata.withdraw, - }); - - await tx.wait(); - - await assert.emits(l1ERC20TokenGateway, tx, "WithdrawalFinalized", [ - l1Token.address, - accountB.address, - accountA.address, - 0, - withdrawalAmount, - ]); - - assert.equalBN( - accountABalanceBefore.add(withdrawalAmount), - await l1Token.balanceOf(accountA.address) - ); - - assert.equalBN( - l1ERC20TokenGatewayBalanceBefore.sub(withdrawalAmount), - await l1Token.balanceOf(l1ERC20TokenGateway.address) - ); - }) - - .run(); - -async function ctx() { - const networkName = env.network("TESTING_ARB_NETWORK", "mainnet"); - const { - l1Provider, - l2Provider, - l1ERC20TokenGatewayAdmin, - l2ERC20TokenGatewayAdmin, - ...contracts - } = await arbitrum.testing(networkName).getIntegrationTestSetup(); - - const l1Snapshot = await l1Provider.send("evm_snapshot", []); - const l2Snapshot = await l2Provider.send("evm_snapshot", []); - - // by default arbSys contract doesn't exist on the hardhat fork - // so we have to deploy there a stub contract - await arbitrum.testing(networkName).stubArbSysContract(); - - const accountA = testing.accounts.accountA(l1Provider, l2Provider); - const accountB = testing.accounts.accountB(l1Provider, l2Provider); - - const l1TokensHolderAddress = await contracts.l1TokensHolder.getAddress(); - - await testing.setBalance( - l1TokensHolderAddress, - wei.toBigNumber(wei`1 ether`), - l1Provider - ); - - const depositAmount = wei`0.15 ether`; - const withdrawalAmount = wei`0.05 ether`; - - await contracts.l1Token - .connect(contracts.l1TokensHolder) - .transfer(accountA.address, depositAmount); - - const l1ERC20TokenGatewayAliased = await testing.impersonate( - testing.accounts.applyL1ToL2Alias(contracts.l1ERC20TokenGateway.address), - l2Provider - ); - - const l1GatewayRouterAliased = await testing.impersonate( - testing.accounts.applyL1ToL2Alias(contracts.l1GatewayRouter.address), - l2Provider - ); - - await testing.setBalance( - await contracts.l1TokensHolder.getAddress(), - wei.toBigNumber(wei`1 ether`), - l1Provider - ); - - await testing.setBalance( - await l1ERC20TokenGatewayAdmin.getAddress(), - wei.toBigNumber(wei`1 ether`), - l1Provider - ); - - await testing.setBalance( - await l2ERC20TokenGatewayAdmin.getAddress(), - wei.toBigNumber(wei`1 ether`), - l2Provider - ); - - // send ether to l1GatewayRouterAliased to run transactions from it - // as from EOA - await testing.setBalance( - await l1GatewayRouterAliased.getAddress(), - wei.toBigNumber(wei`1 ether`), - l2Provider - ); - - // send ether to l1ERC20TokenGatewayAliased to run transactions from it - // as from EOA - - await testing.setBalance( - await l1ERC20TokenGatewayAliased.getAddress(), - wei.toBigNumber(wei`1 ether`), - l2Provider - ); - - const maxSubmissionCost = wei`200_000 gwei`; - - const l1GatewayRouterAdminAddress = await contracts.l1GatewayRouter.owner(); - - const l1GatewayRouterAdmin = await testing.impersonate( - l1GatewayRouterAdminAddress, - l1Provider - ); - - await testing.setBalance( - l1GatewayRouterAdminAddress, - wei.toBigNumber(wei`1 ether`), - l1Provider - ); - - const l1OutboxStub = await new OutboxStub__factory( - accountA.l1Signer - ).deploy(); - - await l1OutboxStub.setL2ToL1Sender(contracts.l2ERC20TokenGateway.address); - - const l1BridgeStub = await new BridgeStub__factory(accountA.l1Signer).deploy( - l1OutboxStub.address - ); - - const { Bridge: l1BridgeAddress } = arbitrumAddresses(networkName); - const l1Bridge = BridgeStub__factory.connect( - l1BridgeAddress, - accountA.l1Signer - ); - - return { - l1Provider, - l2Provider, - l1Bridge, - l1BridgeStub, - l1OutboxStub, - l1Token: contracts.l1Token, - l2Token: contracts.l2Token, - l2GatewayRouter: contracts.l2GatewayRouter, - l2ERC20TokenGateway: contracts.l2ERC20TokenGateway, - arbSys: contracts.arbSysStub, - l1GatewayRouter: contracts.l1GatewayRouter, - l1ERC20TokenGateway: contracts.l1ERC20TokenGateway, - accounts: { - accountA, - accountB, - l1BridgeAdmin: l1ERC20TokenGatewayAdmin, - l1GatewayRouterAdmin, - l2BridgeAdmin: l2ERC20TokenGatewayAdmin, - l1GatewayRouterAliased, - l1ERC20TokenGatewayAliased, - }, - constants: { - depositAmount, - withdrawalAmount, - maxGas: wei`300_000`, - gasPriceBid: wei`1 gwei`, - callValue: wei`500_000 gwei`, - maxSubmissionCost, - // data for outboundTransfer must contain encoded tuple with (maxSubmissionCost, emptyData) - outbdoundTransferData: ethers.utils.defaultAbiCoder.encode( - ["uint256", "bytes"], - [maxSubmissionCost, "0x"] - ), - finalizeInboundTransferCalldata: { - deposit: contracts.l2ERC20TokenGateway.interface.encodeFunctionData( - "finalizeInboundTransfer", - [ - contracts.l1Token.address, - accountA.address, - accountB.address, - depositAmount, - "0x", - ] - ), - withdraw: contracts.l2ERC20TokenGateway.interface.encodeFunctionData( - "finalizeInboundTransfer", - [ - contracts.l1Token.address, - accountB.address, - accountA.address, - withdrawalAmount, - "0x", - ] - ), - }, - }, - snapshot: { - l1: l1Snapshot, - l2: l2Snapshot, - }, - }; -} diff --git a/test/arbitrum/deployment.acceptance.test.ts b/test/arbitrum/deployment.acceptance.test.ts deleted file mode 100644 index 6ce0c0e0..00000000 --- a/test/arbitrum/deployment.acceptance.test.ts +++ /dev/null @@ -1,313 +0,0 @@ -import { assert } from "chai"; -import { - IERC20Metadata__factory, - OssifiableProxy__factory, -} from "../../typechain"; -import arbitrum from "../../utils/arbitrum"; -import { BridgingManagerRole } from "../../utils/bridging-management"; -import deployment from "../../utils/deployment"; -import env from "../../utils/env"; -import { getRoleHolders, scenario } from "../../utils/testing"; -import { wei } from "../../utils/wei"; - -scenario("Arbitrum Gateway :: deployment acceptance test", ctxFactory) - .step("L1 Bridge :: proxy admin", async (ctx) => { - assert.equal( - await ctx.l1ERC20TokenGatewayProxy.proxy__getAdmin(), - ctx.deployment.l1.proxyAdmin - ); - }) - - .step("L1 Bridge :: bridge admin", async (ctx) => { - const currentAdmins = await getRoleHolders( - ctx.l1ERC20TokenGateway, - BridgingManagerRole.DEFAULT_ADMIN_ROLE.hash - ); - assert.equal(currentAdmins.size, 1); - assert.isTrue(currentAdmins.has(ctx.deployment.l1.bridgeAdmin)); - - assert.isTrue( - await ctx.l1ERC20TokenGateway.hasRole( - BridgingManagerRole.DEFAULT_ADMIN_ROLE.hash, - ctx.deployment.l1.bridgeAdmin - ) - ); - }) - - .step("L1 bridge :: router", async (ctx) => { - assert.equal(await ctx.l1ERC20TokenGateway.router(), ctx.l1Router.address); - }) - - .step("L1 bridge :: L1 token", async (ctx) => { - assert.equal(await ctx.l1ERC20TokenGateway.l1Token(), ctx.deployment.token); - }) - - .step("L1 bridge :: L2 token", async (ctx) => { - assert.equal( - await ctx.l1ERC20TokenGateway.l2Token(), - ctx.erc20Bridged.address - ); - }) - .step("L1 bridge :: counterpart gateway", async (ctx) => { - assert.equal( - await ctx.l1ERC20TokenGateway.counterpartGateway(), - ctx.l2ERC20TokenGateway.address - ); - }) - .step("L1 Bridge :: is deposits enabled", async (ctx) => { - assert.equal( - await ctx.l1ERC20TokenGateway.isDepositsEnabled(), - ctx.deployment.l1.depositsEnabled - ); - }) - .step("L1 Bridge :: is withdrawals enabled", async (ctx) => { - assert.equal( - await ctx.l1ERC20TokenGateway.isWithdrawalsEnabled(), - ctx.deployment.l1.withdrawalsEnabled - ); - }) - .step("L1 Bridge :: deposits enablers", async (ctx) => { - const actualDepositsEnablers = await getRoleHolders( - ctx.l1ERC20TokenGateway, - BridgingManagerRole.DEPOSITS_ENABLER_ROLE.hash - ); - const expectedDepositsEnablers = ctx.deployment.l1.depositsEnablers || []; - - assert.equal(actualDepositsEnablers.size, expectedDepositsEnablers.length); - for (const expectedDepositsEnabler of expectedDepositsEnablers) { - assert.isTrue(actualDepositsEnablers.has(expectedDepositsEnabler)); - } - }) - .step("L1 Bridge :: deposits disablers", async (ctx) => { - const actualDepositsDisablers = await getRoleHolders( - ctx.l1ERC20TokenGateway, - BridgingManagerRole.DEPOSITS_DISABLER_ROLE.hash - ); - const expectedDepositsDisablers = ctx.deployment.l1.depositsDisablers || []; - - assert.equal( - actualDepositsDisablers.size, - expectedDepositsDisablers.length - ); - for (const expectedDepositsDisabler of expectedDepositsDisablers) { - assert.isTrue(actualDepositsDisablers.has(expectedDepositsDisabler)); - } - }) - .step("L1 Bridge :: withdrawals enablers", async (ctx) => { - const actualWithdrawalsEnablers = await getRoleHolders( - ctx.l1ERC20TokenGateway, - BridgingManagerRole.WITHDRAWALS_ENABLER_ROLE.hash - ); - const expectedWithdrawalsEnablers = - ctx.deployment.l1.withdrawalsEnablers || []; - - assert.equal( - actualWithdrawalsEnablers.size, - expectedWithdrawalsEnablers.length - ); - for (const expectedWithdrawalsEnabler of expectedWithdrawalsEnablers) { - assert.isTrue(actualWithdrawalsEnablers.has(expectedWithdrawalsEnabler)); - } - }) - .step("L1 Bridge :: withdrawals disablers", async (ctx) => { - const actualWithdrawalsDisablers = await getRoleHolders( - ctx.l1ERC20TokenGateway, - BridgingManagerRole.WITHDRAWALS_DISABLER_ROLE.hash - ); - const expectedWithdrawalsDisablers = - ctx.deployment.l1.withdrawalsDisablers || []; - - assert.equal( - actualWithdrawalsDisablers.size, - expectedWithdrawalsDisablers.length - ); - for (const expectedWithdrawalsDisabler of expectedWithdrawalsDisablers) { - assert.isTrue( - actualWithdrawalsDisablers.has(expectedWithdrawalsDisabler) - ); - } - }) - - .step("L2 Bridge :: proxy admin", async (ctx) => { - assert.equal( - await ctx.l2ERC20TokenGatewayProxy.proxy__getAdmin(), - ctx.deployment.l2.proxyAdmin - ); - }) - .step("L2 Bridge :: bridge admin", async (ctx) => { - const currentAdmins = await getRoleHolders( - ctx.l2ERC20TokenGateway, - BridgingManagerRole.DEFAULT_ADMIN_ROLE.hash - ); - assert.equal(currentAdmins.size, 1); - assert.isTrue(currentAdmins.has(ctx.deployment.l2.bridgeAdmin)); - - await assert.isTrue( - await ctx.l2ERC20TokenGateway.hasRole( - BridgingManagerRole.DEFAULT_ADMIN_ROLE.hash, - ctx.deployment.l2.bridgeAdmin - ) - ); - }) - .step("L2 bridge :: router", async (ctx) => { - assert.equal(await ctx.l2ERC20TokenGateway.router(), ctx.l2Router.address); - }) - .step("L2 bridge :: L1 token", async (ctx) => { - assert.equal(await ctx.l2ERC20TokenGateway.l1Token(), ctx.deployment.token); - }) - .step("L2 bridge :: L2 token", async (ctx) => { - assert.equal( - await ctx.l2ERC20TokenGateway.l2Token(), - ctx.erc20Bridged.address - ); - }) - .step("L2 bridge :: counterpart gateway", async (ctx) => { - assert.equal( - await ctx.l2ERC20TokenGateway.counterpartGateway(), - ctx.l1ERC20TokenGateway.address - ); - }) - .step("L2 Bridge :: is deposits enabled", async (ctx) => { - assert.equal( - await ctx.l2ERC20TokenGateway.isDepositsEnabled(), - ctx.deployment.l2.depositsEnabled - ); - }) - .step("L2 Bridge :: is withdrawals enabled", async (ctx) => { - assert.equal( - await ctx.l2ERC20TokenGateway.isWithdrawalsEnabled(), - ctx.deployment.l2.withdrawalsEnabled - ); - }) - .step("L2 Bridge :: deposits enablers", async (ctx) => { - const actualDepositsEnablers = await getRoleHolders( - ctx.l2ERC20TokenGateway, - BridgingManagerRole.DEPOSITS_ENABLER_ROLE.hash - ); - const expectedDepositsEnablers = ctx.deployment.l2.depositsEnablers || []; - - assert.equal(actualDepositsEnablers.size, expectedDepositsEnablers.length); - for (const expectedDepositsEnabler of expectedDepositsEnablers) { - assert.isTrue(actualDepositsEnablers.has(expectedDepositsEnabler)); - } - }) - .step("L2 Bridge :: deposits disablers", async (ctx) => { - const actualDepositsDisablers = await getRoleHolders( - ctx.l2ERC20TokenGateway, - BridgingManagerRole.DEPOSITS_DISABLER_ROLE.hash - ); - const expectedDepositsDisablers = ctx.deployment.l2.depositsDisablers || []; - - assert.equal( - actualDepositsDisablers.size, - expectedDepositsDisablers.length - ); - for (const expectedDepositsDisabler of expectedDepositsDisablers) { - assert.isTrue(actualDepositsDisablers.has(expectedDepositsDisabler)); - } - }) - .step("L2 Bridge :: withdrawals enablers", async (ctx) => { - const actualWithdrawalsEnablers = await getRoleHolders( - ctx.l2ERC20TokenGateway, - BridgingManagerRole.WITHDRAWALS_ENABLER_ROLE.hash - ); - const expectedWithdrawalsEnablers = - ctx.deployment.l2.withdrawalsEnablers || []; - - assert.equal( - actualWithdrawalsEnablers.size, - expectedWithdrawalsEnablers.length - ); - for (const expectedWithdrawalsEnabler of expectedWithdrawalsEnablers) { - assert.isTrue(actualWithdrawalsEnablers.has(expectedWithdrawalsEnabler)); - } - }) - .step("L2 Bridge :: withdrawals disablers", async (ctx) => { - const actualWithdrawalsDisablers = await getRoleHolders( - ctx.l2ERC20TokenGateway, - BridgingManagerRole.WITHDRAWALS_DISABLER_ROLE.hash - ); - const expectedWithdrawalsDisablers = - ctx.deployment.l2.withdrawalsDisablers || []; - - assert.equal( - actualWithdrawalsDisablers.size, - expectedWithdrawalsDisablers.length - ); - for (const expectedWithdrawalsDisabler of expectedWithdrawalsDisablers) { - assert.isTrue( - actualWithdrawalsDisablers.has(expectedWithdrawalsDisabler) - ); - } - }) - - .step("L2 Token :: proxy admin", async (ctx) => { - assert.equal( - await ctx.erc20BridgedProxy.proxy__getAdmin(), - ctx.deployment.l2.proxyAdmin - ); - }) - .step("L2 Token :: name", async (ctx) => { - assert.equal(await ctx.erc20Bridged.name(), ctx.l2TokenInfo.name); - }) - .step("L2 Token :: symbol", async (ctx) => { - assert.equal(await ctx.erc20Bridged.symbol(), ctx.l2TokenInfo.symbol); - }) - .step("L2 Token :: decimals", async (ctx) => { - assert.equal(await ctx.erc20Bridged.decimals(), ctx.l2TokenInfo.decimals); - }) - .step("L2 Token :: total supply", async (ctx) => { - assert.equalBN(await ctx.erc20Bridged.totalSupply(), wei`0`); - }) - .step("L2 token :: bridge", async (ctx) => { - assert.equalBN( - await ctx.erc20Bridged.bridge(), - ctx.l2ERC20TokenGateway.address - ); - }) - - .run(); - -async function ctxFactory() { - const networkName = env.network(); - const deploymentConfig = deployment.loadMultiChainDeploymentConfig(); - const testingSetup = await arbitrum - .testing(networkName) - .getAcceptanceTestSetup(); - - const l1TokenMeta = IERC20Metadata__factory.connect( - deploymentConfig.token, - testingSetup.l1Provider - ); - const [name, symbol, decimals] = await Promise.all([ - l1TokenMeta.name(), - l1TokenMeta.symbol(), - l1TokenMeta.decimals(), - ]); - - return { - deployment: deploymentConfig, - l1Router: testingSetup.l1GatewayRouter, - l2Router: testingSetup.l2GatewayRouter, - l2TokenInfo: { - name, - symbol, - decimals, - }, - l1ERC20TokenGateway: testingSetup.l1ERC20TokenGateway, - l1ERC20TokenGatewayProxy: OssifiableProxy__factory.connect( - testingSetup.l1ERC20TokenGateway.address, - testingSetup.l1Provider - ), - l2ERC20TokenGateway: testingSetup.l2ERC20TokenGateway, - l2ERC20TokenGatewayProxy: OssifiableProxy__factory.connect( - testingSetup.l2ERC20TokenGateway.address, - testingSetup.l2Provider - ), - erc20Bridged: testingSetup.l2Token, - erc20BridgedProxy: OssifiableProxy__factory.connect( - testingSetup.l2Token.address, - testingSetup.l2Provider - ), - }; -} diff --git a/test/arbitrum/managing-deposits.e2e.test.ts b/test/arbitrum/managing-deposits.e2e.test.ts deleted file mode 100644 index 1154cbca..00000000 --- a/test/arbitrum/managing-deposits.e2e.test.ts +++ /dev/null @@ -1,194 +0,0 @@ -import { L1ToL2MessageStatus } from "@arbitrum/sdk"; -import { assert } from "chai"; -import { ContractReceipt } from "ethers"; - -import { - L2ERC20TokenGateway__factory, - GovBridgeExecutor__factory, -} from "../../typechain"; -import { - E2E_TEST_CONTRACTS_ARBITRUM as E2E_TEST_CONTRACTS, - sleep, -} from "../../utils/testing/e2e"; -import { wei } from "../../utils/wei"; -import network from "../../utils/network"; -import env from "../../utils/env"; -import { scenario } from "../../utils/testing"; -import arbitrum from "../../utils/arbitrum"; -import lido from "../../utils/lido"; - -const DEPOSIT_ENABLER_ROLE = - "0x4b43b36766bde12c5e9cbbc37d15f8d1f769f08f54720ab370faeb4ce893753a"; -const DEPOSIT_DISABLER_ROLE = - "0x63f736f21cb2943826cd50b191eb054ebbea670e4e962d0527611f830cd399d6"; - -let l2DepositsInitialState: boolean; -let ticketTx: ContractReceipt; - -const scenarioTest = scenario( - "Arbitrum :: AAVE governance crosschain bridge: token bridge management", - ctxFactory -) - .step("LDO Holder has enought ETH", async ({ l1LDOHolder, gasAmount }) => { - assert.gte(await l1LDOHolder.getBalance(), gasAmount); - }) - - .step("L2 Tester has enought ETH", async ({ l2Tester, gasAmount }) => { - assert.gte(await l2Tester.getBalance(), gasAmount); - }) - - .step( - "L2 Agent has enought ETH", - async ({ l1Provider, lidoAragonDAO, gasAmount }) => { - assert.gte( - await l1Provider.getBalance(lidoAragonDAO.agent.address), - gasAmount - ); - } - ) - - .step("Checking deposits status", async ({ l2ERC20TokenGateway }) => { - l2DepositsInitialState = await l2ERC20TokenGateway.isDepositsEnabled(); - }) - - .step(`Starting DAO vote`, async (ctx) => { - const grantRoleCalldata = - ctx.l2ERC20TokenGateway.interface.encodeFunctionData("grantRole", [ - l2DepositsInitialState ? DEPOSIT_DISABLER_ROLE : DEPOSIT_ENABLER_ROLE, - ctx.govBridgeExecutor.address, - ]); - const grantRoleData = "0x" + grantRoleCalldata.substring(10); - - const actionCalldata = l2DepositsInitialState - ? ctx.l2ERC20TokenGateway.interface.encodeFunctionData("disableDeposits") - : ctx.l2ERC20TokenGateway.interface.encodeFunctionData("enableDeposits"); - - const actionData = "0x" + actionCalldata.substring(10); - - const executorCalldata = - await ctx.govBridgeExecutor.interface.encodeFunctionData("queue", [ - [ctx.l2ERC20TokenGateway.address, ctx.l2ERC20TokenGateway.address], - [0, 0], - [ - "grantRole(bytes32,address)", - l2DepositsInitialState ? "disableDeposits()" : "enableDeposits()", - ], - [grantRoleData, actionData], - [false, false], - ]); - - const arbAddresses = arbitrum.addresses("sepolia"); - - const { calldata, callvalue } = - await ctx.messaging.prepareRetryableTicketTx({ - sender: ctx.lidoAragonDAO.agent.address, - recipient: ctx.govBridgeExecutor.address, - calldata: executorCalldata, - refundAddress: ctx.l2Tester.address, - }); - - const tx = await ctx.lidoAragonDAO.createVote( - ctx.l1LDOHolder, - "E2E Test Voting", - { - address: ctx.lidoAragonDAO.agent.address, - signature: "execute(address,uint256,bytes)", - decodedCallData: [arbAddresses.Inbox, callvalue, calldata], - } - ); - - await tx.wait(); - }) - - .step("Enacting Vote", async ({ l1LDOHolder, lidoAragonDAO }) => { - const votesLength = await lidoAragonDAO.voting.votesLength(); - - const tx = await lidoAragonDAO.voteAndExecute( - l1LDOHolder, - votesLength.toNumber() - 1 - ); - - ticketTx = await tx.wait(); - }) - - .step("Waiting for L2 tx", async ({ messaging }) => { - const { status } = await messaging.waitForL2Message( - ticketTx.transactionHash - ); - - assert.equal( - status, - L1ToL2MessageStatus.REDEEMED, - `L2 retryable txn failed with status ${L1ToL2MessageStatus[status]}` - ); - }) - - .step("Execute queued task", async ({ govBridgeExecutor, l2Tester }) => { - const tasksCount = await govBridgeExecutor.getActionsSetCount(); - - const targetTask = tasksCount.toNumber() - 1; - - const executionTime = ( - await govBridgeExecutor.getActionsSetById(targetTask) - ).executionTime.toNumber(); - let chainTime; - - do { - await sleep(5000); - const currentBlockNumber = await l2Tester.provider.getBlockNumber(); - const currentBlock = await l2Tester.provider.getBlock(currentBlockNumber); - chainTime = currentBlock.timestamp; - } while (chainTime <= executionTime); - - const tx = await govBridgeExecutor.execute(targetTask, { - gasLimit: 1000000, - }); - await tx.wait(); - }) - - .step("Checking deposits state", async ({ l2ERC20TokenGateway }) => { - assert.equal( - await l2ERC20TokenGateway.isDepositsEnabled(), - !l2DepositsInitialState - ); - }); - -// make first run to change state from enabled/disabled -> disabled/enabled -scenarioTest.run(); - -// make another run to return the state to the initial and test vice versa actions -scenarioTest.run(); - -async function ctxFactory() { - const ethArbNetwork = network.multichain(["eth", "arb"], "sepolia"); - - const [l1Provider] = ethArbNetwork.getProviders({ - forking: false, - }); - const [, l2Tester] = ethArbNetwork.getSigners( - env.string("TESTING_PRIVATE_KEY"), - { forking: false } - ); - - const [l1LDOHolder] = ethArbNetwork.getSigners( - env.string("TESTING_ARB_LDO_HOLDER_PRIVATE_KEY"), - { forking: false } - ); - - return { - lidoAragonDAO: lido("sepolia", l1Provider), - messaging: arbitrum.messaging("sepolia", { forking: false }), - gasAmount: wei`0.1 ether`, - l2Tester, - l1Provider, - l1LDOHolder, - l2ERC20TokenGateway: L2ERC20TokenGateway__factory.connect( - E2E_TEST_CONTRACTS.l2.l2ERC20TokenGateway, - l2Tester - ), - govBridgeExecutor: GovBridgeExecutor__factory.connect( - E2E_TEST_CONTRACTS.l2.govBridgeExecutor, - l2Tester - ), - }; -} diff --git a/test/arbitrum/managing-executor.e2e.test.ts b/test/arbitrum/managing-executor.e2e.test.ts deleted file mode 100644 index 0dc6a15b..00000000 --- a/test/arbitrum/managing-executor.e2e.test.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { assert } from "chai"; -import { ContractReceipt } from "ethers"; -import { L1ToL2MessageStatus } from "@arbitrum/sdk"; - -import { GovBridgeExecutor__factory } from "../../typechain"; -import { - E2E_TEST_CONTRACTS_ARBITRUM as E2E_TEST_CONTRACTS, - sleep, -} from "../../utils/testing/e2e"; -import env from "../../utils/env"; -import network from "../../utils/network"; -import { wei } from "../../utils/wei"; -import { scenario } from "../../utils/testing"; -import arbitrum from "../../utils/arbitrum"; -import lido from "../../utils/lido"; - -let oldGuardian: string; -let newGuardian: string; -let ticketTx: ContractReceipt; - -scenario("Arbitrum :: Update guardian", ctxFactory) - .step("LDO Holder has enought ETH", async ({ l1LDOHolder, gasAmount }) => { - assert.gte(await l1LDOHolder.getBalance(), gasAmount); - }) - - .step("L2 Tester has enought ETH", async ({ l2Tester, gasAmount }) => { - assert.gte(await l2Tester.getBalance(), gasAmount); - }) - - .step( - "L2 Agent has enought ETH", - async ({ l1Provider, lidoAragonDAO, gasAmount }) => { - assert.gte( - await l1Provider.getBalance(lidoAragonDAO.agent.address), - gasAmount - ); - } - ) - - .step(`Starting DAO vote: Update guardian`, async (ctx) => { - oldGuardian = await ctx.govBridgeExecutor.getGuardian(); - newGuardian = - oldGuardian === "0x4e8CC9024Ea3FE886623025fF2aD0CA4bb3D1F42" - ? "0xD06491e4C8B3107B83dC134894C4c96ED8ddbfa2" - : "0x4e8CC9024Ea3FE886623025fF2aD0CA4bb3D1F42"; - - const updateGuardianCalldata = - ctx.govBridgeExecutor.interface.encodeFunctionData("updateGuardian", [ - newGuardian, - ]); - const updateGuardianData = "0x" + updateGuardianCalldata.substring(10); - - const executorCalldata = - await ctx.govBridgeExecutor.interface.encodeFunctionData("queue", [ - [ctx.govBridgeExecutor.address], - [0], - ["updateGuardian(address)"], - [updateGuardianData], - [false], - ]); - - const arbAddresses = arbitrum.addresses("sepolia"); - - const { calldata, callvalue } = - await ctx.messaging.prepareRetryableTicketTx({ - sender: ctx.lidoAragonDAO.agent.address, - recipient: ctx.govBridgeExecutor.address, - calldata: executorCalldata, - refundAddress: ctx.l2Tester.address, - }); - - const tx = await ctx.lidoAragonDAO.createVote( - ctx.l1LDOHolder, - "E2E Test Voting", - { - address: ctx.lidoAragonDAO.agent.address, - signature: "execute(address,uint256,bytes)", - decodedCallData: [arbAddresses.Inbox, callvalue, calldata], - } - ); - - await tx.wait(); - }) - - .step("Enacting Vote", async ({ l1LDOHolder, lidoAragonDAO }) => { - const votesLength = await lidoAragonDAO.voting.votesLength(); - - const tx = await lidoAragonDAO.voteAndExecute( - l1LDOHolder, - votesLength.toNumber() - 1 - ); - - ticketTx = await tx.wait(); - }) - - .step("Waiting for L2 tx", async ({ messaging }) => { - const { status } = await messaging.waitForL2Message( - ticketTx.transactionHash - ); - - assert.equal( - status, - L1ToL2MessageStatus.REDEEMED, - `L2 retryable txn failed with status ${L1ToL2MessageStatus[status]}` - ); - }) - - .step("Execute queued task", async ({ govBridgeExecutor, l2Tester }) => { - const tasksCount = await govBridgeExecutor.getActionsSetCount(); - - const targetTask = tasksCount.toNumber() - 1; - - const executionTime = ( - await govBridgeExecutor.getActionsSetById(targetTask) - ).executionTime.toNumber(); - let chainTime; - - do { - await sleep(5000); - const currentBlockNumber = await l2Tester.provider.getBlockNumber(); - const currentBlock = await l2Tester.provider.getBlock(currentBlockNumber); - chainTime = currentBlock.timestamp; - } while (chainTime <= executionTime); - - const tx = await govBridgeExecutor.execute(targetTask, { - gasLimit: 1000000, - }); - await tx.wait(); - }) - - .step("Checking guardian", async ({ govBridgeExecutor }) => { - assert.equal(await govBridgeExecutor.getGuardian(), newGuardian); - }) - .run(); - -async function ctxFactory() { - const ethArbNetwork = network.multichain(["eth", "arb"], "sepolia"); - - const [l1Provider] = ethArbNetwork.getProviders({ - forking: false, - }); - const [, l2Tester] = ethArbNetwork.getSigners( - env.string("TESTING_PRIVATE_KEY"), - { forking: false } - ); - - const [l1LDOHolder] = ethArbNetwork.getSigners( - env.string("TESTING_ARB_LDO_HOLDER_PRIVATE_KEY"), - { forking: false } - ); - - return { - lidoAragonDAO: lido("sepolia", l1Provider), - messaging: arbitrum.messaging("sepolia", { forking: false }), - gasAmount: wei`0.1 ether`, - l2Tester, - l1Provider, - l1LDOHolder, - govBridgeExecutor: GovBridgeExecutor__factory.connect( - E2E_TEST_CONTRACTS.l2.govBridgeExecutor, - l2Tester - ), - }; -} diff --git a/test/arbitrum/managing-proxy.e2e.test.ts b/test/arbitrum/managing-proxy.e2e.test.ts deleted file mode 100644 index e8342cfa..00000000 --- a/test/arbitrum/managing-proxy.e2e.test.ts +++ /dev/null @@ -1,284 +0,0 @@ -import { L1ToL2MessageStatus, L1TransactionReceipt } from "@arbitrum/sdk"; -import { assert } from "chai"; -import { ContractReceipt } from "ethers"; - -import { - ERC20Bridged__factory, - L2ERC20TokenGateway__factory, - GovBridgeExecutor__factory, - OssifiableProxy__factory, -} from "../../typechain"; -import { - E2E_TEST_CONTRACTS_ARBITRUM as E2E_TEST_CONTRACTS, - sleep, -} from "../../utils/testing/e2e"; -import env from "../../utils/env"; -import { wei } from "../../utils/wei"; -import network from "../../utils/network"; -import { scenario } from "../../utils/testing"; -import arbitrum from "../../utils/arbitrum"; -import lido from "../../utils/lido"; - -let upgradeMessageResponse: ContractReceipt; -let ossifyMessageResponse: ContractReceipt; - -scenario("Arbitrum :: AAVE governance crosschain bridge", ctxFactory) - .step("LDO Holder has enought ETH", async ({ l1LDOHolder, gasAmount }) => { - assert.gte(await l1LDOHolder.getBalance(), gasAmount); - }) - - .step("L2 Tester has enought ETH", async ({ l2Tester, gasAmount }) => { - assert.gte(await l2Tester.getBalance(), gasAmount); - }) - - .step( - "L2 Agent has enought ETH", - async ({ l1Provider, lidoAragonDAO, gasAmount }) => { - assert.gte( - await l1Provider.getBalance(lidoAragonDAO.agent.address), - gasAmount - ); - } - ) - .step("Check OssifiableProxy deployed correct", async (ctx) => { - const { proxyToOssify } = ctx; - const admin = await proxyToOssify.proxy__getAdmin(); - - assert.equal(admin, E2E_TEST_CONTRACTS.l2.govBridgeExecutor); - }) - - .step("Proxy upgrade: send crosschain message", async (ctx) => { - const implBefore = await await ctx.proxyToOssify.proxy__getImplementation(); - - assert.equal(implBefore, ctx.l2ERC20TokenGateway.address); - - const executorCalldata = - await ctx.govBridgeExecutor.interface.encodeFunctionData("queue", [ - [ctx.proxyToOssify.address], - [0], - ["proxy__upgradeTo(address)"], - [ - "0x" + - ctx.proxyToOssify.interface - .encodeFunctionData("proxy__upgradeTo", [ctx.l2Token.address]) - .substring(10), - ], - [false], - ]); - - const arbAddresses = arbitrum.addresses("sepolia"); - - const { calldata, callvalue } = - await ctx.messaging.prepareRetryableTicketTx({ - sender: ctx.lidoAragonDAO.agent.address, - recipient: ctx.govBridgeExecutor.address, - calldata: executorCalldata, - refundAddress: ctx.l2Tester.address, - }); - - const tx = await ctx.lidoAragonDAO.createVote( - ctx.l1LDOHolder, - "E2E Test Voting", - { - address: ctx.lidoAragonDAO.agent.address, - signature: "execute(address,uint256,bytes)", - decodedCallData: [arbAddresses.Inbox, callvalue, calldata], - } - ); - - await tx.wait(); - }) - - .step( - "Proxy upgrade: Enacting Voting", - async ({ l1LDOHolder, lidoAragonDAO }) => { - const votesLength = await lidoAragonDAO.voting.votesLength(); - - const tx = await lidoAragonDAO.voteAndExecute( - l1LDOHolder, - votesLength.toNumber() - 1 - ); - - upgradeMessageResponse = await tx.wait(); - } - ) - - .step("Proxy upgrade: Waiting for L2 tx", async ({ messaging, l2Tester }) => { - const { status } = await messaging.waitForL2Message( - upgradeMessageResponse.transactionHash - ); - - if (status === L1ToL2MessageStatus.FUNDS_DEPOSITED_ON_L2) { - console.warn( - `Auto redeem for tx ${upgradeMessageResponse.transactionHash} failed. Redeeming it manually...` - ); - const l1TxReceipt = new L1TransactionReceipt(upgradeMessageResponse); - const [message] = await l1TxReceipt.getL1ToL2Messages(l2Tester); - const redeemResponse = await message.redeem({ gasLimit: 300_000 }); - await redeemResponse.wait(); - console.log("Tx was redeemed"); - } else if (status === L1ToL2MessageStatus.REDEEMED) { - console.log("Tx was auto redeemed"); - } else { - assert.isTrue( - false, - `L2 retryable txn failed with status ${L1ToL2MessageStatus[status]}` - ); - } - }) - - .step( - "Proxy upgrade: Execute queued task", - async ({ govBridgeExecutor, l2Tester }) => { - const tasksCount = await govBridgeExecutor.getActionsSetCount(); - - const targetTask = tasksCount.toNumber() - 1; - - const executionTime = ( - await govBridgeExecutor.getActionsSetById(targetTask) - ).executionTime.toNumber(); - let chainTime; - - do { - await sleep(5000); - const currentBlockNumber = await l2Tester.provider.getBlockNumber(); - const currentBlock = await l2Tester.provider.getBlock( - currentBlockNumber - ); - chainTime = currentBlock.timestamp; - } while (chainTime <= executionTime); - - const tx = await govBridgeExecutor.execute(targetTask, { - gasLimit: 1000000, - }); - await tx.wait(); - } - ) - - .step("Proxy upgrade: check state", async ({ proxyToOssify, l2Token }) => { - const implAfter = await await proxyToOssify.proxy__getImplementation(); - assert.equal(implAfter, l2Token.address); - }) - - .step("Proxy ossify: send crosschain message", async (ctx) => { - const isOssifiedBefore = await ctx.proxyToOssify.proxy__getIsOssified(); - assert.isFalse(isOssifiedBefore); - - const executorCalldata = - await ctx.govBridgeExecutor.interface.encodeFunctionData("queue", [ - [ctx.proxyToOssify.address], - [0], - ["proxy__ossify()"], - ["0x00"], - [false], - ]); - - const arbAddresses = arbitrum.addresses("sepolia"); - - const { calldata, callvalue } = - await ctx.messaging.prepareRetryableTicketTx({ - sender: ctx.lidoAragonDAO.agent.address, - recipient: ctx.govBridgeExecutor.address, - calldata: executorCalldata, - refundAddress: ctx.l2Tester.address, - }); - - const tx = await ctx.lidoAragonDAO.createVote( - ctx.l1LDOHolder, - "E2E Test Voting", - { - address: ctx.lidoAragonDAO.agent.address, - signature: "execute(address,uint256,bytes)", - decodedCallData: [arbAddresses.Inbox, callvalue, calldata], - } - ); - - await tx.wait(); - }) - - .step( - "Proxy ossify: Enacting Voting", - async ({ lidoAragonDAO, l1LDOHolder }) => { - const votesLength = await lidoAragonDAO.voting.votesLength(); - - const tx = await lidoAragonDAO.voteAndExecute( - l1LDOHolder, - votesLength.toNumber() - 1 - ); - - ossifyMessageResponse = await tx.wait(); - } - ) - - .step("Proxy ossify: Waiting for L2 tx", async ({ messaging }) => { - const { status } = await messaging.waitForL2Message( - ossifyMessageResponse.transactionHash - ); - - assert.equal( - status, - L1ToL2MessageStatus.REDEEMED, - `L2 retryable txn failed with status ${L1ToL2MessageStatus[status]}` - ); - }) - - .step("Proxy ossify: execute", async ({ govBridgeExecutor }) => { - const taskId = - (await govBridgeExecutor.getActionsSetCount()).toNumber() - 1; - const executeTx = await govBridgeExecutor.execute(taskId, { - gasLimit: 2000000, - }); - await executeTx.wait(); - }) - - .step("Proxy upgrade: check state", async ({ proxyToOssify }) => { - const isOssifiedAfter = await proxyToOssify.proxy__getIsOssified(); - - assert.isTrue(isOssifiedAfter); - }) - - .run(); - -async function ctxFactory() { - const ethArbNetwork = network.multichain(["eth", "arb"], "sepolia"); - - const [l1Provider] = ethArbNetwork.getProviders({ - forking: false, - }); - const [, l2Tester] = ethArbNetwork.getSigners( - env.string("TESTING_PRIVATE_KEY"), - { forking: false } - ); - - const [l1LDOHolder] = ethArbNetwork.getSigners( - env.string("TESTING_ARB_LDO_HOLDER_PRIVATE_KEY"), - { forking: false } - ); - - return { - lidoAragonDAO: lido("sepolia", l1Provider), - messaging: arbitrum.messaging("sepolia", { forking: false }), - gasAmount: wei`0.1 ether`, - l2Tester, - l1LDOHolder, - l1Provider, - - l2Token: ERC20Bridged__factory.connect( - E2E_TEST_CONTRACTS.l2.l2Token, - l2Tester - ), - l2ERC20TokenGateway: L2ERC20TokenGateway__factory.connect( - E2E_TEST_CONTRACTS.l2.l2ERC20TokenGateway, - l2Tester - ), - govBridgeExecutor: GovBridgeExecutor__factory.connect( - E2E_TEST_CONTRACTS.l2.govBridgeExecutor, - l2Tester - ), - proxyToOssify: await new OssifiableProxy__factory(l2Tester).deploy( - E2E_TEST_CONTRACTS.l2.l2ERC20TokenGateway, - E2E_TEST_CONTRACTS.l2.govBridgeExecutor, - "0x" - ), - }; -} diff --git a/test/bridge-executor/arbitrum.integration.test.ts b/test/bridge-executor/arbitrum.integration.test.ts deleted file mode 100644 index 3bfcce5a..00000000 --- a/test/bridge-executor/arbitrum.integration.test.ts +++ /dev/null @@ -1,273 +0,0 @@ -import { assert } from "chai"; -import testing, { scenario } from "../../utils/testing"; -import { - ERC20BridgedStub__factory, - L2ERC20TokenGateway__factory, - ArbitrumBridgeExecutor__factory, - ERC20Bridged__factory, - OssifiableProxy__factory, -} from "../../typechain"; -import { wei } from "../../utils/wei"; -import { getBridgeExecutorParams } from "../../utils/bridge-executor"; -import { BridgingManagerRole } from "../../utils/bridging-management"; - -import arbitrum from "../../utils/arbitrum"; -import network from "../../utils/network"; -import env from "../../utils/env"; - -scenario("Arbitrum :: Bridge Executor integration test", ctx) - .before(async (ctx) => { - ctx.snapshot.l2 = await ctx.l2.provider.send("evm_snapshot", []); - }) - - .after(async (ctx) => { - await ctx.l2.provider.send("evm_revert", [ctx.snapshot.l2]); - }) - - .step("Activate Bridging", async (ctx) => { - const { - l2: { bridgeExecutor, l2ERC20TokenGateway }, - } = ctx; - - assert.isFalse( - await l2ERC20TokenGateway.hasRole( - BridgingManagerRole.DEPOSITS_ENABLER_ROLE.hash, - bridgeExecutor.address - ) - ); - assert.isFalse( - await l2ERC20TokenGateway.hasRole( - BridgingManagerRole.WITHDRAWALS_ENABLER_ROLE.hash, - bridgeExecutor.address - ) - ); - assert.isFalse(await l2ERC20TokenGateway.isDepositsEnabled()); - assert.isFalse(await l2ERC20TokenGateway.isWithdrawalsEnabled()); - - const actionsSetCountBefore = await bridgeExecutor.getActionsSetCount(); - await bridgeExecutor.queue( - new Array(4).fill(l2ERC20TokenGateway.address), - new Array(4).fill(0), - [ - "grantRole(bytes32,address)", - "grantRole(bytes32,address)", - "enableDeposits()", - "enableWithdrawals()", - ], - [ - "0x" + - l2ERC20TokenGateway.interface - .encodeFunctionData("grantRole", [ - BridgingManagerRole.DEPOSITS_ENABLER_ROLE.hash, - bridgeExecutor.address, - ]) - .substring(10), - "0x" + - l2ERC20TokenGateway.interface - .encodeFunctionData("grantRole", [ - BridgingManagerRole.WITHDRAWALS_ENABLER_ROLE.hash, - bridgeExecutor.address, - ]) - .substring(10), - "0x" + - l2ERC20TokenGateway.interface - .encodeFunctionData("enableDeposits") - .substring(10), - "0x" + - l2ERC20TokenGateway.interface - .encodeFunctionData("enableWithdrawals") - .substring(10), - ], - new Array(4).fill(false) - ); - - const actionsSetCountAfter = await bridgeExecutor.getActionsSetCount(); - - assert.equalBN(actionsSetCountBefore.add(1), actionsSetCountAfter); - // execute the last added actions set - await bridgeExecutor.execute(actionsSetCountAfter.sub(1), { value: 0 }); - - assert.isTrue( - await l2ERC20TokenGateway.hasRole( - BridgingManagerRole.DEPOSITS_ENABLER_ROLE.hash, - bridgeExecutor.address - ) - ); - assert.isTrue( - await l2ERC20TokenGateway.hasRole( - BridgingManagerRole.WITHDRAWALS_ENABLER_ROLE.hash, - bridgeExecutor.address - ) - ); - assert.isTrue(await l2ERC20TokenGateway.isDepositsEnabled()); - assert.isTrue(await l2ERC20TokenGateway.isWithdrawalsEnabled()); - }) - - .step("Change Proxy implementation", async (ctx) => { - const { - l2: { l2Token, bridgeExecutor, l2ERC20TokenGatewayProxy }, - } = ctx; - - const actionsSetCountBefore = await bridgeExecutor.getActionsSetCount(); - - const proxyImplBefore = - await l2ERC20TokenGatewayProxy.proxy__getImplementation(); - - await bridgeExecutor.queue( - [l2ERC20TokenGatewayProxy.address], - [0], - ["proxy__upgradeTo(address)"], - [ - "0x" + - l2ERC20TokenGatewayProxy.interface - .encodeFunctionData("proxy__upgradeTo", [l2Token.address]) - .substring(10), - ], - [false] - ); - - const actionSetCount = await bridgeExecutor.getActionsSetCount(); - - assert.equalBN(actionsSetCountBefore.add(1), actionSetCount); - - await bridgeExecutor.execute(actionsSetCountBefore, { value: 0 }); - const proxyImplAfter = - await l2ERC20TokenGatewayProxy.proxy__getImplementation(); - - assert.notEqual(proxyImplBefore, proxyImplAfter); - assert.equal(proxyImplAfter, l2Token.address); - }) - - .step("Change proxy Admin", async (ctx) => { - const { - l2: { - l2ERC20TokenGatewayProxy, - bridgeExecutor, - accounts: { deployer }, - }, - } = ctx; - const proxyAdminBefore = await l2ERC20TokenGatewayProxy.proxy__getAdmin(); - - const actionsSetCountBefore = await bridgeExecutor.getActionsSetCount(); - - await bridgeExecutor.queue( - [l2ERC20TokenGatewayProxy.address], - [0], - ["proxy__changeAdmin(address)"], - [ - "0x" + - l2ERC20TokenGatewayProxy.interface - .encodeFunctionData("proxy__changeAdmin", [deployer.address]) - .substring(10), - ], - [false] - ); - - const actionSetCount = await bridgeExecutor.getActionsSetCount(); - assert.equalBN(actionsSetCountBefore.add(1), actionSetCount); - - await bridgeExecutor.execute(actionsSetCountBefore, { value: 0 }); - const proxyAdminAfter = await l2ERC20TokenGatewayProxy.proxy__getAdmin(); - - assert.notEqual(proxyAdminBefore, proxyAdminAfter); - assert.equal(proxyAdminAfter, deployer.address); - }) - - .run(); - -async function ctx() { - const networkName = env.network("TESTING_ARB_NETWORK", "mainnet"); - const [l1Provider, l2Provider] = network - .multichain(["eth", "arb"], networkName) - .getProviders({ forking: true }); - - const testingOnDeployedContracts = testing.env.USE_DEPLOYED_CONTRACTS(false); - - const l1Deployer = testing.accounts.deployer(l1Provider); - const l2Deployer = testing.accounts.deployer(l2Provider); - - await arbitrum.testing(networkName).stubArbSysContract(); - - const l1Token = await new ERC20BridgedStub__factory(l1Deployer).deploy( - "Test Token", - "TT" - ); - const govBridgeExecutor = testingOnDeployedContracts - ? ArbitrumBridgeExecutor__factory.connect( - testing.env.ARB_GOV_BRIDGE_EXECUTOR(), - l2Provider - ) - : await new ArbitrumBridgeExecutor__factory(l2Deployer).deploy( - l1Deployer.address, - ...getBridgeExecutorParams(), - l2Deployer.address - ); - - const l1EthGovExecutorAddress = - await govBridgeExecutor.getEthereumGovernanceExecutor(); - - const [, l2DeployScript] = await arbitrum - .deployment(networkName) - .erc20TokenGatewayDeployScript( - l1Token.address, - { - deployer: l1Deployer, - admins: { proxy: l1Deployer.address, bridge: l1Deployer.address }, - }, - { - deployer: l2Deployer, - admins: { - proxy: govBridgeExecutor.address, - bridge: govBridgeExecutor.address, - }, - } - ); - - await l2DeployScript.run(); - - const l2Token = ERC20Bridged__factory.connect( - l2DeployScript.getContractAddress(1), - l2Deployer - ); - const l2ERC20TokenGateway = L2ERC20TokenGateway__factory.connect( - l2DeployScript.getContractAddress(3), - l2Deployer - ); - const l2ERC20TokenGatewayProxy = OssifiableProxy__factory.connect( - l2DeployScript.getContractAddress(3), - l2Deployer - ); - const l1ExecutorAliased = await testing.impersonate( - testing.accounts.applyL1ToL2Alias(l1EthGovExecutorAddress), - l2Provider - ); - - await testing.setBalance( - await l1ExecutorAliased.getAddress(), - wei.toBigNumber(wei`1 ether`), - l2Provider - ); - - if (testingOnDeployedContracts) { - console.log("Testing on deployed contracts"); - console.log(` Network name: ${networkName}`); - console.log(` Gov Bridge Executor Address: ${govBridgeExecutor.address}`); - } - - return { - l2: { - l2Token, - bridgeExecutor: govBridgeExecutor.connect(l1ExecutorAliased), - l2ERC20TokenGateway, - l2ERC20TokenGatewayProxy, - accounts: { - deployer: l2Deployer, - }, - provider: l2Provider, - }, - snapshot: { - l1: "", - l2: "", - }, - }; -} diff --git a/utils/arbitrum/addresses.ts b/utils/arbitrum/addresses.ts deleted file mode 100644 index d06b22ed..00000000 --- a/utils/arbitrum/addresses.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { NetworkName } from "../network"; -import { ArbContractAddresses, CommonOptions } from "./types"; - -const ArbitrumMainnetAddresses: ArbContractAddresses = { - Inbox: "0x4Dbd4fc535Ac27206064B68FfCf827b0A60BAB3f", - ArbSys: "0x0000000000000000000000000000000000000064", - Bridge: "0x8315177ab297ba92a06054ce80a67ed4dbd7ed3a", - Outbox: "0x760723CD2e632826c38Fef8CD438A4CC7E7E1A40", - L1GatewayRouter: "0x72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef", - L2GatewayRouter: "0x5288c571Fd7aD117beA99bF60FE0846C4E84F933", -}; - -const ArbitrumGoerliAddresses: ArbContractAddresses = { - Inbox: "0x6BEbC4925716945D46F0Ec336D5C2564F419682C", - ArbSys: "0x0000000000000000000000000000000000000064", - Bridge: "0xaf4159A80B6Cc41ED517DB1c453d1Ef5C2e4dB72", - Outbox: "0x45Af9Ed1D03703e480CE7d328fB684bb67DA5049", - L1GatewayRouter: "0x4c7708168395aEa569453Fc36862D2ffcDaC588c", - L2GatewayRouter: "0xE5B9d8d42d656d1DcB8065A6c012FE3780246041", -}; - -export default function addresses( - networkName: NetworkName, - options: CommonOptions = {} -) { - switch (networkName) { - case "mainnet": - return { ...ArbitrumMainnetAddresses, ...options.customAddresses }; - case "sepolia": - return { ...ArbitrumGoerliAddresses, ...options.customAddresses }; - default: - throw new Error(`Network "${networkName}" is not supported`); - } -} diff --git a/utils/arbitrum/artifacts/ArbitrumBridgeExecutor.json b/utils/arbitrum/artifacts/ArbitrumBridgeExecutor.json deleted file mode 100644 index 73fa1fbb..00000000 --- a/utils/arbitrum/artifacts/ArbitrumBridgeExecutor.json +++ /dev/null @@ -1,696 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "ArbitrumBridgeExecutor", - "sourceName": "contracts/bridges/ArbitrumBridgeExecutor.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "ethereumGovernanceExecutor", - "type": "address" - }, - { - "internalType": "uint256", - "name": "delay", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gracePeriod", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "minimumDelay", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maximumDelay", - "type": "uint256" - }, - { - "internalType": "address", - "name": "guardian", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "DelayLongerThanMax", - "type": "error" - }, - { - "inputs": [], - "name": "DelayShorterThanMin", - "type": "error" - }, - { - "inputs": [], - "name": "DuplicateAction", - "type": "error" - }, - { - "inputs": [], - "name": "EmptyTargets", - "type": "error" - }, - { - "inputs": [], - "name": "FailedActionExecution", - "type": "error" - }, - { - "inputs": [], - "name": "GracePeriodTooShort", - "type": "error" - }, - { - "inputs": [], - "name": "InconsistentParamsLength", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidActionsSetId", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitParams", - "type": "error" - }, - { - "inputs": [], - "name": "MaximumDelayTooShort", - "type": "error" - }, - { - "inputs": [], - "name": "MinimumDelayTooLong", - "type": "error" - }, - { - "inputs": [], - "name": "NotGuardian", - "type": "error" - }, - { - "inputs": [], - "name": "OnlyCallableByThis", - "type": "error" - }, - { - "inputs": [], - "name": "OnlyQueuedActions", - "type": "error" - }, - { - "inputs": [], - "name": "TimelockNotFinished", - "type": "error" - }, - { - "inputs": [], - "name": "UnauthorizedEthereumExecutor", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "id", - "type": "uint256" - } - ], - "name": "ActionsSetCanceled", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "id", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "initiatorExecution", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes[]", - "name": "returnedData", - "type": "bytes[]" - } - ], - "name": "ActionsSetExecuted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "id", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address[]", - "name": "targets", - "type": "address[]" - }, - { - "indexed": false, - "internalType": "uint256[]", - "name": "values", - "type": "uint256[]" - }, - { - "indexed": false, - "internalType": "string[]", - "name": "signatures", - "type": "string[]" - }, - { - "indexed": false, - "internalType": "bytes[]", - "name": "calldatas", - "type": "bytes[]" - }, - { - "indexed": false, - "internalType": "bool[]", - "name": "withDelegatecalls", - "type": "bool[]" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "executionTime", - "type": "uint256" - } - ], - "name": "ActionsSetQueued", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldDelay", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newDelay", - "type": "uint256" - } - ], - "name": "DelayUpdate", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldEthereumGovernanceExecutor", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newEthereumGovernanceExecutor", - "type": "address" - } - ], - "name": "EthereumGovernanceExecutorUpdate", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldGracePeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newGracePeriod", - "type": "uint256" - } - ], - "name": "GracePeriodUpdate", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldGuardian", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newGuardian", - "type": "address" - } - ], - "name": "GuardianUpdate", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldMaximumDelay", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newMaximumDelay", - "type": "uint256" - } - ], - "name": "MaximumDelayUpdate", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldMinimumDelay", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newMinimumDelay", - "type": "uint256" - } - ], - "name": "MinimumDelayUpdate", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "actionsSetId", - "type": "uint256" - } - ], - "name": "cancel", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "actionsSetId", - "type": "uint256" - } - ], - "name": "execute", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "executeDelegateCall", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - }, - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "actionsSetId", - "type": "uint256" - } - ], - "name": "getActionsSetById", - "outputs": [ - { - "components": [ - { - "internalType": "address[]", - "name": "targets", - "type": "address[]" - }, - { - "internalType": "uint256[]", - "name": "values", - "type": "uint256[]" - }, - { - "internalType": "string[]", - "name": "signatures", - "type": "string[]" - }, - { - "internalType": "bytes[]", - "name": "calldatas", - "type": "bytes[]" - }, - { - "internalType": "bool[]", - "name": "withDelegatecalls", - "type": "bool[]" - }, - { - "internalType": "uint256", - "name": "executionTime", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "executed", - "type": "bool" - }, - { - "internalType": "bool", - "name": "canceled", - "type": "bool" - } - ], - "internalType": "struct IExecutorBase.ActionsSet", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getActionsSetCount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "actionsSetId", - "type": "uint256" - } - ], - "name": "getCurrentState", - "outputs": [ - { - "internalType": "enum IExecutorBase.ActionsSetState", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getDelay", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getEthereumGovernanceExecutor", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getGracePeriod", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getGuardian", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getMaximumDelay", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getMinimumDelay", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "actionHash", - "type": "bytes32" - } - ], - "name": "isActionQueued", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address[]", - "name": "targets", - "type": "address[]" - }, - { - "internalType": "uint256[]", - "name": "values", - "type": "uint256[]" - }, - { - "internalType": "string[]", - "name": "signatures", - "type": "string[]" - }, - { - "internalType": "bytes[]", - "name": "calldatas", - "type": "bytes[]" - }, - { - "internalType": "bool[]", - "name": "withDelegatecalls", - "type": "bool[]" - } - ], - "name": "queue", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "receiveFunds", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "delay", - "type": "uint256" - } - ], - "name": "updateDelay", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "ethereumGovernanceExecutor", - "type": "address" - } - ], - "name": "updateEthereumGovernanceExecutor", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "gracePeriod", - "type": "uint256" - } - ], - "name": "updateGracePeriod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "guardian", - "type": "address" - } - ], - "name": "updateGuardian", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "maximumDelay", - "type": "uint256" - } - ], - "name": "updateMaximumDelay", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "minimumDelay", - "type": "uint256" - } - ], - "name": "updateMinimumDelay", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "0x60806040523480156200001157600080fd5b50604051620026bb380380620026bb83398101604081905262000034916200027e565b8585858585858484848484610258841080620000505750818310155b806200005b57508285105b806200006657508185115b156200008557604051630a5addd160e21b815260040160405180910390fd5b6200009085620000f4565b6200009b8462000135565b620000a68362000176565b620000b182620001b7565b620000bc81620001f8565b5050600880546001600160a01b0319166001600160a01b039a909a169990991790985550620002db9c50505050505050505050505050565b60005460408051918252602082018390527f43de56b886294fc29767e51a88b5c67fd24aefebc5ddf813b1d9b91b1df38444910160405180910390a1600055565b60015460408051918252602082018390527f9953f3a71052edcd4ae7a0f97302839d1dda32ab93c1039207c91c866b094f72910160405180910390a1600155565b60025460408051918252602082018390527fc534cdcbe9b52100810d787afd57e4174322776fcb58872ea706f23e9319fa8d910160405180910390a1600255565b60035460408051918252602082018390527faf46013422363beb5e6f00ab923cffe3574670494c864de2828b9d7c201fdde5910160405180910390a1600355565b600454604080516001600160a01b03928316815291831660208301527f85bd8788d3c4a160f0f6254229589f137d5633a870dcb46f99ffe07b4da1894b910160405180910390a1600480546001600160a01b0319166001600160a01b0392909216919091179055565b80516001600160a01b03811681146200027957600080fd5b919050565b60008060008060008060c087890312156200029857600080fd5b620002a38762000261565b955060208701519450604087015193506060870151925060808701519150620002cf60a0880162000261565b90509295509295509295565b6123d080620002eb6000396000f3fe6080604052600436106101295760003560e01c8063b3c82e92116100ab578063d9a4cbdf1161006f578063d9a4cbdf1461031e578063dbd183881461033e578063e471b02614610353578063e68a5c3d14610373578063fc52539514610393578063fe0d94c1146103b357600080fd5b8063b3c82e9214610288578063b68df16d146102b5578063c3a76886146102d6578063cebc9a82146102f4578063d89aac391461030957600080fd5b80635ab98d5a116100f25780635ab98d5a146101c157806364d62353146101e15780638533f33714610201578063a75b87d214610216578063b1fc87961461024857600080fd5b80625c33e11461012e57806303c2762114610130578063083a73a21461015457806340e58ee5146101745780635748c13014610194575b600080fd5b005b34801561013c57600080fd5b506002545b6040519081526020015b60405180910390f35b34801561016057600080fd5b5061012e61016f3660046119a8565b6103c6565b34801561018057600080fd5b5061012e61018f3660046119a8565b61041f565b3480156101a057600080fd5b506101b46101af3660046119a8565b6106ca565b60405161014b91906119d7565b3480156101cd57600080fd5b5061012e6101dc3660046119a8565b610760565b3480156101ed57600080fd5b5061012e6101fc3660046119a8565b6107ac565b34801561020d57600080fd5b50600554610141565b34801561022257600080fd5b506004546001600160a01b03165b6040516001600160a01b03909116815260200161014b565b34801561025457600080fd5b506102786102633660046119a8565b60009081526007602052604090205460ff1690565b604051901515815260200161014b565b34801561029457600080fd5b506102a86102a33660046119a8565b6107de565b60405161014b9190611b56565b6102c86102c3366004611c3e565b610b51565b60405161014b929190611cc1565b3480156102e257600080fd5b506008546001600160a01b0316610230565b34801561030057600080fd5b50600054610141565b34801561031557600080fd5b50600354610141565b34801561032a57600080fd5b5061012e610339366004612019565b610be2565b34801561034a57600080fd5b50600154610141565b34801561035f57600080fd5b5061012e61036e3660046119a8565b610c41565b34801561037f57600080fd5b5061012e61038e3660046120eb565b610c8c565b34801561039f57600080fd5b5061012e6103ae3660046120eb565b610d15565b61012e6103c13660046119a8565b610d3e565b3330146103e657604051631dbf5f2360e01b815260040160405180910390fd5b60025481116104085760405163cb2f2b2360e01b815260040160405180910390fd5b61041181611066565b61041c6000546110a7565b50565b6004546001600160a01b0316331461044a576040516377b6878160e11b815260040160405180910390fd5b6000610455826106ca565b6003811115610466576104666119c1565b146104845760405163050ac78b60e11b815260040160405180910390fd5b60008181526006602081905260408220908101805461ff001916610100179055805490915b81811015610699576106918360000182815481106104c9576104c961210d565b6000918252602090912001546001850180546001600160a01b0390921691849081106104f7576104f761210d565b90600052602060002001548560020184815481106105175761051761210d565b90600052602060002001805461052c90612123565b80601f016020809104026020016040519081016040528092919081815260200182805461055890612123565b80156105a55780601f1061057a576101008083540402835291602001916105a5565b820191906000526020600020905b81548152906001019060200180831161058857829003601f168201915b50505050508660030185815481106105bf576105bf61210d565b9060005260206000200180546105d490612123565b80601f016020809104026020016040519081016040528092919081815260200182805461060090612123565b801561064d5780601f106106225761010080835404028352916020019161064d565b820191906000526020600020905b81548152906001019060200180831161063057829003601f168201915b5050505050876005015488600401878154811061066c5761066c61210d565b90600052602060002090602091828204019190069054906101000a900460ff166110ed565b6001016104a9565b5060405183907f0743c673685efcbf3db8591d9e1d98336bc844fe4f4599e6f7efb6d71c02563490600090a2505050565b600081600554116106ee5760405163e5bc0e7b60e01b815260040160405180910390fd5b600082815260066020819052604090912090810154610100900460ff16156107195750600292915050565b600681015460ff161561072f5750600192915050565b60015481600501546107419190612158565b4211156107515750600392915050565b50600092915050565b50919050565b33301461078057604051631dbf5f2360e01b815260040160405180910390fd5b6102588110156107a3576040516301f6f9e560e71b815260040160405180910390fd5b61041c8161113f565b3330146107cc57604051631dbf5f2360e01b815260040160405180910390fd5b6107d5816110a7565b61041c81611180565b61082a6040518061010001604052806060815260200160608152602001606081526020016060815260200160608152602001600081526020016000151581526020016000151581525090565b60008281526006602090815260409182902082518154610120938102820184019094526101008101848152909391928492849184018282801561089657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610878575b50505050508152602001600182018054806020026020016040519081016040528092919081815260200182805480156108ee57602002820191906000526020600020905b8154815260200190600101908083116108da575b5050505050815260200160028201805480602002602001604051908101604052809291908181526020016000905b828210156109c857838290600052602060002001805461093b90612123565b80601f016020809104026020016040519081016040528092919081815260200182805461096790612123565b80156109b45780601f10610989576101008083540402835291602001916109b4565b820191906000526020600020905b81548152906001019060200180831161099757829003601f168201915b50505050508152602001906001019061091c565b50505050815260200160038201805480602002602001604051908101604052809291908181526020016000905b82821015610aa1578382906000526020600020018054610a1490612123565b80601f0160208091040260200160405190810160405280929190818152602001828054610a4090612123565b8015610a8d5780601f10610a6257610100808354040283529160200191610a8d565b820191906000526020600020905b815481529060010190602001808311610a7057829003601f168201915b5050505050815260200190600101906109f5565b50505050815260200160048201805480602002602001604051908101604052809291908181526020018280548015610b1857602002820191906000526020600020906000905b825461010083900a900460ff161515815260206001928301818104948501949093039092029101808411610ae75790505b50505091835250506005820154602082015260069091015460ff8082161515604084015261010090910416151560609091015292915050565b60006060333014610b7557604051631dbf5f2360e01b815260040160405180910390fd5b60006060866001600160a01b03168686604051610b9392919061217e565b600060405180830381855af49150503d8060008114610bce576040519150601f19603f3d011682016040523d82523d6000602084013e610bd3565b606091505b50909890975095505050505050565b6008546001600160a01b03167311110000000000000000000000000000000011101933016001600160a01b031614610c2d576040516359e8359960e01b815260040160405180910390fd5b610c3a85858585856111c1565b5050505050565b333014610c6157604051631dbf5f2360e01b815260040160405180910390fd5b6003548110610c83576040516301b1029b60e61b815260040160405180910390fd5b6104118161142e565b333014610cac57604051631dbf5f2360e01b815260040160405180910390fd5b600854604080516001600160a01b03928316815291831660208301527f01dd0ca50426f21c1b37ce7f3e95eef45b4a55bc5da80a7b67b2c65a7463caf0910160405180910390a1600880546001600160a01b0319166001600160a01b0392909216919091179055565b333014610d3557604051631dbf5f2360e01b815260040160405180910390fd5b61041c8161146f565b6000610d49826106ca565b6003811115610d5a57610d5a6119c1565b14610d785760405163050ac78b60e11b815260040160405180910390fd5b60008181526006602052604090206005810154421015610dab57604051635192dd5560e01b815260040160405180910390fd5b60068101805460ff19166001179055805460008167ffffffffffffffff811115610dd757610dd7611ce4565b604051908082528060200260200182016040528015610e0a57816020015b6060815260200190600190039081610df55790505b50905060005b8281101561101d57610ff8846000018281548110610e3057610e3061210d565b6000918252602090912001546001860180546001600160a01b039092169184908110610e5e57610e5e61210d565b9060005260206000200154866002018481548110610e7e57610e7e61210d565b906000526020600020018054610e9390612123565b80601f0160208091040260200160405190810160405280929190818152602001828054610ebf90612123565b8015610f0c5780601f10610ee157610100808354040283529160200191610f0c565b820191906000526020600020905b815481529060010190602001808311610eef57829003601f168201915b5050505050876003018581548110610f2657610f2661210d565b906000526020600020018054610f3b90612123565b80601f0160208091040260200160405190810160405280929190818152602001828054610f6790612123565b8015610fb45780601f10610f8957610100808354040283529160200191610fb4565b820191906000526020600020905b815481529060010190602001808311610f9757829003601f168201915b50505050508860050154896004018781548110610fd357610fd361210d565b90600052602060002090602091828204019190069054906101000a900460ff166114d8565b82828151811061100a5761100a61210d565b6020908102919091010152600101610e10565b50336001600160a01b0316847ff5efc4bb09a12b6c9561a7e7ab02938a72a4351316b473d574fdaaa89c43eb9a83604051611058919061218e565b60405180910390a350505050565b60035460408051918252602082018390527faf46013422363beb5e6f00ab923cffe3574670494c864de2828b9d7c201fdde5910160405180910390a1600355565b6002548110156110ca576040516361759e6560e01b815260040160405180910390fd5b60035481111561041c576040516386dac63560e01b815260040160405180910390fd5b600086868686868660405160200161110a969594939291906121a1565b60408051601f198184030181529181528151602092830120600090815260079092529020805460ff1916905550505050505050565b60015460408051918252602082018390527f9953f3a71052edcd4ae7a0f97302839d1dda32ab93c1039207c91c866b094f72910160405180910390a1600155565b60005460408051918252602082018390527f43de56b886294fc29767e51a88b5c67fd24aefebc5ddf813b1d9b91b1df38444910160405180910390a1600055565b84516111e057604051636a8e3e9360e11b815260040160405180910390fd5b84518451811415806111f3575083518114155b806111ff575082518114155b8061120b575081518114155b1561122957604051630d10f63b60e01b815260040160405180910390fd5b6005546000805461123a9042612158565b600580546001019055905060005b8381101561135b5760008982815181106112645761126461210d565b602002602001015189838151811061127e5761127e61210d565b60200260200101518984815181106112985761129861210d565b60200260200101518985815181106112b2576112b261210d565b6020026020010151868a87815181106112cd576112cd61210d565b60200260200101516040516020016112ea969594939291906121a1565b60405160208183030381529060405280519060200120905061131b8160009081526007602052604090205460ff1690565b1561133957604051633b2f04e360e21b815260040160405180910390fd5b6000908152600760205260409020805460ff1916600190811790915501611248565b5060008281526006602090815260409091208951909161137f9183918c01906116be565b50875161139590600183019060208b0190611723565b5086516113ab90600283019060208a019061175e565b5085516113c190600383019060208901906117b7565b5084516113d79060048301906020880190611810565b50818160050181905550827f0325966a4aa089b42f4766ec96f599405102bb309e065f24874aff59082dbc8b8a8a8a8a8a8860405161141b969594939291906121f5565b60405180910390a2505050505050505050565b60025460408051918252602082018390527fc534cdcbe9b52100810d787afd57e4174322776fcb58872ea706f23e9319fa8d910160405180910390a1600255565b600454604080516001600160a01b03928316815291831660208301527f85bd8788d3c4a160f0f6254229589f137d5633a870dcb46f99ffe07b4da1894b910160405180910390a1600480546001600160a01b0319166001600160a01b0392909216919091179055565b6060854710156114fb57604051631e9acf1760e31b815260040160405180910390fd5b6000878787878787604051602001611518969594939291906121a1565b60408051601f198184030181529181528151602092830120600081815260079093529120805460ff191690558651909150606090611557575084611583565b86805190602001208660405160200161157192919061229c565b60405160208183030381529060405290505b6000606085156116055760405163b68df16d60e01b8152309063b68df16d908c906115b4908f9088906004016122cd565b60006040518083038185885af11580156115d2573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f191682016040526115fb91908101906122f1565b9092509050611667565b8a6001600160a01b03168a8460405161161e919061237e565b60006040518083038185875af1925050503d806000811461165b576040519150601f19603f3d011682016040523d82523d6000602084013e611660565b606091505b5090925090505b6116718282611680565b9b9a5050505050505050505050565b6060821561168f5750806116b8565b81511561169f5781518083602001fd5b6040516332f63ed360e21b815260040160405180910390fd5b92915050565b828054828255906000526020600020908101928215611713579160200282015b8281111561171357825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906116de565b5061171f9291506118ac565b5090565b828054828255906000526020600020908101928215611713579160200282015b82811115611713578251825591602001919060010190611743565b8280548282559060005260206000209081019282156117ab579160200282015b828111156117ab578251805161179b9184916020909101906118c1565b509160200191906001019061177e565b5061171f929150611934565b828054828255906000526020600020908101928215611804579160200282015b8281111561180457825180516117f49184916020909101906118c1565b50916020019190600101906117d7565b5061171f929150611951565b82805482825590600052602060002090601f016020900481019282156117135791602002820160005b8382111561187657835183826101000a81548160ff0219169083151502179055509260200192600101602081600001049283019260010302611839565b80156118a35782816101000a81549060ff0219169055600101602081600001049283019260010302611876565b505061171f9291505b5b8082111561171f57600081556001016118ad565b8280546118cd90612123565b90600052602060002090601f0160209004810192826118ef5760008555611713565b82601f1061190857805160ff1916838001178555611713565b828001600101855582156117135791820182811115611713578251825591602001919060010190611743565b8082111561171f576000611948828261196e565b50600101611934565b8082111561171f576000611965828261196e565b50600101611951565b50805461197a90612123565b6000825580601f1061198a575050565b601f01602090049060005260206000209081019061041c91906118ac565b6000602082840312156119ba57600080fd5b5035919050565b634e487b7160e01b600052602160045260246000fd5b60208101600483106119f957634e487b7160e01b600052602160045260246000fd5b91905290565b600081518084526020808501945080840160005b83811015611a385781516001600160a01b031687529582019590820190600101611a13565b509495945050505050565b600081518084526020808501945080840160005b83811015611a3857815187529582019590820190600101611a57565b60005b83811015611a8e578181015183820152602001611a76565b83811115611a9d576000848401525b50505050565b60008151808452611abb816020860160208601611a73565b601f01601f19169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b85811015611b17578284038952611b05848351611aa3565b98850198935090840190600101611aed565b5091979650505050505050565b600081518084526020808501945080840160005b83811015611a38578151151587529582019590820190600101611b38565b6020815260008251610100806020850152611b756101208501836119ff565b91506020850151601f1980868503016040870152611b938483611a43565b93506040870151915080868503016060870152611bb08483611acf565b93506060870151915080868503016080870152611bcd8483611acf565b935060808701519150808685030160a087015250611beb8382611b24565b92505060a085015160c085015260c0850151611c0b60e086018215159052565b5060e0850151801515858301525090949350505050565b80356001600160a01b0381168114611c3957600080fd5b919050565b600080600060408486031215611c5357600080fd5b611c5c84611c22565b9250602084013567ffffffffffffffff80821115611c7957600080fd5b818601915086601f830112611c8d57600080fd5b813581811115611c9c57600080fd5b876020828501011115611cae57600080fd5b6020830194508093505050509250925092565b8215158152604060208201526000611cdc6040830184611aa3565b949350505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715611d2357611d23611ce4565b604052919050565b600067ffffffffffffffff821115611d4557611d45611ce4565b5060051b60200190565b600082601f830112611d6057600080fd5b81356020611d75611d7083611d2b565b611cfa565b82815260059290921b84018101918181019086841115611d9457600080fd5b8286015b84811015611db657611da981611c22565b8352918301918301611d98565b509695505050505050565b600082601f830112611dd257600080fd5b81356020611de2611d7083611d2b565b82815260059290921b84018101918181019086841115611e0157600080fd5b8286015b84811015611db65780358352918301918301611e05565b600067ffffffffffffffff821115611e3657611e36611ce4565b50601f01601f191660200190565b6000611e52611d7084611e1c565b9050828152838383011115611e6657600080fd5b828260208301376000602084830101529392505050565b600082601f830112611e8e57600080fd5b81356020611e9e611d7083611d2b565b82815260059290921b84018101918181019086841115611ebd57600080fd5b8286015b84811015611db657803567ffffffffffffffff811115611ee15760008081fd5b8701603f81018913611ef35760008081fd5b611f04898683013560408401611e44565b845250918301918301611ec1565b600082601f830112611f2357600080fd5b81356020611f33611d7083611d2b565b82815260059290921b84018101918181019086841115611f5257600080fd5b8286015b84811015611db657803567ffffffffffffffff811115611f765760008081fd5b8701603f81018913611f885760008081fd5b611f99898683013560408401611e44565b845250918301918301611f56565b801515811461041c57600080fd5b600082601f830112611fc657600080fd5b81356020611fd6611d7083611d2b565b82815260059290921b84018101918181019086841115611ff557600080fd5b8286015b84811015611db657803561200c81611fa7565b8352918301918301611ff9565b600080600080600060a0868803121561203157600080fd5b853567ffffffffffffffff8082111561204957600080fd5b61205589838a01611d4f565b9650602088013591508082111561206b57600080fd5b61207789838a01611dc1565b9550604088013591508082111561208d57600080fd5b61209989838a01611e7d565b945060608801359150808211156120af57600080fd5b6120bb89838a01611f12565b935060808801359150808211156120d157600080fd5b506120de88828901611fb5565b9150509295509295909350565b6000602082840312156120fd57600080fd5b61210682611c22565b9392505050565b634e487b7160e01b600052603260045260246000fd5b600181811c9082168061213757607f821691505b6020821081141561075a57634e487b7160e01b600052602260045260246000fd5b6000821982111561217957634e487b7160e01b600052601160045260246000fd5b500190565b8183823760009101908152919050565b6020815260006121066020830184611acf565b60018060a01b038716815285602082015260c0604082015260006121c860c0830187611aa3565b82810360608401526121da8187611aa3565b6080840195909552505090151560a090910152949350505050565b60c0808252875190820181905260009060209060e0840190828b01845b828110156122375781516001600160a01b031684529284019290840190600101612212565b5050508381038285015261224b818a611a43565b91505082810360408401526122608188611acf565b905082810360608401526122748187611acf565b905082810360808401526122888186611b24565b9150508260a0830152979650505050505050565b6001600160e01b03198316815281516000906122bf816004850160208701611a73565b919091016004019392505050565b6001600160a01b0383168152604060208201819052600090611cdc90830184611aa3565b6000806040838503121561230457600080fd5b825161230f81611fa7565b602084015190925067ffffffffffffffff81111561232c57600080fd5b8301601f8101851361233d57600080fd5b805161234b611d7082611e1c565b81815286602083850101111561236057600080fd5b612371826020830160208601611a73565b8093505050509250929050565b60008251612390818460208701611a73565b919091019291505056fea26469706673582212204d15d998b970c88abcf61ca388d9d45b990eea314f3479db111535845712274d64736f6c634300080a0033", - "deployedBytecode": "0x6080604052600436106101295760003560e01c8063b3c82e92116100ab578063d9a4cbdf1161006f578063d9a4cbdf1461031e578063dbd183881461033e578063e471b02614610353578063e68a5c3d14610373578063fc52539514610393578063fe0d94c1146103b357600080fd5b8063b3c82e9214610288578063b68df16d146102b5578063c3a76886146102d6578063cebc9a82146102f4578063d89aac391461030957600080fd5b80635ab98d5a116100f25780635ab98d5a146101c157806364d62353146101e15780638533f33714610201578063a75b87d214610216578063b1fc87961461024857600080fd5b80625c33e11461012e57806303c2762114610130578063083a73a21461015457806340e58ee5146101745780635748c13014610194575b600080fd5b005b34801561013c57600080fd5b506002545b6040519081526020015b60405180910390f35b34801561016057600080fd5b5061012e61016f3660046119a8565b6103c6565b34801561018057600080fd5b5061012e61018f3660046119a8565b61041f565b3480156101a057600080fd5b506101b46101af3660046119a8565b6106ca565b60405161014b91906119d7565b3480156101cd57600080fd5b5061012e6101dc3660046119a8565b610760565b3480156101ed57600080fd5b5061012e6101fc3660046119a8565b6107ac565b34801561020d57600080fd5b50600554610141565b34801561022257600080fd5b506004546001600160a01b03165b6040516001600160a01b03909116815260200161014b565b34801561025457600080fd5b506102786102633660046119a8565b60009081526007602052604090205460ff1690565b604051901515815260200161014b565b34801561029457600080fd5b506102a86102a33660046119a8565b6107de565b60405161014b9190611b56565b6102c86102c3366004611c3e565b610b51565b60405161014b929190611cc1565b3480156102e257600080fd5b506008546001600160a01b0316610230565b34801561030057600080fd5b50600054610141565b34801561031557600080fd5b50600354610141565b34801561032a57600080fd5b5061012e610339366004612019565b610be2565b34801561034a57600080fd5b50600154610141565b34801561035f57600080fd5b5061012e61036e3660046119a8565b610c41565b34801561037f57600080fd5b5061012e61038e3660046120eb565b610c8c565b34801561039f57600080fd5b5061012e6103ae3660046120eb565b610d15565b61012e6103c13660046119a8565b610d3e565b3330146103e657604051631dbf5f2360e01b815260040160405180910390fd5b60025481116104085760405163cb2f2b2360e01b815260040160405180910390fd5b61041181611066565b61041c6000546110a7565b50565b6004546001600160a01b0316331461044a576040516377b6878160e11b815260040160405180910390fd5b6000610455826106ca565b6003811115610466576104666119c1565b146104845760405163050ac78b60e11b815260040160405180910390fd5b60008181526006602081905260408220908101805461ff001916610100179055805490915b81811015610699576106918360000182815481106104c9576104c961210d565b6000918252602090912001546001850180546001600160a01b0390921691849081106104f7576104f761210d565b90600052602060002001548560020184815481106105175761051761210d565b90600052602060002001805461052c90612123565b80601f016020809104026020016040519081016040528092919081815260200182805461055890612123565b80156105a55780601f1061057a576101008083540402835291602001916105a5565b820191906000526020600020905b81548152906001019060200180831161058857829003601f168201915b50505050508660030185815481106105bf576105bf61210d565b9060005260206000200180546105d490612123565b80601f016020809104026020016040519081016040528092919081815260200182805461060090612123565b801561064d5780601f106106225761010080835404028352916020019161064d565b820191906000526020600020905b81548152906001019060200180831161063057829003601f168201915b5050505050876005015488600401878154811061066c5761066c61210d565b90600052602060002090602091828204019190069054906101000a900460ff166110ed565b6001016104a9565b5060405183907f0743c673685efcbf3db8591d9e1d98336bc844fe4f4599e6f7efb6d71c02563490600090a2505050565b600081600554116106ee5760405163e5bc0e7b60e01b815260040160405180910390fd5b600082815260066020819052604090912090810154610100900460ff16156107195750600292915050565b600681015460ff161561072f5750600192915050565b60015481600501546107419190612158565b4211156107515750600392915050565b50600092915050565b50919050565b33301461078057604051631dbf5f2360e01b815260040160405180910390fd5b6102588110156107a3576040516301f6f9e560e71b815260040160405180910390fd5b61041c8161113f565b3330146107cc57604051631dbf5f2360e01b815260040160405180910390fd5b6107d5816110a7565b61041c81611180565b61082a6040518061010001604052806060815260200160608152602001606081526020016060815260200160608152602001600081526020016000151581526020016000151581525090565b60008281526006602090815260409182902082518154610120938102820184019094526101008101848152909391928492849184018282801561089657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610878575b50505050508152602001600182018054806020026020016040519081016040528092919081815260200182805480156108ee57602002820191906000526020600020905b8154815260200190600101908083116108da575b5050505050815260200160028201805480602002602001604051908101604052809291908181526020016000905b828210156109c857838290600052602060002001805461093b90612123565b80601f016020809104026020016040519081016040528092919081815260200182805461096790612123565b80156109b45780601f10610989576101008083540402835291602001916109b4565b820191906000526020600020905b81548152906001019060200180831161099757829003601f168201915b50505050508152602001906001019061091c565b50505050815260200160038201805480602002602001604051908101604052809291908181526020016000905b82821015610aa1578382906000526020600020018054610a1490612123565b80601f0160208091040260200160405190810160405280929190818152602001828054610a4090612123565b8015610a8d5780601f10610a6257610100808354040283529160200191610a8d565b820191906000526020600020905b815481529060010190602001808311610a7057829003601f168201915b5050505050815260200190600101906109f5565b50505050815260200160048201805480602002602001604051908101604052809291908181526020018280548015610b1857602002820191906000526020600020906000905b825461010083900a900460ff161515815260206001928301818104948501949093039092029101808411610ae75790505b50505091835250506005820154602082015260069091015460ff8082161515604084015261010090910416151560609091015292915050565b60006060333014610b7557604051631dbf5f2360e01b815260040160405180910390fd5b60006060866001600160a01b03168686604051610b9392919061217e565b600060405180830381855af49150503d8060008114610bce576040519150601f19603f3d011682016040523d82523d6000602084013e610bd3565b606091505b50909890975095505050505050565b6008546001600160a01b03167311110000000000000000000000000000000011101933016001600160a01b031614610c2d576040516359e8359960e01b815260040160405180910390fd5b610c3a85858585856111c1565b5050505050565b333014610c6157604051631dbf5f2360e01b815260040160405180910390fd5b6003548110610c83576040516301b1029b60e61b815260040160405180910390fd5b6104118161142e565b333014610cac57604051631dbf5f2360e01b815260040160405180910390fd5b600854604080516001600160a01b03928316815291831660208301527f01dd0ca50426f21c1b37ce7f3e95eef45b4a55bc5da80a7b67b2c65a7463caf0910160405180910390a1600880546001600160a01b0319166001600160a01b0392909216919091179055565b333014610d3557604051631dbf5f2360e01b815260040160405180910390fd5b61041c8161146f565b6000610d49826106ca565b6003811115610d5a57610d5a6119c1565b14610d785760405163050ac78b60e11b815260040160405180910390fd5b60008181526006602052604090206005810154421015610dab57604051635192dd5560e01b815260040160405180910390fd5b60068101805460ff19166001179055805460008167ffffffffffffffff811115610dd757610dd7611ce4565b604051908082528060200260200182016040528015610e0a57816020015b6060815260200190600190039081610df55790505b50905060005b8281101561101d57610ff8846000018281548110610e3057610e3061210d565b6000918252602090912001546001860180546001600160a01b039092169184908110610e5e57610e5e61210d565b9060005260206000200154866002018481548110610e7e57610e7e61210d565b906000526020600020018054610e9390612123565b80601f0160208091040260200160405190810160405280929190818152602001828054610ebf90612123565b8015610f0c5780601f10610ee157610100808354040283529160200191610f0c565b820191906000526020600020905b815481529060010190602001808311610eef57829003601f168201915b5050505050876003018581548110610f2657610f2661210d565b906000526020600020018054610f3b90612123565b80601f0160208091040260200160405190810160405280929190818152602001828054610f6790612123565b8015610fb45780601f10610f8957610100808354040283529160200191610fb4565b820191906000526020600020905b815481529060010190602001808311610f9757829003601f168201915b50505050508860050154896004018781548110610fd357610fd361210d565b90600052602060002090602091828204019190069054906101000a900460ff166114d8565b82828151811061100a5761100a61210d565b6020908102919091010152600101610e10565b50336001600160a01b0316847ff5efc4bb09a12b6c9561a7e7ab02938a72a4351316b473d574fdaaa89c43eb9a83604051611058919061218e565b60405180910390a350505050565b60035460408051918252602082018390527faf46013422363beb5e6f00ab923cffe3574670494c864de2828b9d7c201fdde5910160405180910390a1600355565b6002548110156110ca576040516361759e6560e01b815260040160405180910390fd5b60035481111561041c576040516386dac63560e01b815260040160405180910390fd5b600086868686868660405160200161110a969594939291906121a1565b60408051601f198184030181529181528151602092830120600090815260079092529020805460ff1916905550505050505050565b60015460408051918252602082018390527f9953f3a71052edcd4ae7a0f97302839d1dda32ab93c1039207c91c866b094f72910160405180910390a1600155565b60005460408051918252602082018390527f43de56b886294fc29767e51a88b5c67fd24aefebc5ddf813b1d9b91b1df38444910160405180910390a1600055565b84516111e057604051636a8e3e9360e11b815260040160405180910390fd5b84518451811415806111f3575083518114155b806111ff575082518114155b8061120b575081518114155b1561122957604051630d10f63b60e01b815260040160405180910390fd5b6005546000805461123a9042612158565b600580546001019055905060005b8381101561135b5760008982815181106112645761126461210d565b602002602001015189838151811061127e5761127e61210d565b60200260200101518984815181106112985761129861210d565b60200260200101518985815181106112b2576112b261210d565b6020026020010151868a87815181106112cd576112cd61210d565b60200260200101516040516020016112ea969594939291906121a1565b60405160208183030381529060405280519060200120905061131b8160009081526007602052604090205460ff1690565b1561133957604051633b2f04e360e21b815260040160405180910390fd5b6000908152600760205260409020805460ff1916600190811790915501611248565b5060008281526006602090815260409091208951909161137f9183918c01906116be565b50875161139590600183019060208b0190611723565b5086516113ab90600283019060208a019061175e565b5085516113c190600383019060208901906117b7565b5084516113d79060048301906020880190611810565b50818160050181905550827f0325966a4aa089b42f4766ec96f599405102bb309e065f24874aff59082dbc8b8a8a8a8a8a8860405161141b969594939291906121f5565b60405180910390a2505050505050505050565b60025460408051918252602082018390527fc534cdcbe9b52100810d787afd57e4174322776fcb58872ea706f23e9319fa8d910160405180910390a1600255565b600454604080516001600160a01b03928316815291831660208301527f85bd8788d3c4a160f0f6254229589f137d5633a870dcb46f99ffe07b4da1894b910160405180910390a1600480546001600160a01b0319166001600160a01b0392909216919091179055565b6060854710156114fb57604051631e9acf1760e31b815260040160405180910390fd5b6000878787878787604051602001611518969594939291906121a1565b60408051601f198184030181529181528151602092830120600081815260079093529120805460ff191690558651909150606090611557575084611583565b86805190602001208660405160200161157192919061229c565b60405160208183030381529060405290505b6000606085156116055760405163b68df16d60e01b8152309063b68df16d908c906115b4908f9088906004016122cd565b60006040518083038185885af11580156115d2573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f191682016040526115fb91908101906122f1565b9092509050611667565b8a6001600160a01b03168a8460405161161e919061237e565b60006040518083038185875af1925050503d806000811461165b576040519150601f19603f3d011682016040523d82523d6000602084013e611660565b606091505b5090925090505b6116718282611680565b9b9a5050505050505050505050565b6060821561168f5750806116b8565b81511561169f5781518083602001fd5b6040516332f63ed360e21b815260040160405180910390fd5b92915050565b828054828255906000526020600020908101928215611713579160200282015b8281111561171357825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906116de565b5061171f9291506118ac565b5090565b828054828255906000526020600020908101928215611713579160200282015b82811115611713578251825591602001919060010190611743565b8280548282559060005260206000209081019282156117ab579160200282015b828111156117ab578251805161179b9184916020909101906118c1565b509160200191906001019061177e565b5061171f929150611934565b828054828255906000526020600020908101928215611804579160200282015b8281111561180457825180516117f49184916020909101906118c1565b50916020019190600101906117d7565b5061171f929150611951565b82805482825590600052602060002090601f016020900481019282156117135791602002820160005b8382111561187657835183826101000a81548160ff0219169083151502179055509260200192600101602081600001049283019260010302611839565b80156118a35782816101000a81549060ff0219169055600101602081600001049283019260010302611876565b505061171f9291505b5b8082111561171f57600081556001016118ad565b8280546118cd90612123565b90600052602060002090601f0160209004810192826118ef5760008555611713565b82601f1061190857805160ff1916838001178555611713565b828001600101855582156117135791820182811115611713578251825591602001919060010190611743565b8082111561171f576000611948828261196e565b50600101611934565b8082111561171f576000611965828261196e565b50600101611951565b50805461197a90612123565b6000825580601f1061198a575050565b601f01602090049060005260206000209081019061041c91906118ac565b6000602082840312156119ba57600080fd5b5035919050565b634e487b7160e01b600052602160045260246000fd5b60208101600483106119f957634e487b7160e01b600052602160045260246000fd5b91905290565b600081518084526020808501945080840160005b83811015611a385781516001600160a01b031687529582019590820190600101611a13565b509495945050505050565b600081518084526020808501945080840160005b83811015611a3857815187529582019590820190600101611a57565b60005b83811015611a8e578181015183820152602001611a76565b83811115611a9d576000848401525b50505050565b60008151808452611abb816020860160208601611a73565b601f01601f19169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b85811015611b17578284038952611b05848351611aa3565b98850198935090840190600101611aed565b5091979650505050505050565b600081518084526020808501945080840160005b83811015611a38578151151587529582019590820190600101611b38565b6020815260008251610100806020850152611b756101208501836119ff565b91506020850151601f1980868503016040870152611b938483611a43565b93506040870151915080868503016060870152611bb08483611acf565b93506060870151915080868503016080870152611bcd8483611acf565b935060808701519150808685030160a087015250611beb8382611b24565b92505060a085015160c085015260c0850151611c0b60e086018215159052565b5060e0850151801515858301525090949350505050565b80356001600160a01b0381168114611c3957600080fd5b919050565b600080600060408486031215611c5357600080fd5b611c5c84611c22565b9250602084013567ffffffffffffffff80821115611c7957600080fd5b818601915086601f830112611c8d57600080fd5b813581811115611c9c57600080fd5b876020828501011115611cae57600080fd5b6020830194508093505050509250925092565b8215158152604060208201526000611cdc6040830184611aa3565b949350505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715611d2357611d23611ce4565b604052919050565b600067ffffffffffffffff821115611d4557611d45611ce4565b5060051b60200190565b600082601f830112611d6057600080fd5b81356020611d75611d7083611d2b565b611cfa565b82815260059290921b84018101918181019086841115611d9457600080fd5b8286015b84811015611db657611da981611c22565b8352918301918301611d98565b509695505050505050565b600082601f830112611dd257600080fd5b81356020611de2611d7083611d2b565b82815260059290921b84018101918181019086841115611e0157600080fd5b8286015b84811015611db65780358352918301918301611e05565b600067ffffffffffffffff821115611e3657611e36611ce4565b50601f01601f191660200190565b6000611e52611d7084611e1c565b9050828152838383011115611e6657600080fd5b828260208301376000602084830101529392505050565b600082601f830112611e8e57600080fd5b81356020611e9e611d7083611d2b565b82815260059290921b84018101918181019086841115611ebd57600080fd5b8286015b84811015611db657803567ffffffffffffffff811115611ee15760008081fd5b8701603f81018913611ef35760008081fd5b611f04898683013560408401611e44565b845250918301918301611ec1565b600082601f830112611f2357600080fd5b81356020611f33611d7083611d2b565b82815260059290921b84018101918181019086841115611f5257600080fd5b8286015b84811015611db657803567ffffffffffffffff811115611f765760008081fd5b8701603f81018913611f885760008081fd5b611f99898683013560408401611e44565b845250918301918301611f56565b801515811461041c57600080fd5b600082601f830112611fc657600080fd5b81356020611fd6611d7083611d2b565b82815260059290921b84018101918181019086841115611ff557600080fd5b8286015b84811015611db657803561200c81611fa7565b8352918301918301611ff9565b600080600080600060a0868803121561203157600080fd5b853567ffffffffffffffff8082111561204957600080fd5b61205589838a01611d4f565b9650602088013591508082111561206b57600080fd5b61207789838a01611dc1565b9550604088013591508082111561208d57600080fd5b61209989838a01611e7d565b945060608801359150808211156120af57600080fd5b6120bb89838a01611f12565b935060808801359150808211156120d157600080fd5b506120de88828901611fb5565b9150509295509295909350565b6000602082840312156120fd57600080fd5b61210682611c22565b9392505050565b634e487b7160e01b600052603260045260246000fd5b600181811c9082168061213757607f821691505b6020821081141561075a57634e487b7160e01b600052602260045260246000fd5b6000821982111561217957634e487b7160e01b600052601160045260246000fd5b500190565b8183823760009101908152919050565b6020815260006121066020830184611acf565b60018060a01b038716815285602082015260c0604082015260006121c860c0830187611aa3565b82810360608401526121da8187611aa3565b6080840195909552505090151560a090910152949350505050565b60c0808252875190820181905260009060209060e0840190828b01845b828110156122375781516001600160a01b031684529284019290840190600101612212565b5050508381038285015261224b818a611a43565b91505082810360408401526122608188611acf565b905082810360608401526122748187611acf565b905082810360808401526122888186611b24565b9150508260a0830152979650505050505050565b6001600160e01b03198316815281516000906122bf816004850160208701611a73565b919091016004019392505050565b6001600160a01b0383168152604060208201819052600090611cdc90830184611aa3565b6000806040838503121561230457600080fd5b825161230f81611fa7565b602084015190925067ffffffffffffffff81111561232c57600080fd5b8301601f8101851361233d57600080fd5b805161234b611d7082611e1c565b81815286602083850101111561236057600080fd5b612371826020830160208601611a73565b8093505050509250929050565b60008251612390818460208701611a73565b919091019291505056fea26469706673582212204d15d998b970c88abcf61ca388d9d45b990eea314f3479db111535845712274d64736f6c634300080a0033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/utils/arbitrum/artifacts/L1GatewayRouter.json b/utils/arbitrum/artifacts/L1GatewayRouter.json deleted file mode 100644 index 45af03c2..00000000 --- a/utils/arbitrum/artifacts/L1GatewayRouter.json +++ /dev/null @@ -1,582 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "L1GatewayRouter", - "sourceName": "contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol", - "abi": [ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newDefaultGateway", - "type": "address" - } - ], - "name": "DefaultGatewayUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "l1Token", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "gateway", - "type": "address" - } - ], - "name": "GatewaySet", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "_userFrom", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "_userTo", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "gateway", - "type": "address" - } - ], - "name": "TransferRouted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "_from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "_to", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "_seqNum", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "name": "TxToL2", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newSource", - "type": "address" - } - ], - "name": "WhitelistSourceUpdated", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "l1ERC20", - "type": "address" - } - ], - "name": "calculateL2TokenAddress", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "counterpartGateway", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "defaultGateway", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "name": "finalizeInboundTransfer", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_token", - "type": "address" - } - ], - "name": "getGateway", - "outputs": [ - { - "internalType": "address", - "name": "gateway", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_token", - "type": "address" - }, - { - "internalType": "address", - "name": "_from", - "type": "address" - }, - { - "internalType": "address", - "name": "_to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "name": "getOutboundCalldata", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "inbox", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_owner", - "type": "address" - }, - { - "internalType": "address", - "name": "_defaultGateway", - "type": "address" - }, - { - "internalType": "address", - "name": "_whitelist", - "type": "address" - }, - { - "internalType": "address", - "name": "_counterpartGateway", - "type": "address" - }, - { - "internalType": "address", - "name": "_inbox", - "type": "address" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "l1TokenToGateway", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_token", - "type": "address" - }, - { - "internalType": "address", - "name": "_to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_maxGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_gasPriceBid", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "name": "outboundTransfer", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "postUpgradeInit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "router", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newL1DefaultGateway", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_maxGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_gasPriceBid", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_maxSubmissionCost", - "type": "uint256" - } - ], - "name": "setDefaultGateway", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_gateway", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_maxGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_gasPriceBid", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_maxSubmissionCost", - "type": "uint256" - }, - { - "internalType": "address", - "name": "_creditBackAddress", - "type": "address" - } - ], - "name": "setGateway", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_gateway", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_maxGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_gasPriceBid", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_maxSubmissionCost", - "type": "uint256" - } - ], - "name": "setGateway", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address[]", - "name": "_token", - "type": "address[]" - }, - { - "internalType": "address[]", - "name": "_gateway", - "type": "address[]" - }, - { - "internalType": "uint256", - "name": "_maxGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_gasPriceBid", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_maxSubmissionCost", - "type": "uint256" - } - ], - "name": "setGateways", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "setOwner", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newSource", - "type": "address" - } - ], - "name": "updateWhitelistSource", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "whitelist", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - } - ], - "bytecode": "0x608060405234801561001057600080fd5b50611f1d806100206000396000f3fe60806040526004361061011f5760003560e01c806393e59dc1116100a0578063d2ce7d6511610064578063d2ce7d651461066a578063dd61456914610704578063ed08fdc61461073c578063f887ea401461076f578063fb0e722b146107845761011f565b806393e59dc11461048c57806395fcea78146104a1578063a0c76a96146104b6578063a7e28d4814610604578063bda009fe146106375761011f565b80632e567b36116100e75780632e567b361461024857806347466f98146102de5780635625a95214610311578063658b53f4146103495780638da5cb5b146104775761011f565b8063032958021461012457806313af4035146101555780631459457a1461018a5780632d67b72d146101df5780632db09c1c14610233575b600080fd5b34801561013057600080fd5b50610139610799565b604080516001600160a01b039092168252519081900360200190f35b34801561016157600080fd5b506101886004803603602081101561017857600080fd5b50356001600160a01b03166107a8565b005b34801561019657600080fd5b50610188600480360360a08110156101ad57600080fd5b506001600160a01b03813581169160208101358216916040820135811691606081013582169160809091013516610861565b610221600480360360a08110156101f557600080fd5b506001600160a01b038135811691602081013591604082013591606081013591608090910135166108af565b60408051918252519081900360200190f35b34801561023f57600080fd5b50610139610b0c565b610188600480360360a081101561025e57600080fd5b6001600160a01b03823581169260208101358216926040820135909216916060820135919081019060a081016080820135600160201b8111156102a057600080fd5b8201836020820111156102b257600080fd5b803590602001918460018302840111600160201b831117156102d357600080fd5b509092509050610b1b565b3480156102ea57600080fd5b506101886004803603602081101561030157600080fd5b50356001600160a01b0316610b5f565b6102216004803603608081101561032757600080fd5b506001600160a01b038135169060208101359060408101359060600135610c02565b610221600480360360a081101561035f57600080fd5b810190602081018135600160201b81111561037957600080fd5b82018360208201111561038b57600080fd5b803590602001918460208302840111600160201b831117156103ac57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b8111156103fb57600080fd5b82018360208201111561040d57600080fd5b803590602001918460208302840111600160201b8311171561042e57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505082359350505060208101359060400135610d9f565b34801561048357600080fd5b50610139610e06565b34801561049857600080fd5b50610139610e15565b3480156104ad57600080fd5b50610188610e24565b3480156104c257600080fd5b5061058f600480360360a08110156104d957600080fd5b6001600160a01b03823581169260208101358216926040820135909216916060820135919081019060a081016080820135600160201b81111561051b57600080fd5b82018360208201111561052d57600080fd5b803590602001918460018302840111600160201b8311171561054e57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610e81945050505050565b6040805160208082528351818301528351919283929083019185019080838360005b838110156105c95781810151838201526020016105b1565b50505050905090810190601f1680156105f65780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561061057600080fd5b506101396004803603602081101561062757600080fd5b50356001600160a01b0316611083565b34801561064357600080fd5b506101396004803603602081101561065a57600080fd5b50356001600160a01b0316611134565b61058f600480360360c081101561068057600080fd5b6001600160a01b0382358116926020810135909116916040820135916060810135916080820135919081019060c0810160a0820135600160201b8111156106c657600080fd5b8201836020820111156106d857600080fd5b803590602001918460018302840111600160201b831117156106f957600080fd5b509092509050611196565b6102216004803603608081101561071a57600080fd5b506001600160a01b0381351690602081013590604081013590606001356113ba565b34801561074857600080fd5b506101396004803603602081101561075f57600080fd5b50356001600160a01b03166113d2565b34801561077b57600080fd5b506101396113ed565b34801561079057600080fd5b506101396113fc565b6004546001600160a01b031681565b6005546001600160a01b031633146107f4576040805162461bcd60e51b815260206004820152600a60248201526927a7262cafa7aba722a960b11b604482015290519081900360640190fd5b6001600160a01b03811661083f576040805162461bcd60e51b815260206004820152600d60248201526c24a72b20a624a22fa7aba722a960991b604482015290519081900360640190fd5b600580546001600160a01b0319166001600160a01b0392909216919091179055565b61086d8260008661140b565b600580546001600160a01b03199081166001600160a01b0397881617909155600080548216948716949094179093556006805490931694169390931790555050565b600061a4b160ff16336001600160a01b0316638e5f5ad16040518163ffffffff1660e01b815260040160206040518083038186803b1580156108f057600080fd5b505afa158015610904573d6000803e3d6000fd5b505050506040513d602081101561091a57600080fd5b505160ff1614610963576040805162461bcd60e51b815260206004820152600f60248201526e1393d517d0549097d1539050931151608a1b604482015290519081900360640190fd5b610975866001600160a01b0316611482565b6109b8576040805162461bcd60e51b815260206004820152600f60248201526e1393d517d513d7d0d3d395149050d5608a1b604482015290519081900360640190fd5b60006109c333611134565b90506001600160a01b038116158015906109eb57506004546001600160a01b03828116911614155b15610a5657866001600160a01b0316816001600160a01b031614610a56576040805162461bcd60e51b815260206004820152601b60248201527f4e4f5f5550444154455f544f5f444946464552454e545f414444520000000000604482015290519081900360640190fd5b604080516001808252818301909252606091602080830190803683370190505090503381600081518110610a8657fe5b6001600160a01b0392909216602092830291909101909101526040805160018082528183019092526060918160200160208202803683370190505090508881600081518110610ad157fe5b60200260200101906001600160a01b031690816001600160a01b031681525050610aff82828a8a8a8a611488565b9998505050505050505050565b6001546001600160a01b031681565b6040805162461bcd60e51b815260206004820152601460248201527327a7262cafa7aaaa2127aaa7222fa927aaaa22a960611b604482015290519081900360640190fd5b6000546001600160a01b03163314610bae576040805162461bcd60e51b815260206004820152600d60248201526c1393d517d19493d357d31254d5609a1b604482015290519081900360640190fd5b600080546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f37389c47920d5cc3229678a0205d0455002c07541a4139ebdce91ac2274657779181900360200190a150565b6005546000906001600160a01b03163314610c51576040805162461bcd60e51b815260206004820152600a60248201526927a7262cafa7aba722a960b11b604482015290519081900360640190fd5b600480546001600160a01b0387166001600160a01b0319909116811790915560408051918252517f3a8f8eb961383a94d41d193e16a3af73eaddfd5764a4c640257323a1603ac3319181900360200190a160006001600160a01b03861615610d1b57856001600160a01b0316632db09c1c6040518163ffffffff1660e01b815260040160206040518083038186803b158015610cec57600080fd5b505afa158015610d00573d6000803e3d6000fd5b505050506040513d6020811015610d1657600080fd5b505190505b604080516001600160a01b038084166024808401919091528351808403909101815260449092018352602082810180516001600160e01b031663f7c9362f60e01b17905260065460015485516060810187528981529283018b90529482018990529293610d949383169216903390349060009087611905565b979650505050505050565b6005546000906001600160a01b03163314610dee576040805162461bcd60e51b815260206004820152600a60248201526927a7262cafa7aba722a960b11b604482015290519081900360640190fd5b610dfc868686868633611488565b9695505050505050565b6005546001600160a01b031681565b6000546001600160a01b031681565b6000610e2e611924565b9050336001600160a01b03821614610e7e576040805162461bcd60e51b815260206004820152600e60248201526d2727aa2fa32927a6afa0a226a4a760911b604482015290519081900360640190fd5b50565b60606000610e8e87611134565b9050806001600160a01b031663a0c76a9688888888886040518663ffffffff1660e01b815260040180866001600160a01b03166001600160a01b03168152602001856001600160a01b03166001600160a01b03168152602001846001600160a01b03166001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610f3e578181015183820152602001610f26565b50505050905090810190601f168015610f6b5780820380516001836020036101000a031916815260200191505b50965050505050505060006040518083038186803b158015610f8c57600080fd5b505afa158015610fa0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015610fc957600080fd5b8101908080516040519392919084600160201b821115610fe857600080fd5b908301906020820185811115610ffd57600080fd5b8251600160201b81118282018810171561101657600080fd5b82525081516020918201929091019080838360005b8381101561104357818101518382015260200161102b565b50505050905090810190601f1680156110705780820380516001836020036101000a031916815260200191505b5060405250505091505095945050505050565b60008061108f83611134565b90506001600160a01b0381166110a957600091505061112f565b806001600160a01b031663a7e28d48846040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156110ff57600080fd5b505afa158015611113573d6000803e3d6000fd5b505050506040513d602081101561112957600080fd5b50519150505b919050565b6001600160a01b03808216600090815260036020526040902054168061116257506004546001600160a01b03165b6001600160a01b038116600114806111895750611187816001600160a01b0316611482565b155b1561112f5750600061112f565b6000546060906001600160a01b031615611264576000546040805163babcc53960e01b815233600482015290516001600160a01b039092169163babcc53991602480820192602092909190829003018186803b1580156111f557600080fd5b505afa158015611209573d6000803e3d6000fd5b505050506040513d602081101561121f57600080fd5b5051611264576040805162461bcd60e51b815260206004820152600f60248201526e1393d517d5d2125511531254d51151608a1b604482015290519081900360640190fd5b60008383604081101561127657600080fd5b81359190810190604081016020820135600160201b81111561129757600080fd5b8201836020820111156112a957600080fd5b803590602001918460018302840111600160201b831117156112ca57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509697505050508989028501935050508215159050611357576040805162461bcd60e51b81526020600482015260126024820152711393d7d4d550935254d4d253d397d0d3d4d560721b604482015290519081900360640190fd5b80341461139d576040805162461bcd60e51b815260206004820152600f60248201526e57524f4e475f4554485f56414c554560881b604482015290519081900360640190fd5b6113ac8a8a8a8a8a8a8a611949565b9a9950505050505050505050565b60006113c985858585336108af565b95945050505050565b6003602052600090815260409020546001600160a01b031681565b6002546001600160a01b031681565b6006546001600160a01b031681565b6001600160a01b03821615611454576040805162461bcd60e51b815260206004820152600a6024820152692120a22fa927aaaa22a960b11b604482015290519081900360640190fd5b61145e8383611b9e565b600480546001600160a01b0319166001600160a01b03929092169190911790555050565b3b151590565b600085518751146114cf576040805162461bcd60e51b815260206004820152600c60248201526b0aea49e9c8ebe988a9c8ea8960a31b604482015290519081900360640190fd5b60005b87518110156117d0578681815181106114e757fe5b6020026020010151600360008a84815181106114ff57fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555086818151811061155757fe5b60200260200101516001600160a01b031688828151811061157457fe5b60200260200101516001600160a01b03167f812ca95fe4492a9e2d1f2723c2c40c03a60a27b059581ae20ac4e4d73bfba35460405160405180910390a360006001600160a01b03168782815181106115c857fe5b60200260200101516001600160a01b03161415801561160d575060016001600160a01b03168782815181106115f957fe5b60200260200101516001600160a01b031614155b156117c85760006001600160a01b031687828151811061162957fe5b60200260200101516001600160a01b031663a7e28d488a848151811061164b57fe5b60200260200101516040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561169957600080fd5b505afa1580156116ad573d6000803e3d6000fd5b505050506040513d60208110156116c357600080fd5b50516001600160a01b03161415611721576040805162461bcd60e51b815260206004820152601c60248201527f544f4b454e5f4e4f545f48414e444c45445f42595f4741544557415900000000604482015290519081900360640190fd5b86818151811061172d57fe5b60200260200101516001600160a01b0316632db09c1c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561176d57600080fd5b505afa158015611781573d6000803e3d6000fd5b505050506040513d602081101561179757600080fd5b505187518890839081106117a757fe5b60200260200101906001600160a01b031690816001600160a01b0316815250505b6001016114d2565b506060634201f98560e01b8888604051602401808060200180602001838103835285818151815260200191508051906020019060200280838360005b8381101561182457818101518382015260200161180c565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561186357818101518382015260200161184b565b50505050905001945050505050604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505090506118f9600660009054906101000a90046001600160a01b0316600160009054906101000a90046001600160a01b03168534600060405180606001604052808b81526020018d81526020018c81525087611905565b98975050505050505050565b60006118f98888888888886000015189602001518a604001518a611c6a565b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b6060600061195689611134565b90506060611965338686611e7d565b604080516001600160a01b0385811682529151929350818c169233928e16917f85291dff2161a93c2f12c819d31889c96c63042116f5bc5a205aa701c2c429f5919081900360200190a4816001600160a01b031663d2ce7d65348c8c8c8c8c886040518863ffffffff1660e01b815260040180876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b0316815260200185815260200184815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611a53578181015183820152602001611a3b565b50505050905090810190601f168015611a805780820380516001836020036101000a031916815260200191505b509750505050505050506000604051808303818588803b158015611aa357600080fd5b505af1158015611ab7573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f191682016040526020811015611ae157600080fd5b8101908080516040519392919084600160201b821115611b0057600080fd5b908301906020820185811115611b1557600080fd5b8251600160201b811182820188101715611b2e57600080fd5b82525081516020918201929091019080838360005b83811015611b5b578181015183820152602001611b43565b50505050905090810190601f168015611b885780820380516001836020036101000a031916815260200191505b5060405250505092505050979650505050505050565b6001600160a01b038216611bef576040805162461bcd60e51b81526020600482015260136024820152721253959053125117d0d3d55395115494105495606a1b604482015290519081900360640190fd5b6001546001600160a01b031615611c3c576040805162461bcd60e51b815260206004820152600c60248201526b1053149150511657d253925560a21b604482015290519081900360640190fd5b600180546001600160a01b039384166001600160a01b03199182161790915560028054929093169116179055565b6000808a6001600160a01b031663679b6ded898c8a8a8e8f8c8c8c6040518a63ffffffff1660e01b815260040180896001600160a01b03166001600160a01b03168152602001888152602001878152602001866001600160a01b03166001600160a01b03168152602001856001600160a01b03166001600160a01b0316815260200184815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611d31578181015183820152602001611d19565b50505050905090810190601f168015611d5e5780820380516001836020036101000a031916815260200191505b5099505050505050505050506020604051808303818588803b158015611d8357600080fd5b505af1158015611d97573d6000803e3d6000fd5b50505050506040513d6020811015611dae57600080fd5b81019080805190602001909291905050509050808a6001600160a01b03168a6001600160a01b03167fc1d1490cf25c3b40d600dfb27c7680340ed1ab901b7e8f3551280968a3b372b0866040518080602001828103825283818151815260200191508051906020019080838360005b83811015611e35578181015183820152602001611e1d565b50505050905090810190601f168015611e625780820380516001836020036101000a031916815260200191505b509250505060405180910390a49a9950505050505050505050565b606083838360405160200180846001600160a01b03166001600160a01b0316815260200180602001828103825284848281815260200192508082843760008184015260408051601f19601f909301831690940184810390920184525250999850505050505050505056fea2646970667358221220d7743bc55082d15fef9972e04a86235c42530952c92b25d83792f50a8a6830f564736f6c634300060b0033", - "deployedBytecode": "0x60806040526004361061011f5760003560e01c806393e59dc1116100a0578063d2ce7d6511610064578063d2ce7d651461066a578063dd61456914610704578063ed08fdc61461073c578063f887ea401461076f578063fb0e722b146107845761011f565b806393e59dc11461048c57806395fcea78146104a1578063a0c76a96146104b6578063a7e28d4814610604578063bda009fe146106375761011f565b80632e567b36116100e75780632e567b361461024857806347466f98146102de5780635625a95214610311578063658b53f4146103495780638da5cb5b146104775761011f565b8063032958021461012457806313af4035146101555780631459457a1461018a5780632d67b72d146101df5780632db09c1c14610233575b600080fd5b34801561013057600080fd5b50610139610799565b604080516001600160a01b039092168252519081900360200190f35b34801561016157600080fd5b506101886004803603602081101561017857600080fd5b50356001600160a01b03166107a8565b005b34801561019657600080fd5b50610188600480360360a08110156101ad57600080fd5b506001600160a01b03813581169160208101358216916040820135811691606081013582169160809091013516610861565b610221600480360360a08110156101f557600080fd5b506001600160a01b038135811691602081013591604082013591606081013591608090910135166108af565b60408051918252519081900360200190f35b34801561023f57600080fd5b50610139610b0c565b610188600480360360a081101561025e57600080fd5b6001600160a01b03823581169260208101358216926040820135909216916060820135919081019060a081016080820135600160201b8111156102a057600080fd5b8201836020820111156102b257600080fd5b803590602001918460018302840111600160201b831117156102d357600080fd5b509092509050610b1b565b3480156102ea57600080fd5b506101886004803603602081101561030157600080fd5b50356001600160a01b0316610b5f565b6102216004803603608081101561032757600080fd5b506001600160a01b038135169060208101359060408101359060600135610c02565b610221600480360360a081101561035f57600080fd5b810190602081018135600160201b81111561037957600080fd5b82018360208201111561038b57600080fd5b803590602001918460208302840111600160201b831117156103ac57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b8111156103fb57600080fd5b82018360208201111561040d57600080fd5b803590602001918460208302840111600160201b8311171561042e57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505082359350505060208101359060400135610d9f565b34801561048357600080fd5b50610139610e06565b34801561049857600080fd5b50610139610e15565b3480156104ad57600080fd5b50610188610e24565b3480156104c257600080fd5b5061058f600480360360a08110156104d957600080fd5b6001600160a01b03823581169260208101358216926040820135909216916060820135919081019060a081016080820135600160201b81111561051b57600080fd5b82018360208201111561052d57600080fd5b803590602001918460018302840111600160201b8311171561054e57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610e81945050505050565b6040805160208082528351818301528351919283929083019185019080838360005b838110156105c95781810151838201526020016105b1565b50505050905090810190601f1680156105f65780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561061057600080fd5b506101396004803603602081101561062757600080fd5b50356001600160a01b0316611083565b34801561064357600080fd5b506101396004803603602081101561065a57600080fd5b50356001600160a01b0316611134565b61058f600480360360c081101561068057600080fd5b6001600160a01b0382358116926020810135909116916040820135916060810135916080820135919081019060c0810160a0820135600160201b8111156106c657600080fd5b8201836020820111156106d857600080fd5b803590602001918460018302840111600160201b831117156106f957600080fd5b509092509050611196565b6102216004803603608081101561071a57600080fd5b506001600160a01b0381351690602081013590604081013590606001356113ba565b34801561074857600080fd5b506101396004803603602081101561075f57600080fd5b50356001600160a01b03166113d2565b34801561077b57600080fd5b506101396113ed565b34801561079057600080fd5b506101396113fc565b6004546001600160a01b031681565b6005546001600160a01b031633146107f4576040805162461bcd60e51b815260206004820152600a60248201526927a7262cafa7aba722a960b11b604482015290519081900360640190fd5b6001600160a01b03811661083f576040805162461bcd60e51b815260206004820152600d60248201526c24a72b20a624a22fa7aba722a960991b604482015290519081900360640190fd5b600580546001600160a01b0319166001600160a01b0392909216919091179055565b61086d8260008661140b565b600580546001600160a01b03199081166001600160a01b0397881617909155600080548216948716949094179093556006805490931694169390931790555050565b600061a4b160ff16336001600160a01b0316638e5f5ad16040518163ffffffff1660e01b815260040160206040518083038186803b1580156108f057600080fd5b505afa158015610904573d6000803e3d6000fd5b505050506040513d602081101561091a57600080fd5b505160ff1614610963576040805162461bcd60e51b815260206004820152600f60248201526e1393d517d0549097d1539050931151608a1b604482015290519081900360640190fd5b610975866001600160a01b0316611482565b6109b8576040805162461bcd60e51b815260206004820152600f60248201526e1393d517d513d7d0d3d395149050d5608a1b604482015290519081900360640190fd5b60006109c333611134565b90506001600160a01b038116158015906109eb57506004546001600160a01b03828116911614155b15610a5657866001600160a01b0316816001600160a01b031614610a56576040805162461bcd60e51b815260206004820152601b60248201527f4e4f5f5550444154455f544f5f444946464552454e545f414444520000000000604482015290519081900360640190fd5b604080516001808252818301909252606091602080830190803683370190505090503381600081518110610a8657fe5b6001600160a01b0392909216602092830291909101909101526040805160018082528183019092526060918160200160208202803683370190505090508881600081518110610ad157fe5b60200260200101906001600160a01b031690816001600160a01b031681525050610aff82828a8a8a8a611488565b9998505050505050505050565b6001546001600160a01b031681565b6040805162461bcd60e51b815260206004820152601460248201527327a7262cafa7aaaa2127aaa7222fa927aaaa22a960611b604482015290519081900360640190fd5b6000546001600160a01b03163314610bae576040805162461bcd60e51b815260206004820152600d60248201526c1393d517d19493d357d31254d5609a1b604482015290519081900360640190fd5b600080546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f37389c47920d5cc3229678a0205d0455002c07541a4139ebdce91ac2274657779181900360200190a150565b6005546000906001600160a01b03163314610c51576040805162461bcd60e51b815260206004820152600a60248201526927a7262cafa7aba722a960b11b604482015290519081900360640190fd5b600480546001600160a01b0387166001600160a01b0319909116811790915560408051918252517f3a8f8eb961383a94d41d193e16a3af73eaddfd5764a4c640257323a1603ac3319181900360200190a160006001600160a01b03861615610d1b57856001600160a01b0316632db09c1c6040518163ffffffff1660e01b815260040160206040518083038186803b158015610cec57600080fd5b505afa158015610d00573d6000803e3d6000fd5b505050506040513d6020811015610d1657600080fd5b505190505b604080516001600160a01b038084166024808401919091528351808403909101815260449092018352602082810180516001600160e01b031663f7c9362f60e01b17905260065460015485516060810187528981529283018b90529482018990529293610d949383169216903390349060009087611905565b979650505050505050565b6005546000906001600160a01b03163314610dee576040805162461bcd60e51b815260206004820152600a60248201526927a7262cafa7aba722a960b11b604482015290519081900360640190fd5b610dfc868686868633611488565b9695505050505050565b6005546001600160a01b031681565b6000546001600160a01b031681565b6000610e2e611924565b9050336001600160a01b03821614610e7e576040805162461bcd60e51b815260206004820152600e60248201526d2727aa2fa32927a6afa0a226a4a760911b604482015290519081900360640190fd5b50565b60606000610e8e87611134565b9050806001600160a01b031663a0c76a9688888888886040518663ffffffff1660e01b815260040180866001600160a01b03166001600160a01b03168152602001856001600160a01b03166001600160a01b03168152602001846001600160a01b03166001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610f3e578181015183820152602001610f26565b50505050905090810190601f168015610f6b5780820380516001836020036101000a031916815260200191505b50965050505050505060006040518083038186803b158015610f8c57600080fd5b505afa158015610fa0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015610fc957600080fd5b8101908080516040519392919084600160201b821115610fe857600080fd5b908301906020820185811115610ffd57600080fd5b8251600160201b81118282018810171561101657600080fd5b82525081516020918201929091019080838360005b8381101561104357818101518382015260200161102b565b50505050905090810190601f1680156110705780820380516001836020036101000a031916815260200191505b5060405250505091505095945050505050565b60008061108f83611134565b90506001600160a01b0381166110a957600091505061112f565b806001600160a01b031663a7e28d48846040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156110ff57600080fd5b505afa158015611113573d6000803e3d6000fd5b505050506040513d602081101561112957600080fd5b50519150505b919050565b6001600160a01b03808216600090815260036020526040902054168061116257506004546001600160a01b03165b6001600160a01b038116600114806111895750611187816001600160a01b0316611482565b155b1561112f5750600061112f565b6000546060906001600160a01b031615611264576000546040805163babcc53960e01b815233600482015290516001600160a01b039092169163babcc53991602480820192602092909190829003018186803b1580156111f557600080fd5b505afa158015611209573d6000803e3d6000fd5b505050506040513d602081101561121f57600080fd5b5051611264576040805162461bcd60e51b815260206004820152600f60248201526e1393d517d5d2125511531254d51151608a1b604482015290519081900360640190fd5b60008383604081101561127657600080fd5b81359190810190604081016020820135600160201b81111561129757600080fd5b8201836020820111156112a957600080fd5b803590602001918460018302840111600160201b831117156112ca57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509697505050508989028501935050508215159050611357576040805162461bcd60e51b81526020600482015260126024820152711393d7d4d550935254d4d253d397d0d3d4d560721b604482015290519081900360640190fd5b80341461139d576040805162461bcd60e51b815260206004820152600f60248201526e57524f4e475f4554485f56414c554560881b604482015290519081900360640190fd5b6113ac8a8a8a8a8a8a8a611949565b9a9950505050505050505050565b60006113c985858585336108af565b95945050505050565b6003602052600090815260409020546001600160a01b031681565b6002546001600160a01b031681565b6006546001600160a01b031681565b6001600160a01b03821615611454576040805162461bcd60e51b815260206004820152600a6024820152692120a22fa927aaaa22a960b11b604482015290519081900360640190fd5b61145e8383611b9e565b600480546001600160a01b0319166001600160a01b03929092169190911790555050565b3b151590565b600085518751146114cf576040805162461bcd60e51b815260206004820152600c60248201526b0aea49e9c8ebe988a9c8ea8960a31b604482015290519081900360640190fd5b60005b87518110156117d0578681815181106114e757fe5b6020026020010151600360008a84815181106114ff57fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555086818151811061155757fe5b60200260200101516001600160a01b031688828151811061157457fe5b60200260200101516001600160a01b03167f812ca95fe4492a9e2d1f2723c2c40c03a60a27b059581ae20ac4e4d73bfba35460405160405180910390a360006001600160a01b03168782815181106115c857fe5b60200260200101516001600160a01b03161415801561160d575060016001600160a01b03168782815181106115f957fe5b60200260200101516001600160a01b031614155b156117c85760006001600160a01b031687828151811061162957fe5b60200260200101516001600160a01b031663a7e28d488a848151811061164b57fe5b60200260200101516040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561169957600080fd5b505afa1580156116ad573d6000803e3d6000fd5b505050506040513d60208110156116c357600080fd5b50516001600160a01b03161415611721576040805162461bcd60e51b815260206004820152601c60248201527f544f4b454e5f4e4f545f48414e444c45445f42595f4741544557415900000000604482015290519081900360640190fd5b86818151811061172d57fe5b60200260200101516001600160a01b0316632db09c1c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561176d57600080fd5b505afa158015611781573d6000803e3d6000fd5b505050506040513d602081101561179757600080fd5b505187518890839081106117a757fe5b60200260200101906001600160a01b031690816001600160a01b0316815250505b6001016114d2565b506060634201f98560e01b8888604051602401808060200180602001838103835285818151815260200191508051906020019060200280838360005b8381101561182457818101518382015260200161180c565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561186357818101518382015260200161184b565b50505050905001945050505050604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505090506118f9600660009054906101000a90046001600160a01b0316600160009054906101000a90046001600160a01b03168534600060405180606001604052808b81526020018d81526020018c81525087611905565b98975050505050505050565b60006118f98888888888886000015189602001518a604001518a611c6a565b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b6060600061195689611134565b90506060611965338686611e7d565b604080516001600160a01b0385811682529151929350818c169233928e16917f85291dff2161a93c2f12c819d31889c96c63042116f5bc5a205aa701c2c429f5919081900360200190a4816001600160a01b031663d2ce7d65348c8c8c8c8c886040518863ffffffff1660e01b815260040180876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b0316815260200185815260200184815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611a53578181015183820152602001611a3b565b50505050905090810190601f168015611a805780820380516001836020036101000a031916815260200191505b509750505050505050506000604051808303818588803b158015611aa357600080fd5b505af1158015611ab7573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f191682016040526020811015611ae157600080fd5b8101908080516040519392919084600160201b821115611b0057600080fd5b908301906020820185811115611b1557600080fd5b8251600160201b811182820188101715611b2e57600080fd5b82525081516020918201929091019080838360005b83811015611b5b578181015183820152602001611b43565b50505050905090810190601f168015611b885780820380516001836020036101000a031916815260200191505b5060405250505092505050979650505050505050565b6001600160a01b038216611bef576040805162461bcd60e51b81526020600482015260136024820152721253959053125117d0d3d55395115494105495606a1b604482015290519081900360640190fd5b6001546001600160a01b031615611c3c576040805162461bcd60e51b815260206004820152600c60248201526b1053149150511657d253925560a21b604482015290519081900360640190fd5b600180546001600160a01b039384166001600160a01b03199182161790915560028054929093169116179055565b6000808a6001600160a01b031663679b6ded898c8a8a8e8f8c8c8c6040518a63ffffffff1660e01b815260040180896001600160a01b03166001600160a01b03168152602001888152602001878152602001866001600160a01b03166001600160a01b03168152602001856001600160a01b03166001600160a01b0316815260200184815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611d31578181015183820152602001611d19565b50505050905090810190601f168015611d5e5780820380516001836020036101000a031916815260200191505b5099505050505050505050506020604051808303818588803b158015611d8357600080fd5b505af1158015611d97573d6000803e3d6000fd5b50505050506040513d6020811015611dae57600080fd5b81019080805190602001909291905050509050808a6001600160a01b03168a6001600160a01b03167fc1d1490cf25c3b40d600dfb27c7680340ed1ab901b7e8f3551280968a3b372b0866040518080602001828103825283818151815260200191508051906020019080838360005b83811015611e35578181015183820152602001611e1d565b50505050905090810190601f168015611e625780820380516001836020036101000a031916815260200191505b509250505060405180910390a49a9950505050505050505050565b606083838360405160200180846001600160a01b03166001600160a01b0316815260200180602001828103825284848281815260200192508082843760008184015260408051601f19601f909301831690940184810390920184525250999850505050505050505056fea2646970667358221220d7743bc55082d15fef9972e04a86235c42530952c92b25d83792f50a8a6830f564736f6c634300060b0033", - "linkReferences": {}, - "deployedLinkReferences": {} - } - \ No newline at end of file diff --git a/utils/arbitrum/artifacts/L2GatewayRouter.json b/utils/arbitrum/artifacts/L2GatewayRouter.json deleted file mode 100644 index 8fd5cce8..00000000 --- a/utils/arbitrum/artifacts/L2GatewayRouter.json +++ /dev/null @@ -1,408 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "L2GatewayRouter", - "sourceName": "contracts/tokenbridge/arbitrum/gateway/L2GatewayRouter.sol", - "abi": [ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "newDefaultGateway", - "type": "address" - } - ], - "name": "DefaultGatewayUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "l1Token", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "gateway", - "type": "address" - } - ], - "name": "GatewaySet", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "_userFrom", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "_userTo", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "gateway", - "type": "address" - } - ], - "name": "TransferRouted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "_from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "_to", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "_id", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "name": "TxToL1", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "l1ERC20", - "type": "address" - } - ], - "name": "calculateL2TokenAddress", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "counterpartGateway", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "defaultGateway", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "name": "finalizeInboundTransfer", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_token", - "type": "address" - } - ], - "name": "getGateway", - "outputs": [ - { - "internalType": "address", - "name": "gateway", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_token", - "type": "address" - }, - { - "internalType": "address", - "name": "_from", - "type": "address" - }, - { - "internalType": "address", - "name": "_to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "name": "getOutboundCalldata", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_counterpartGateway", - "type": "address" - }, - { - "internalType": "address", - "name": "_defaultGateway", - "type": "address" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "l1TokenToGateway", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_l1Token", - "type": "address" - }, - { - "internalType": "address", - "name": "_to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "name": "outboundTransfer", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_token", - "type": "address" - }, - { - "internalType": "address", - "name": "_to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_maxGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_gasPriceBid", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "name": "outboundTransfer", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "postUpgradeInit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "router", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newL2DefaultGateway", - "type": "address" - } - ], - "name": "setDefaultGateway", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address[]", - "name": "_l1Token", - "type": "address[]" - }, - { - "internalType": "address[]", - "name": "_gateway", - "type": "address[]" - } - ], - "name": "setGateway", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "0x608060405234801561001057600080fd5b50611161806100206000396000f3fe6080604052600436106100bd5760003560e01c8063a0c76a961161006f578063a0c76a9614610423578063a7e28d48146104fc578063bda009fe1461052f578063d2ce7d6514610562578063ed08fdc6146105fc578063f7c9362f1461062f578063f887ea4014610662576100bd565b806303295802146100c25780632db09c1c146100f35780632e567b36146101085780634201f985146101a0578063485cc955146102d05780637b3a3c8b1461030b57806395fcea781461040e575b600080fd5b3480156100ce57600080fd5b506100d7610677565b604080516001600160a01b039092168252519081900360200190f35b3480156100ff57600080fd5b506100d7610686565b61019e600480360360a081101561011e57600080fd5b6001600160a01b03823581169260208101358216926040820135909216916060820135919081019060a081016080820135600160201b81111561016057600080fd5b82018360208201111561017257600080fd5b803590602001918460018302840111600160201b8311171561019357600080fd5b509092509050610695565b005b3480156101ac57600080fd5b5061019e600480360360408110156101c357600080fd5b810190602081018135600160201b8111156101dd57600080fd5b8201836020820111156101ef57600080fd5b803590602001918460208302840111600160201b8311171561021057600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561025f57600080fd5b82018360208201111561027157600080fd5b803590602001918460208302840111600160201b8311171561029257600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506106d9945050505050565b3480156102dc57600080fd5b5061019e600480360360408110156102f357600080fd5b506001600160a01b0381358116916020013516610853565b6103996004803603608081101561032157600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b81111561035b57600080fd5b82018360208201111561036d57600080fd5b803590602001918460018302840111600160201b8311171561038e57600080fd5b509092509050610863565b6040805160208082528351818301528351919283929083019185019080838360005b838110156103d35781810151838201526020016103bb565b50505050905090810190601f1680156104005780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561041a57600080fd5b5061019e61087f565b34801561042f57600080fd5b50610399600480360360a081101561044657600080fd5b6001600160a01b03823581169260208101358216926040820135909216916060820135919081019060a081016080820135600160201b81111561048857600080fd5b82018360208201111561049a57600080fd5b803590602001918460018302840111600160201b831117156104bb57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295506108dc945050505050565b34801561050857600080fd5b506100d76004803603602081101561051f57600080fd5b50356001600160a01b0316610ade565b34801561053b57600080fd5b506100d76004803603602081101561055257600080fd5b50356001600160a01b0316610b8f565b610399600480360360c081101561057857600080fd5b6001600160a01b0382358116926020810135909116916040820135916060810135916080820135919081019060c0810160a0820135600160201b8111156105be57600080fd5b8201836020820111156105d057600080fd5b803590602001918460018302840111600160201b831117156105f157600080fd5b509092509050610bf1565b34801561060857600080fd5b506100d76004803603602081101561061f57600080fd5b50356001600160a01b0316610e46565b34801561063b57600080fd5b5061019e6004803603602081101561065257600080fd5b50356001600160a01b0316610e61565b34801561066e57600080fd5b506100d7610f35565b6003546001600160a01b031681565b6000546001600160a01b031681565b6040805162461bcd60e51b815260206004820152601460248201527327a7262cafa7aaaa2127aaa7222fa927aaaa22a960611b604482015290519081900360640190fd5b6000546001600160a01b031633148061070d57506000546001600160a01b031661070233610f44565b6001600160a01b0316145b610759576040805162461bcd60e51b81526020600482015260186024820152774f4e4c595f434f554e544552504152545f4741544557415960401b604482015290519081900360640190fd5b805182511461076457fe5b60005b825181101561084e5781818151811061077c57fe5b60200260200101516002600085848151811061079457fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055508181815181106107ec57fe5b60200260200101516001600160a01b031683828151811061080957fe5b60200260200101516001600160a01b03167f812ca95fe4492a9e2d1f2723c2c40c03a60a27b059581ae20ac4e4d73bfba35460405160405180910390a3600101610767565b505050565b61085f82600083610f53565b5050565b60606108758686866000808888610bf1565b9695505050505050565b6000610889610fca565b9050336001600160a01b038216146108d9576040805162461bcd60e51b815260206004820152600e60248201526d2727aa2fa32927a6afa0a226a4a760911b604482015290519081900360640190fd5b50565b606060006108e987610b8f565b9050806001600160a01b031663a0c76a9688888888886040518663ffffffff1660e01b815260040180866001600160a01b03166001600160a01b03168152602001856001600160a01b03166001600160a01b03168152602001846001600160a01b03166001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610999578181015183820152602001610981565b50505050905090810190601f1680156109c65780820380516001836020036101000a031916815260200191505b50965050505050505060006040518083038186803b1580156109e757600080fd5b505afa1580156109fb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015610a2457600080fd5b8101908080516040519392919084600160201b821115610a4357600080fd5b908301906020820185811115610a5857600080fd5b8251600160201b811182820188101715610a7157600080fd5b82525081516020918201929091019080838360005b83811015610a9e578181015183820152602001610a86565b50505050905090810190601f168015610acb5780820380516001836020036101000a031916815260200191505b5060405250505091505095945050505050565b600080610aea83610b8f565b90506001600160a01b038116610b04576000915050610b8a565b806001600160a01b031663a7e28d48846040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610b5a57600080fd5b505afa158015610b6e573d6000803e3d6000fd5b505050506040513d6020811015610b8457600080fd5b50519150505b919050565b6001600160a01b038082166000908152600260205260409020541680610bbd57506003546001600160a01b03165b6001600160a01b03811660011480610be45750610be2816001600160a01b0316610fef565b155b15610b8a57506000610b8a565b60606000610bfe89610b8f565b90506060610c0d338686610ff5565b604080516001600160a01b0385811682529151929350818c169233928e16917f85291dff2161a93c2f12c819d31889c96c63042116f5bc5a205aa701c2c429f5919081900360200190a4816001600160a01b031663d2ce7d65348c8c8c8c8c886040518863ffffffff1660e01b815260040180876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b0316815260200185815260200184815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610cfb578181015183820152602001610ce3565b50505050905090810190601f168015610d285780820380516001836020036101000a031916815260200191505b509750505050505050506000604051808303818588803b158015610d4b57600080fd5b505af1158015610d5f573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f191682016040526020811015610d8957600080fd5b8101908080516040519392919084600160201b821115610da857600080fd5b908301906020820185811115610dbd57600080fd5b8251600160201b811182820188101715610dd657600080fd5b82525081516020918201929091019080838360005b83811015610e03578181015183820152602001610deb565b50505050905090810190601f168015610e305780820380516001836020036101000a031916815260200191505b5060405250505092505050979650505050505050565b6002602052600090815260409020546001600160a01b031681565b6000546001600160a01b0316331480610e9557506000546001600160a01b0316610e8a33610f44565b6001600160a01b0316145b610ee1576040805162461bcd60e51b81526020600482015260186024820152774f4e4c595f434f554e544552504152545f4741544557415960401b604482015290519081900360640190fd5b600380546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f3a8f8eb961383a94d41d193e16a3af73eaddfd5764a4c640257323a1603ac3319181900360200190a150565b6001546001600160a01b031681565b61111061111160901b01190190565b6001600160a01b03821615610f9c576040805162461bcd60e51b815260206004820152600a6024820152692120a22fa927aaaa22a960b11b604482015290519081900360640190fd5b610fa6838361105f565b600380546001600160a01b0319166001600160a01b03929092169190911790555050565b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b3b151590565b606083838360405160200180846001600160a01b03166001600160a01b0316815260200180602001828103825284848281815260200192508082843760008184015260408051601f19601f9093018316909401848103909201845252509998505050505050505050565b6001600160a01b0382166110b0576040805162461bcd60e51b81526020600482015260136024820152721253959053125117d0d3d55395115494105495606a1b604482015290519081900360640190fd5b6000546001600160a01b0316156110fd576040805162461bcd60e51b815260206004820152600c60248201526b1053149150511657d253925560a21b604482015290519081900360640190fd5b600080546001600160a01b039384166001600160a01b0319918216179091556001805492909316911617905556fea26469706673582212207198cc8944389c1932c3adbf1316bc74ec7525726bc255b125ee69816950af4464736f6c634300060b0033", - "deployedBytecode": "0x6080604052600436106100bd5760003560e01c8063a0c76a961161006f578063a0c76a9614610423578063a7e28d48146104fc578063bda009fe1461052f578063d2ce7d6514610562578063ed08fdc6146105fc578063f7c9362f1461062f578063f887ea4014610662576100bd565b806303295802146100c25780632db09c1c146100f35780632e567b36146101085780634201f985146101a0578063485cc955146102d05780637b3a3c8b1461030b57806395fcea781461040e575b600080fd5b3480156100ce57600080fd5b506100d7610677565b604080516001600160a01b039092168252519081900360200190f35b3480156100ff57600080fd5b506100d7610686565b61019e600480360360a081101561011e57600080fd5b6001600160a01b03823581169260208101358216926040820135909216916060820135919081019060a081016080820135600160201b81111561016057600080fd5b82018360208201111561017257600080fd5b803590602001918460018302840111600160201b8311171561019357600080fd5b509092509050610695565b005b3480156101ac57600080fd5b5061019e600480360360408110156101c357600080fd5b810190602081018135600160201b8111156101dd57600080fd5b8201836020820111156101ef57600080fd5b803590602001918460208302840111600160201b8311171561021057600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561025f57600080fd5b82018360208201111561027157600080fd5b803590602001918460208302840111600160201b8311171561029257600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506106d9945050505050565b3480156102dc57600080fd5b5061019e600480360360408110156102f357600080fd5b506001600160a01b0381358116916020013516610853565b6103996004803603608081101561032157600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b81111561035b57600080fd5b82018360208201111561036d57600080fd5b803590602001918460018302840111600160201b8311171561038e57600080fd5b509092509050610863565b6040805160208082528351818301528351919283929083019185019080838360005b838110156103d35781810151838201526020016103bb565b50505050905090810190601f1680156104005780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561041a57600080fd5b5061019e61087f565b34801561042f57600080fd5b50610399600480360360a081101561044657600080fd5b6001600160a01b03823581169260208101358216926040820135909216916060820135919081019060a081016080820135600160201b81111561048857600080fd5b82018360208201111561049a57600080fd5b803590602001918460018302840111600160201b831117156104bb57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295506108dc945050505050565b34801561050857600080fd5b506100d76004803603602081101561051f57600080fd5b50356001600160a01b0316610ade565b34801561053b57600080fd5b506100d76004803603602081101561055257600080fd5b50356001600160a01b0316610b8f565b610399600480360360c081101561057857600080fd5b6001600160a01b0382358116926020810135909116916040820135916060810135916080820135919081019060c0810160a0820135600160201b8111156105be57600080fd5b8201836020820111156105d057600080fd5b803590602001918460018302840111600160201b831117156105f157600080fd5b509092509050610bf1565b34801561060857600080fd5b506100d76004803603602081101561061f57600080fd5b50356001600160a01b0316610e46565b34801561063b57600080fd5b5061019e6004803603602081101561065257600080fd5b50356001600160a01b0316610e61565b34801561066e57600080fd5b506100d7610f35565b6003546001600160a01b031681565b6000546001600160a01b031681565b6040805162461bcd60e51b815260206004820152601460248201527327a7262cafa7aaaa2127aaa7222fa927aaaa22a960611b604482015290519081900360640190fd5b6000546001600160a01b031633148061070d57506000546001600160a01b031661070233610f44565b6001600160a01b0316145b610759576040805162461bcd60e51b81526020600482015260186024820152774f4e4c595f434f554e544552504152545f4741544557415960401b604482015290519081900360640190fd5b805182511461076457fe5b60005b825181101561084e5781818151811061077c57fe5b60200260200101516002600085848151811061079457fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055508181815181106107ec57fe5b60200260200101516001600160a01b031683828151811061080957fe5b60200260200101516001600160a01b03167f812ca95fe4492a9e2d1f2723c2c40c03a60a27b059581ae20ac4e4d73bfba35460405160405180910390a3600101610767565b505050565b61085f82600083610f53565b5050565b60606108758686866000808888610bf1565b9695505050505050565b6000610889610fca565b9050336001600160a01b038216146108d9576040805162461bcd60e51b815260206004820152600e60248201526d2727aa2fa32927a6afa0a226a4a760911b604482015290519081900360640190fd5b50565b606060006108e987610b8f565b9050806001600160a01b031663a0c76a9688888888886040518663ffffffff1660e01b815260040180866001600160a01b03166001600160a01b03168152602001856001600160a01b03166001600160a01b03168152602001846001600160a01b03166001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610999578181015183820152602001610981565b50505050905090810190601f1680156109c65780820380516001836020036101000a031916815260200191505b50965050505050505060006040518083038186803b1580156109e757600080fd5b505afa1580156109fb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015610a2457600080fd5b8101908080516040519392919084600160201b821115610a4357600080fd5b908301906020820185811115610a5857600080fd5b8251600160201b811182820188101715610a7157600080fd5b82525081516020918201929091019080838360005b83811015610a9e578181015183820152602001610a86565b50505050905090810190601f168015610acb5780820380516001836020036101000a031916815260200191505b5060405250505091505095945050505050565b600080610aea83610b8f565b90506001600160a01b038116610b04576000915050610b8a565b806001600160a01b031663a7e28d48846040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610b5a57600080fd5b505afa158015610b6e573d6000803e3d6000fd5b505050506040513d6020811015610b8457600080fd5b50519150505b919050565b6001600160a01b038082166000908152600260205260409020541680610bbd57506003546001600160a01b03165b6001600160a01b03811660011480610be45750610be2816001600160a01b0316610fef565b155b15610b8a57506000610b8a565b60606000610bfe89610b8f565b90506060610c0d338686610ff5565b604080516001600160a01b0385811682529151929350818c169233928e16917f85291dff2161a93c2f12c819d31889c96c63042116f5bc5a205aa701c2c429f5919081900360200190a4816001600160a01b031663d2ce7d65348c8c8c8c8c886040518863ffffffff1660e01b815260040180876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b0316815260200185815260200184815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610cfb578181015183820152602001610ce3565b50505050905090810190601f168015610d285780820380516001836020036101000a031916815260200191505b509750505050505050506000604051808303818588803b158015610d4b57600080fd5b505af1158015610d5f573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f191682016040526020811015610d8957600080fd5b8101908080516040519392919084600160201b821115610da857600080fd5b908301906020820185811115610dbd57600080fd5b8251600160201b811182820188101715610dd657600080fd5b82525081516020918201929091019080838360005b83811015610e03578181015183820152602001610deb565b50505050905090810190601f168015610e305780820380516001836020036101000a031916815260200191505b5060405250505092505050979650505050505050565b6002602052600090815260409020546001600160a01b031681565b6000546001600160a01b0316331480610e9557506000546001600160a01b0316610e8a33610f44565b6001600160a01b0316145b610ee1576040805162461bcd60e51b81526020600482015260186024820152774f4e4c595f434f554e544552504152545f4741544557415960401b604482015290519081900360640190fd5b600380546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f3a8f8eb961383a94d41d193e16a3af73eaddfd5764a4c640257323a1603ac3319181900360200190a150565b6001546001600160a01b031681565b61111061111160901b01190190565b6001600160a01b03821615610f9c576040805162461bcd60e51b815260206004820152600a6024820152692120a22fa927aaaa22a960b11b604482015290519081900360640190fd5b610fa6838361105f565b600380546001600160a01b0319166001600160a01b03929092169190911790555050565b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b3b151590565b606083838360405160200180846001600160a01b03166001600160a01b0316815260200180602001828103825284848281815260200192508082843760008184015260408051601f19601f9093018316909401848103909201845252509998505050505050505050565b6001600160a01b0382166110b0576040805162461bcd60e51b81526020600482015260136024820152721253959053125117d0d3d55395115494105495606a1b604482015290519081900360640190fd5b6000546001600160a01b0316156110fd576040805162461bcd60e51b815260206004820152600c60248201526b1053149150511657d253925560a21b604482015290519081900360640190fd5b600080546001600160a01b039384166001600160a01b0319918216179091556001805492909316911617905556fea26469706673582212207198cc8944389c1932c3adbf1316bc74ec7525726bc255b125ee69816950af4464736f6c634300060b0033", - "linkReferences": {}, - "deployedLinkReferences": {} - } - \ No newline at end of file diff --git a/utils/arbitrum/contracts.ts b/utils/arbitrum/contracts.ts deleted file mode 100644 index 778e2eb5..00000000 --- a/utils/arbitrum/contracts.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { - L1GatewayRouter__factory, - L2GatewayRouter__factory, - ArbSysStub__factory, - Inbox__factory, -} from "../../typechain/"; -import addresses from "./addresses"; -import { CommonOptions } from "./types"; -import network, { NetworkName } from "../network"; - -interface ContractsOptions extends CommonOptions { - forking: boolean; -} - -export default function contracts( - networkName: NetworkName, - options: ContractsOptions -) { - const [l1Provider, l2Provider] = network - .multichain(["eth", "arb"], networkName) - .getProviders(options); - - const arbAddresses = addresses(networkName, options); - - return { - ArbSysStub: ArbSysStub__factory.connect(arbAddresses.ArbSys, l2Provider), - L1GatewayRouter: L1GatewayRouter__factory.connect( - arbAddresses.L1GatewayRouter, - l1Provider - ), - L2GatewayRouter: L2GatewayRouter__factory.connect( - arbAddresses.L2GatewayRouter, - l2Provider - ), - Inbox: Inbox__factory.connect(arbAddresses.Inbox, l1Provider), - }; -} diff --git a/utils/arbitrum/deployment.ts b/utils/arbitrum/deployment.ts deleted file mode 100644 index 3327cff2..00000000 --- a/utils/arbitrum/deployment.ts +++ /dev/null @@ -1,203 +0,0 @@ -import { assert } from "chai"; -import { ethers } from "hardhat"; -import { Overrides, Wallet } from "ethers"; -import { - ERC20Bridged__factory, - IERC20Metadata__factory, - L1ERC20TokenGateway__factory, - L1GatewayRouter__factory, - L2ERC20TokenGateway__factory, - L2GatewayRouter__factory, - OssifiableProxy__factory, -} from "../../typechain"; - -import addresses from "./addresses"; -import { CommonOptions } from "./types"; -import network, { NetworkName } from "../network"; -import { DeployScript, Logger } from "../deployment/DeployScript"; - -interface ArbL1DeployScriptParams { - deployer: Wallet; - admins: { proxy: string; bridge: string }; -} - -interface ArbL2DeployScriptParams extends ArbL1DeployScriptParams { - l2Token?: { name?: string; symbol?: string }; -} - -interface ArbDeploymentOptions extends CommonOptions { - logger?: Logger; - overrides?: Overrides; -} - -export default function deployment( - networkName: NetworkName, - options: ArbDeploymentOptions = {} -) { - const arbAddresses = addresses(networkName, options); - - return { - async erc20TokenGatewayDeployScript( - l1Token: string, - l1Params: ArbL1DeployScriptParams, - l2Params: ArbL2DeployScriptParams - ) { - const [ - expectedL1TokensGatewayImplAddress, - expectedL1TokensGatewayProxyAddress, - ] = await network.predictAddresses(l1Params.deployer, 2); - - const [ - expectedL2TokenImplAddress, - expectedL2TokenProxyAddress, - expectedL2TokensGatewayImplAddress, - expectedL2TokensGatewayProxyAddress, - ] = await network.predictAddresses(l2Params.deployer, 4); - - const l1DeployScript = new DeployScript( - l1Params.deployer, - options?.logger - ) - .addStep({ - factory: L1ERC20TokenGateway__factory, - args: [ - arbAddresses.Inbox, - arbAddresses.L1GatewayRouter, - expectedL2TokensGatewayProxyAddress, - l1Token, - expectedL2TokenProxyAddress, - options?.overrides, - ], - afterDeploy: (c) => - assert.equal(c.address, expectedL1TokensGatewayImplAddress), - }) - .addStep({ - factory: OssifiableProxy__factory, - args: [ - expectedL1TokensGatewayImplAddress, - l1Params.admins.proxy, - L1ERC20TokenGateway__factory.createInterface().encodeFunctionData( - "initialize", - [l1Params.admins.bridge] - ), - options?.overrides, - ], - afterDeploy: (c) => - assert.equal(c.address, expectedL1TokensGatewayProxyAddress), - }); - - const l1TokenInfo = IERC20Metadata__factory.connect( - l1Token, - l1Params.deployer - ); - - const [decimals, l2TokenName, l2TokenSymbol] = await Promise.all([ - l1TokenInfo.decimals(), - l2Params.l2Token?.name ?? l1TokenInfo.name(), - l2Params.l2Token?.symbol ?? l1TokenInfo.symbol(), - ]); - - const l2DeployScript = new DeployScript( - l2Params.deployer, - options?.logger - ) - .addStep({ - factory: ERC20Bridged__factory, - args: [ - l2TokenName, - l2TokenSymbol, - decimals, - expectedL2TokensGatewayProxyAddress, - options?.overrides, - ], - afterDeploy: (c) => - assert.equal(c.address, expectedL2TokenImplAddress), - }) - .addStep({ - factory: OssifiableProxy__factory, - args: [ - expectedL2TokenImplAddress, - l2Params.admins.proxy, - ERC20Bridged__factory.createInterface().encodeFunctionData( - "initialize", - [l2TokenName, l2TokenSymbol] - ), - options?.overrides, - ], - afterDeploy: (c) => - assert.equal(c.address, expectedL2TokenProxyAddress), - }) - .addStep({ - factory: L2ERC20TokenGateway__factory, - args: [ - arbAddresses.ArbSys, - arbAddresses.L2GatewayRouter, - expectedL1TokensGatewayProxyAddress, - l1Token, - expectedL2TokenProxyAddress, - options?.overrides, - ], - afterDeploy: (c) => - assert.equal(c.address, expectedL2TokensGatewayImplAddress), - }) - .addStep({ - factory: OssifiableProxy__factory, - args: [ - expectedL2TokensGatewayImplAddress, - l2Params.admins.proxy, - L2ERC20TokenGateway__factory.createInterface().encodeFunctionData( - "initialize", - [l2Params.admins.bridge] - ), - options?.overrides, - ], - }); - - return [l1DeployScript, l2DeployScript]; - }, - async gatewayRouterDeployScript(l1Deployer: Wallet, l2Deployer: Wallet) { - const [expectedL1GatewayRouter] = await network.predictAddresses( - l1Deployer, - 1 - ); - const [expectedL2GatewayRouter] = await network.predictAddresses( - l2Deployer, - 1 - ); - - const l1DeployScript = new DeployScript( - l1Deployer, - options?.logger - ).addStep({ - factory: L1GatewayRouter__factory, - args: [options?.overrides], - afterDeploy: async (l1GatewayRouter) => { - assert.equal(l1GatewayRouter.address, expectedL1GatewayRouter); - await l1GatewayRouter.initialize( - l1Deployer.address, - ethers.constants.AddressZero, - ethers.constants.AddressZero, - expectedL2GatewayRouter, - arbAddresses.Inbox - ); - }, - }); - - const l2DeployScript = new DeployScript( - l2Deployer, - options?.logger - ).addStep({ - factory: L2GatewayRouter__factory, - args: [options?.overrides], - afterDeploy: async (l2GatewayRouter) => { - assert.equal(l2GatewayRouter.address, expectedL2GatewayRouter); - await l2GatewayRouter.initialize( - expectedL1GatewayRouter, - ethers.constants.AddressZero - ); - }, - }); - return [l1DeployScript, l2DeployScript]; - }, - }; -} diff --git a/utils/arbitrum/index.ts b/utils/arbitrum/index.ts deleted file mode 100644 index 73d4d32b..00000000 --- a/utils/arbitrum/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -import testing from "./testing"; -import addresses from "./addresses"; -import contracts from "./contracts"; -import deployment from "./deployment"; -import messaging from "./messaging"; - -export default { - testing, - addresses, - contracts, - messaging, - deployment, -}; diff --git a/utils/arbitrum/messaging.ts b/utils/arbitrum/messaging.ts deleted file mode 100644 index 5fb57499..00000000 --- a/utils/arbitrum/messaging.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { L1ToL2MessageGasEstimator, L1TransactionReceipt } from "@arbitrum/sdk"; -import { JsonRpcProvider } from "@ethersproject/providers"; -import { BigNumber, BigNumberish } from "ethers"; -import { hexDataLength } from "ethers/lib/utils"; -import network, { NetworkName } from "../network"; -import contracts from "./contracts"; - -import { CommonOptions } from "./types"; - -interface RetryableTicketOptions extends CommonOptions { - forking: boolean; -} - -interface MessageData { - sender: string; - recipient: string; - calldata: string; - callvalue?: BigNumberish; - refundAddress?: string; -} - -const SUBMISSION_PRICE_MULTIPLIER = 2; - -async function getRetryableTicketSendParams( - ethProvider: JsonRpcProvider, - arbProvider: JsonRpcProvider, - msg: MessageData -) { - const l1ToL2MessageGasEstimator = new L1ToL2MessageGasEstimator(arbProvider); - - const { baseFeePerGas } = await ethProvider.getBlock( - await ethProvider.getBlockNumber() - ); - if (!baseFeePerGas) { - throw new Error( - "Latest block did not contain base fee, ensure provider is connected to a network that supports EIP 1559." - ); - } - - const maxSubmissionCost = await l1ToL2MessageGasEstimator - .estimateSubmissionFee( - ethProvider, - baseFeePerGas, - hexDataLength(msg.calldata) + 4 - ) - .then((submissionPrice) => - submissionPrice.mul(SUBMISSION_PRICE_MULTIPLIER) - ); - - const arbGasPriceBid = await arbProvider.getGasPrice(); - - const maxGas = - await l1ToL2MessageGasEstimator.estimateRetryableTicketGasLimit({ - from: msg.sender, - to: msg.recipient, - l2CallValue: BigNumber.from(msg.callvalue || 0), - excessFeeRefundAddress: msg.refundAddress || msg.sender, - callValueRefundAddress: msg.refundAddress || msg.sender, - data: msg.calldata, - }); - - return { - maxGas, - maxSubmissionCost, - gasPriceBid: arbGasPriceBid, - callvalue: maxSubmissionCost.add(arbGasPriceBid.mul(maxGas)), - }; -} - -export default function messaging( - networkName: NetworkName, - options: RetryableTicketOptions -) { - const [ethProvider, arbProvider] = network - .multichain(["eth", "arb"], networkName) - .getProviders(options); - const arbContracts = contracts(networkName, options); - return { - async waitForL2Message(l1TxHash: string) { - const l1TxReceipt = new L1TransactionReceipt( - await ethProvider.getTransactionReceipt(l1TxHash) - ); - const [message] = await l1TxReceipt.getL1ToL2Messages(arbProvider); - return message.waitForStatus(); - }, - async getRetryableTicketSendParams(msg: MessageData) { - return getRetryableTicketSendParams(ethProvider, arbProvider, msg); - }, - async prepareRetryableTicketTx(msg: MessageData) { - const { maxGas, gasPriceBid, maxSubmissionCost, callvalue } = - await getRetryableTicketSendParams(ethProvider, arbProvider, msg); - - return { - callvalue, - calldata: arbContracts.Inbox.interface.encodeFunctionData( - "createRetryableTicket", - [ - msg.recipient, - BigNumber.from(msg.callvalue || 0), - maxSubmissionCost, - msg.refundAddress || msg.sender, - msg.refundAddress || msg.sender, - maxGas, - gasPriceBid, - msg.calldata, - ] - ), - }; - }, - }; -} diff --git a/utils/arbitrum/testing.ts b/utils/arbitrum/testing.ts deleted file mode 100644 index e34dce4c..00000000 --- a/utils/arbitrum/testing.ts +++ /dev/null @@ -1,337 +0,0 @@ -import { - IERC20__factory, - ERC20BridgedStub__factory, - L1ERC20TokenGateway__factory, - L2ERC20TokenGateway__factory, - ArbSysStub__factory, - ERC20Bridged__factory, -} from "../../typechain"; -import contracts from "./contracts"; -import addresses from "./addresses"; -import deployment from "./deployment"; -import testingUtils from "../testing"; -import { BridgingManagement } from "../bridging-management"; -import network, { NetworkName, SignerOrProvider } from "../network"; -import { JsonRpcProvider } from "@ethersproject/providers"; - -export default function testing(networkName: NetworkName) { - const defaultArbAddresses = addresses(networkName); - const ethArbNetworks = network.multichain(["eth", "arb"], networkName); - - const [ethProviderForking, arbProviderForking] = ethArbNetworks.getProviders({ - forking: true, - }); - - return { - async getAcceptanceTestSetup() { - const gatewayContracts = await loadDeployedGateways( - ethProviderForking, - arbProviderForking - ); - - const { L1GatewayRouter, L2GatewayRouter } = contracts(networkName, { - customAddresses: loadGatewayRouterAddresses(networkName), - forking: true, - }); - - return { - l1Provider: ethProviderForking, - l2Provider: arbProviderForking, - ...gatewayContracts, - l1GatewayRouter: L1GatewayRouter, - l2GatewayRouter: L2GatewayRouter, - }; - }, - async getIntegrationTestSetup() { - const hasDeployedContracts = - testingUtils.env.USE_DEPLOYED_CONTRACTS(false); - - const gatewayContracts = hasDeployedContracts - ? await loadDeployedGateways(ethProviderForking, arbProviderForking) - : await deployTestGateway( - networkName, - ethProviderForking, - arbProviderForking - ); - - const [l1ERC20TokenGatewayAdminAddress] = - await BridgingManagement.getAdmins( - gatewayContracts.l1ERC20TokenGateway - ); - - const [l2ERC20TokenGatewayAdminAddress] = - await BridgingManagement.getAdmins( - gatewayContracts.l2ERC20TokenGateway - ); - - const customGatewayRouterAddresses = hasDeployedContracts - ? loadGatewayRouterAddresses(networkName) - : undefined; - - const { - L1GatewayRouter: l1GatewayRouter, - L2GatewayRouter: l2GatewayRouter, - } = contracts(networkName, { - customAddresses: customGatewayRouterAddresses, - forking: true, - }); - - const l1TokensHolder = hasDeployedContracts - ? await testingUtils.impersonate( - testingUtils.env.L1_TOKENS_HOLDER(), - ethProviderForking - ) - : testingUtils.accounts.deployer(ethProviderForking); - - if (hasDeployedContracts) { - await printLoadedTestConfig( - networkName, - l1TokensHolder, - gatewayContracts, - { l1GatewayRouter, l2GatewayRouter } - ); - } - - // if the L1 bridge admin is a contract, remove it's code to - // make it behave as EOA - await ethProviderForking.send("hardhat_setCode", [ - l1ERC20TokenGatewayAdminAddress, - "0x", - ]); - - // same for the L2 bridge admin - await arbProviderForking.send("hardhat_setCode", [ - l2ERC20TokenGatewayAdminAddress, - "0x", - ]); - - const { ArbSysStub } = contracts(networkName, { forking: true }); - - return { - l1GatewayRouter, - l2GatewayRouter, - l1Provider: ethProviderForking, - l2Provider: arbProviderForking, - l1TokensHolder, - ...gatewayContracts, - arbSysStub: ArbSysStub, - l1ERC20TokenGatewayAdmin: await testingUtils.impersonate( - l1ERC20TokenGatewayAdminAddress, - ethProviderForking - ), - l2ERC20TokenGatewayAdmin: await testingUtils.impersonate( - l2ERC20TokenGatewayAdminAddress, - arbProviderForking - ), - }; - }, - async getE2ETestSetup() { - const testerPrivateKey = testingUtils.env.TESTING_PRIVATE_KEY(); - - const [l1Provider, l2Provider] = ethArbNetworks.getProviders({ - forking: false, - }); - - const [l1Tester, l2Tester] = ethArbNetworks.getSigners(testerPrivateKey, { - forking: false, - }); - - const gatewayContracts = await loadDeployedGateways(l1Tester, l2Tester); - - const { - L1GatewayRouter: l1GatewayRouter, - L2GatewayRouter: l2GatewayRouter, - } = contracts(networkName, { - customAddresses: loadGatewayRouterAddresses(networkName), - forking: true, - }); - - await printLoadedTestConfig(networkName, l1Tester, gatewayContracts, { - l1GatewayRouter, - l2GatewayRouter, - }); - - return { - l1Tester, - l2Tester, - l1Provider, - l2Provider, - l1GatewayRouter, - l2GatewayRouter, - ...gatewayContracts, - }; - }, - async stubArbSysContract() { - const deployer = testingUtils.accounts.deployer(arbProviderForking); - const stub = await new ArbSysStub__factory(deployer).deploy(); - const stubBytecode = await arbProviderForking.send("eth_getCode", [ - stub.address, - ]); - - await arbProviderForking.send("hardhat_setCode", [ - defaultArbAddresses.ArbSys, - stubBytecode, - ]); - }, - }; -} - -async function deployTestGateway( - networkName: NetworkName, - ethProvider: JsonRpcProvider, - arbProvider: JsonRpcProvider -) { - const ethDeployer = testingUtils.accounts.deployer(ethProvider); - const arbDeployer = testingUtils.accounts.deployer(arbProvider); - - const l1Token = await new ERC20BridgedStub__factory(ethDeployer).deploy( - "Test Token", - "TT" - ); - - const [ethDeployScript, arbDeployScript] = await deployment( - networkName - ).erc20TokenGatewayDeployScript( - l1Token.address, - { - deployer: ethDeployer, - admins: { proxy: ethDeployer.address, bridge: ethDeployer.address }, - }, - { - deployer: arbDeployer, - admins: { proxy: arbDeployer.address, bridge: arbDeployer.address }, - } - ); - - await ethDeployScript.run(); - await arbDeployScript.run(); - - const l1ERC20TokenBridgeProxyDeployStepIndex = 1; - const l1BridgingManagement = new BridgingManagement( - ethDeployScript.getContractAddress(l1ERC20TokenBridgeProxyDeployStepIndex), - ethDeployer - ); - - const l2ERC20TokenBridgeProxyDeployStepIndex = 3; - const l2BridgingManagement = new BridgingManagement( - arbDeployScript.getContractAddress(l2ERC20TokenBridgeProxyDeployStepIndex), - arbDeployer - ); - - await l1BridgingManagement.setup({ - bridgeAdmin: ethDeployer.address, - depositsEnabled: true, - withdrawalsEnabled: true, - }); - - await l2BridgingManagement.setup({ - bridgeAdmin: arbDeployer.address, - depositsEnabled: true, - withdrawalsEnabled: true, - }); - - return { - l1Token: l1Token.connect(ethProvider), - ...connectGatewayContracts( - { - l2Token: arbDeployScript.getContractAddress(1), - l1ERC20TokenGateway: ethDeployScript.getContractAddress(1), - l2ERC20TokenGateway: arbDeployScript.getContractAddress(3), - }, - ethProvider, - arbProvider - ), - }; -} - -async function loadDeployedGateways( - l1SignerOrProvider: SignerOrProvider, - l2SignerOrProvider: SignerOrProvider -) { - return { - l1Token: IERC20__factory.connect( - testingUtils.env.ARB_L1_TOKEN(), - l1SignerOrProvider - ), - ...connectGatewayContracts( - { - l2Token: testingUtils.env.ARB_L2_TOKEN(), - l1ERC20TokenGateway: testingUtils.env.ARB_L1_ERC20_TOKEN_GATEWAY(), - l2ERC20TokenGateway: testingUtils.env.ARB_L2_ERC20_TOKEN_GATEWAY(), - }, - l1SignerOrProvider, - l2SignerOrProvider - ), - }; -} - -function connectGatewayContracts( - addresses: { - l2Token: string; - l1ERC20TokenGateway: string; - l2ERC20TokenGateway: string; - }, - l1SignerOrProvider: SignerOrProvider, - l2SignerOrProvider: SignerOrProvider -) { - const l1ERC20TokenGateway = L1ERC20TokenGateway__factory.connect( - addresses.l1ERC20TokenGateway, - l1SignerOrProvider - ); - const l2ERC20TokenGateway = L2ERC20TokenGateway__factory.connect( - addresses.l2ERC20TokenGateway, - l2SignerOrProvider - ); - const l2Token = ERC20Bridged__factory.connect( - addresses.l2Token, - l2SignerOrProvider - ); - return { - l2Token, - l1ERC20TokenGateway, - l2ERC20TokenGateway, - }; -} - -function loadGatewayRouterAddresses(networkName: NetworkName) { - const defaultArbAddresses = addresses(networkName); - return { - L1GatewayRouter: testingUtils.env.ARB_L1_GATEWAY_ROUTER( - defaultArbAddresses.L1GatewayRouter - ), - L2GatewayRouter: testingUtils.env.ARB_L2_GATEWAY_ROUTER( - defaultArbAddresses.L2GatewayRouter - ), - }; -} - -async function printLoadedTestConfig( - networkName: NetworkName, - l1TokensHolder: any, - gatewayContracts: any, - gatewayRouters: any -) { - console.log("Using the deployed contracts for integration tests"); - console.log( - "In case of unexpected fails, please, make sure that you are forking correct Ethereum/Arbitrum networks" - ); - console.log(` Network Name: ${networkName}`); - console.log(` L1 Token: ${gatewayContracts.l1Token.address}`); - console.log(` L2 Token: ${gatewayContracts.l2Token.address}`); - const l1TokensHolderAddress = await l1TokensHolder.getAddress(); - console.log(` L1 Tokens Holder: ${l1TokensHolderAddress}`); - const holderBalance = await gatewayContracts.l1Token.balanceOf( - l1TokensHolderAddress - ); - console.log(` L1 Tokens Holder Balance: ${holderBalance.toString()}`); - console.log( - ` L1 ERC20 Token Gateway: ${gatewayContracts.l1ERC20TokenGateway.address}` - ); - console.log( - ` L2 ERC20 Token Gateway: ${gatewayContracts.l2ERC20TokenGateway.address}` - ); - console.log(` L1 Gateway Router: ${gatewayRouters.l1GatewayRouter.address}`); - console.log( - ` L2 Gateway Routery: ${gatewayRouters.l2GatewayRouter.address}` - ); -} diff --git a/utils/arbitrum/types.ts b/utils/arbitrum/types.ts deleted file mode 100644 index e17ed21b..00000000 --- a/utils/arbitrum/types.ts +++ /dev/null @@ -1,15 +0,0 @@ -export type ArbContractNames = - | "Inbox" - | "ArbSys" - | "Bridge" - | "Outbox" - | "L1GatewayRouter" - | "L2GatewayRouter"; - -export type ArbContractAddresses = Record; - -export type CustomArbContractAddresses = Partial; - -export interface CommonOptions { - customAddresses?: CustomArbContractAddresses; -} diff --git a/utils/deployment/DeployScript.ts b/utils/deployment/DeployScript.ts index a6adb1d9..3e9f7b8c 100644 --- a/utils/deployment/DeployScript.ts +++ b/utils/deployment/DeployScript.ts @@ -170,8 +170,6 @@ export class DeployScript { 10: "opt_mainnet", 11155420: "opt_sepolia", 31337: "hardhat", - 42161: "arb_mainnet", - 421613: "arb_sepolia", }; const networkName = networkNameByChainId[chainId] || ""; const arsString = stepInfo.args.map((a) => `"${a.value}"`).join(" "); diff --git a/utils/network.ts b/utils/network.ts index 1564aa27..30603cda 100644 --- a/utils/network.ts +++ b/utils/network.ts @@ -6,7 +6,7 @@ import { HardhatRuntimeEnvironment, HttpNetworkConfig } from "hardhat/types"; import env from "./env"; -type ChainNameShort = "arb" | "opt" | "eth"; +type ChainNameShort = "opt" | "eth"; export type NetworkName = "sepolia" | "mainnet"; export type SignerOrProvider = Signer | Provider; @@ -15,10 +15,6 @@ const HARDHAT_NETWORK_NAMES = { sepolia: "eth_sepolia", mainnet: "eth_mainnet", }, - arb: { - sepolia: "arb_sepolia", - mainnet: "arb_mainnet", - }, opt: { sepolia: "opt_sepolia", mainnet: "opt_mainnet", @@ -30,10 +26,6 @@ const HARDHAT_NETWORK_NAMES_FORK = { sepolia: "eth_sepolia_fork", mainnet: "eth_mainnet_fork", }, - arb: { - sepolia: "arb_sepolia_fork", - mainnet: "arb_mainnet_fork", - }, opt: { sepolia: "opt_sepolia_fork", mainnet: "opt_mainnet_fork", @@ -125,10 +117,6 @@ function getChainId(protocol: ChainNameShort, networkName: NetworkName) { mainnet: 10, sepolia: 11155420, }, - arb: { - mainnet: 42161, - sepolia: 421613, - }, }; const chainId = chainIds[protocol][networkName]; if (!chainId) { @@ -142,9 +130,6 @@ function getBlockExplorerBaseUrlByChainId(chainId: number) { // ethereum 1: "https://etherscan.io", 11155111: "https://sepolia.etherscan.io", - // arbitrum - 42161: "https://arbiscan.io", - 421613: "https://sepolia-rollup-explorer.arbitrum.io", // optimism 10: "https://optimistic.etherscan.io", 11155420: "https://blockscout.com/optimism/sepolia", diff --git a/utils/testing/e2e.ts b/utils/testing/e2e.ts index 010596e7..1c60955c 100644 --- a/utils/testing/e2e.ts +++ b/utils/testing/e2e.ts @@ -21,25 +21,6 @@ export const E2E_TEST_CONTRACTS_OPTIMISM = { }, }; -export const E2E_TEST_CONTRACTS_ARBITRUM = { - l1: { - l1Token: "0x7AEE39c46f20135114e85A03C02aB4FE73fB8127", - l1GatewayRouter: "0xa2a8F940752aDc4A3278B63B96d56D72D2b075B1", - l1ERC20TokenGateway: "0x46b10f1E65f19876F50bfdD59C9B39E9De6B9150", - aragonVoting: "0x04F9590D3EEC8e619D7714ffeF664aD3fd53b880", - tokenManager: "0x1ee7e87486f9ae6e27a5e58310a5319394360cf0", - agent: "0x12869c3349f993c5c20bab9482b7d16aff0ae2f9", - l1LDOToken: "0x84b4c77b260910fc02dddac41ef0e45e658b18af", - inbox: "0x578BAde599406A8fE3d24Fd7f7211c0911F5B29e", - }, - l2: { - l2Token: "0x57FA50b80f79b9140fe7249A93D432d9fa8C4192", - l2GatewayRouter: "0x57f54f87C44d816f60b92864e23b8c0897D4d81D", - l2ERC20TokenGateway: "0xD06491e4C8B3107B83dC134894C4c96ED8ddbfa2", - govBridgeExecutor: "0x4e8CC9024Ea3FE886623025fF2aD0CA4bb3D1F42", - }, -}; - export const createOptimismVoting = async ( ctx: any, executorCalldata: string @@ -84,40 +65,5 @@ export const encodeEVMScript = ( ); }; -export const createArbitrumVoting = async ( - ctx: any, - executorCalldata: string, - options: Record = {} -) => { - const messageCalldata = await ctx.inbox.interface.encodeFunctionData( - "createRetryableTicket", - [ - ctx.govBridgeExecutor.address, - 0, - options.maxSubmissionCost || wei`0.01 ether`, - ctx.l2Tester.address, - ctx.l2Tester.address, - options.maxGas || 3000000, - options.gasPriceBid || 5000000000, - executorCalldata, - ] - ); - - const agentCalldata = ctx.agent.interface.encodeFunctionData("execute", [ - ctx.inbox.address, - options.callValue || wei`0.01 ether`, - messageCalldata, - ]); - const agentEvmScript = encodeEVMScript(ctx.agent.address, agentCalldata); - - const newVoteCalldata = - "0xd5db2c80" + - abiCoder.encode(["bytes", "string"], [agentEvmScript, ""]).substring(2); - const votingEvmScript = encodeEVMScript(ctx.voting.address, newVoteCalldata); - const newVotingTx = await ctx.tokenMnanager.forward(votingEvmScript); - - await newVotingTx.wait(); -}; - export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); diff --git a/utils/testing/env.ts b/utils/testing/env.ts index faf8acd6..7d78ab5b 100644 --- a/utils/testing/env.ts +++ b/utils/testing/env.ts @@ -4,29 +4,6 @@ export default { USE_DEPLOYED_CONTRACTS(defaultValue: boolean = false) { return env.bool("TESTING_USE_DEPLOYED_CONTRACTS", defaultValue); }, - - ARB_L1_TOKEN() { - return env.address("TESTING_ARB_L1_TOKEN"); - }, - ARB_L2_TOKEN() { - return env.address("TESTING_ARB_L2_TOKEN"); - }, - ARB_L1_ERC20_TOKEN_GATEWAY() { - return env.address("TESTING_ARB_L1_ERC20_TOKEN_GATEWAY"); - }, - ARB_L2_ERC20_TOKEN_GATEWAY() { - return env.address("TESTING_ARB_L2_ERC20_TOKEN_GATEWAY"); - }, - ARB_L1_GATEWAY_ROUTER(defaultValue?: string) { - return env.address("TESTING_ARB_L1_GATEWAY_ROUTER", defaultValue); - }, - ARB_L2_GATEWAY_ROUTER(defaultValue?: string) { - return env.address("TESTING_ARB_L2_GATEWAY_ROUTER", defaultValue); - }, - ARB_GOV_BRIDGE_EXECUTOR() { - return env.address("TESTING_ARB_GOV_BRIDGE_EXECUTOR"); - }, - OPT_L1_TOKEN() { return env.address("TESTING_OPT_L1_TOKEN"); },