From 4bc472f331320afa7d741a51964a04d98bf9079f Mon Sep 17 00:00:00 2001 From: jump <> Date: Tue, 19 Mar 2024 20:33:21 +0800 Subject: [PATCH 1/4] adjust manta configs --- hardhat.config.ts | 6 +++--- utils/network.ts | 2 ++ utils/optimism/addresses.ts | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/hardhat.config.ts b/hardhat.config.ts index ed47221..6c80b0c 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -108,10 +108,10 @@ const config: HardhatUserConfig = { }, { network: 'opt_sepolia', - chainId: 11155420, + chainId: 3441006, urls: { - apiURL: 'https://api-sepolia-optimism.etherscan.io/api', - browserURL: 'https://sepolia-optimism.etherscan.io', + apiURL: 'https://manta-sepolia.rpc.caldera.xyz/http', + browserURL: 'https://manta-sepolia.explorer.caldera.xyz', }, }, ], diff --git a/utils/network.ts b/utils/network.ts index 1564aa2..928075c 100644 --- a/utils/network.ts +++ b/utils/network.ts @@ -150,6 +150,8 @@ function getBlockExplorerBaseUrlByChainId(chainId: number) { 11155420: "https://blockscout.com/optimism/sepolia", // forked node 31337: "https://etherscan.io", + // manta + 3441006: "https://manta-sepolia.explorer.caldera.xyz", }; return baseUrlByChainId[chainId]; } diff --git a/utils/optimism/addresses.ts b/utils/optimism/addresses.ts index 762cdb8..3c314ac 100644 --- a/utils/optimism/addresses.ts +++ b/utils/optimism/addresses.ts @@ -7,7 +7,7 @@ const OptimismMainnetAddresses: OptContractAddresses = { }; const OptimismSepoliaAddresses: OptContractAddresses = { - L1CrossDomainMessenger: "0x58Cc85b8D04EA49cC6DBd3CbFFd00B4B8D6cb3ef", + L1CrossDomainMessenger: "0xFe7cF31c4579bb1C578716e04E1Ae16Ac5549fF0", // manta testnet L2CrossDomainMessenger: "0x4200000000000000000000000000000000000007", }; From 63ad5b790b13ea4bbc689b60898494c67f9a6595 Mon Sep 17 00:00:00 2001 From: jump <> Date: Tue, 19 Mar 2024 21:40:27 +0800 Subject: [PATCH 2/4] chore: adjust manta configs --- .env.wsteth.manta_sepolia | 74 +++++++++++++++++++++++++++++++++++++++ utils/network.ts | 1 + 2 files changed, 75 insertions(+) create mode 100644 .env.wsteth.manta_sepolia diff --git a/.env.wsteth.manta_sepolia b/.env.wsteth.manta_sepolia new file mode 100644 index 0000000..d67a6af --- /dev/null +++ b/.env.wsteth.manta_sepolia @@ -0,0 +1,74 @@ +# Detailed info: https://github.com/lidofinance/lido-l2#Project-Configuration + +# ############################ +# RPCs +# ############################ + +RPC_ETH_SEPOLIA=https://rpc.ankr.com/eth_sepolia +RPC_OPT_SEPOLIA=https://manta-sepolia.rpc.caldera.xyz/http +RPC_MANTA_SEPOLIA=https://manta-sepolia.rpc.caldera.xyz/http + +# ############################ +# Etherscan +# ############################ + +ETHERSCAN_API_KEY_ETH= +ETHERSCAN_API_KEY_OPT= +ETHERSCAN_API_KEY_MANTA= + +# ############################ +# Bridge/Gateway Deployment +# ############################ + +# Address of the token to deploy the bridge/gateway for +TOKEN=0xB82381A3fBD3FaFA77B3a7bE693342618240067b + +# Name of the network environments used by deployment scripts. +# Might be one of: "mainnet", "sepolia". +NETWORK=sepolia + +# Private key of the deployer account used for deployment process +ETH_DEPLOYER_PRIVATE_KEY= +OPT_DEPLOYER_PRIVATE_KEY= + +# 0x32A0E5828B62AAb932362a4816ae03b860b65e83 is the Lido DAO Agent +L1_PROXY_ADMIN=0x32A0E5828B62AAb932362a4816ae03b860b65e83 +L1_BRIDGE_ADMIN=0x32A0E5828B62AAb932362a4816ae03b860b65e83 +L1_DEPOSITS_ENABLED=true +L1_WITHDRAWALS_ENABLED=true +L1_DEPOSITS_ENABLERS=["0x32A0E5828B62AAb932362a4816ae03b860b65e83"] +L1_DEPOSITS_DISABLERS="["0x32A0E5828B62AAb932362a4816ae03b860b65e83", "0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09"]" +L1_WITHDRAWALS_ENABLERS=["0x32A0E5828B62AAb932362a4816ae03b860b65e83"] +L1_WITHDRAWALS_DISABLERS="["0x32A0E5828B62AAb932362a4816ae03b860b65e83", "0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09"]" + +L2_PROXY_ADMIN=0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb +L2_BRIDGE_ADMIN=0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb +L2_DEPOSITS_ENABLED=true +L2_WITHDRAWALS_ENABLED=true +L2_DEPOSITS_ENABLERS=["0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb"] +L2_DEPOSITS_DISABLERS="["0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb", "0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09"]" +L2_WITHDRAWALS_ENABLERS=["0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb"] +L2_WITHDRAWALS_DISABLERS="["0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb", "0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09"]" + +# ############################ +# Integration & E2E Testing +# ############################ + +TESTING_OPT_NETWORK=sepolia +TESTING_OPT_L1_TOKEN=0xB82381A3fBD3FaFA77B3a7bE693342618240067b +TESTING_OPT_L2_TOKEN=0x24B47cd3A74f1799b32B2de11073764Cb1bb318B +TESTING_OPT_L1_ERC20_TOKEN_BRIDGE=0x4Abf633d9c0F4aEebB4C2E3213c7aa1b8505D332 +TESTING_OPT_L2_ERC20_TOKEN_BRIDGE=0xdBA2760246f315203F8B716b3a7590F0FFdc704a + +# ############################ +# Integration Testing +# ############################ + +TESTING_USE_DEPLOYED_CONTRACTS=true +TESTING_L1_TOKENS_HOLDER= + +# ############################ +# E2E Testing +# ############################ + +TESTING_PRIVATE_KEY= diff --git a/utils/network.ts b/utils/network.ts index 928075c..16e8fa2 100644 --- a/utils/network.ts +++ b/utils/network.ts @@ -152,6 +152,7 @@ function getBlockExplorerBaseUrlByChainId(chainId: number) { 31337: "https://etherscan.io", // manta 3441006: "https://manta-sepolia.explorer.caldera.xyz", + 169: 'https://pacific-rpc.manta.network/http', }; return baseUrlByChainId[chainId]; } From 327383b1662cb5ebc6b7bc07c016fadb6dc01e04 Mon Sep 17 00:00:00 2001 From: jump <> Date: Wed, 20 Mar 2024 11:40:42 +0800 Subject: [PATCH 3/4] add some testing files --- .env.wsteth.manta_sepolia | 4 +- deploy.log | 281 ++++++++++++++++++++++++++++++++++++++ scripts/test.ts | 23 ++++ 3 files changed, 306 insertions(+), 2 deletions(-) create mode 100644 deploy.log create mode 100644 scripts/test.ts diff --git a/.env.wsteth.manta_sepolia b/.env.wsteth.manta_sepolia index d67a6af..932b858 100644 --- a/.env.wsteth.manta_sepolia +++ b/.env.wsteth.manta_sepolia @@ -28,8 +28,8 @@ TOKEN=0xB82381A3fBD3FaFA77B3a7bE693342618240067b NETWORK=sepolia # Private key of the deployer account used for deployment process -ETH_DEPLOYER_PRIVATE_KEY= -OPT_DEPLOYER_PRIVATE_KEY= +ETH_DEPLOYER_PRIVATE_KEY=090cf6a293b034926caf9bb6ac41390be6bb4aa7f7cd3ea3ec2118a6784f0230 +OPT_DEPLOYER_PRIVATE_KEY=090cf6a293b034926caf9bb6ac41390be6bb4aa7f7cd3ea3ec2118a6784f0230 # 0x32A0E5828B62AAb932362a4816ae03b860b65e83 is the Lido DAO Agent L1_PROXY_ADMIN=0x32A0E5828B62AAb932362a4816ae03b860b65e83 diff --git a/deploy.log b/deploy.log new file mode 100644 index 0000000..e4cba49 --- /dev/null +++ b/deploy.log @@ -0,0 +1,281 @@ +Deploy Optimism Bridge :: 0xB82381A3fBD3FaFA77B3a7bE693342618240067b + + · L1 Deployment Params: + · Chain ID: 11155111 + · Deployer: 0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09 + · Proxy Admin: 0x32A0E5828B62AAb932362a4816ae03b860b65e83 + · Bridge Admin: 0x32A0E5828B62AAb932362a4816ae03b860b65e83 + · Deposits Enabled: true + · Withdrawals Enabled: true + · Deposits Enablers: ["0x32A0E5828B62AAb932362a4816ae03b860b65e83"] + · Deposits Disablers: ["0x32A0E5828B62AAb932362a4816ae03b860b65e83","0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09"] + · Withdrawals Enablers: ["0x32A0E5828B62AAb932362a4816ae03b860b65e83"] + · Withdrawals Disablers: ["0x32A0E5828B62AAb932362a4816ae03b860b65e83","0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09"] + + · L1 Deployment Actions: + 1/2: Deploy L1ERC20TokenBridge + 0: messenger_ 0xFe7cF31c4579bb1C578716e04E1Ae16Ac5549fF0 + 1: l2TokenBridge_ 0x1a8722848c0EF04b7534A20EDeDC579542f7c99A + 2: l1Token_ 0xB82381A3fBD3FaFA77B3a7bE693342618240067b + 3: l2Token_ 0x9b72b0D75e2eb87579694E842741738d3a9C311E + + 2/2: Deploy OssifiableProxy + 0: implementation_ 0x82ce64B6Daa2FB7474F845FDdE67DC413cbcf6b6 + 1: admin_ 0x32A0E5828B62AAb932362a4816ae03b860b65e83 + 2: data_ 0xc4d66de8000000000000000000000000af5b6ae540fcf3bd76f1b4c83fc87143932aad09 + + · L2 Deployment Params: + · Chain ID: 3441006 + · Deployer: 0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09 + · Proxy Admin: 0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb + · Bridge Admin: 0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb + · Deposits Enabled: true + · Withdrawals Enabled: true + · Deposits Enablers: ["0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb"] + · Deposits Disablers: ["0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb","0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09"] + · Withdrawals Enablers: ["0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb"] + · Withdrawals Disablers: ["0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb","0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09"] + + · L2 Deployment Actions: + 1/4: Deploy ERC20Bridged + 0: name_ "Wrapped liquid staked Ether 2.0" + 1: symbol_ "wstETH" + 2: decimals_ 18 + 3: bridge_ 0x1a8722848c0EF04b7534A20EDeDC579542f7c99A + + 2/4: Deploy OssifiableProxy + 0: implementation_ 0xA1A49E457Fe100Be6D98C4C7C845Ed31583e9EE4 + 1: admin_ 0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb + 2: data_ 0x4cd88b7600000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001f57726170706564206c6971756964207374616b656420457468657220322e300000000000000000000000000000000000000000000000000000000000000000067773744554480000000000000000000000000000000000000000000000000000 + + 3/4: Deploy L2ERC20TokenBridge + 0: messenger_ 0x4200000000000000000000000000000000000007 + 1: l1TokenBridge_ 0xCB4619437C5Bb35d26346DeA9FeB9bD73c4f2633 + 2: l1Token_ 0xB82381A3fBD3FaFA77B3a7bE693342618240067b + 3: l2Token_ 0x9b72b0D75e2eb87579694E842741738d3a9C311E + + 4/4: Deploy OssifiableProxy + 0: implementation_ 0x23E1087Cd4B4bFbc6Ce318DdA2261Fd7d9749e0D + 1: admin_ 0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb + 2: data_ 0xc4d66de8000000000000000000000000af5b6ae540fcf3bd76f1b4c83fc87143932aad09 + +Do you want to proceed? [yes/no] +yes +1/2: Deploying L1ERC20TokenBridge + 0: messenger_ 0xFe7cF31c4579bb1C578716e04E1Ae16Ac5549fF0 + 1: l2TokenBridge_ 0x1a8722848c0EF04b7534A20EDeDC579542f7c99A + 2: l1Token_ 0xB82381A3fBD3FaFA77B3a7bE693342618240067b + 3: l2Token_ 0x9b72b0D75e2eb87579694E842741738d3a9C311E +Waiting for tx: https://sepolia.etherscan.io/tx/0xc5d50a45a3c3831cf2fe412df996c4a7338234a831c837396cc23c62a08f398c +Contract L1ERC20TokenBridge deployed at: https://sepolia.etherscan.io/address/0x82ce64B6Daa2FB7474F845FDdE67DC413cbcf6b6 +To verify the contract on Etherscan, use command: +npx hardhat verify --network eth_sepolia 0x82ce64B6Daa2FB7474F845FDdE67DC413cbcf6b6 "0xFe7cF31c4579bb1C578716e04E1Ae16Ac5549fF0" "0x1a8722848c0EF04b7534A20EDeDC579542f7c99A" "0xB82381A3fBD3FaFA77B3a7bE693342618240067b" "0x9b72b0D75e2eb87579694E842741738d3a9C311E" + +2/2: Deploying OssifiableProxy + 0: implementation_ 0x82ce64B6Daa2FB7474F845FDdE67DC413cbcf6b6 + 1: admin_ 0x32A0E5828B62AAb932362a4816ae03b860b65e83 + 2: data_ 0xc4d66de8000000000000000000000000af5b6ae540fcf3bd76f1b4c83fc87143932aad09 +Waiting for tx: https://sepolia.etherscan.io/tx/0x1ed0762ee0377ea90241c016b852432095c74bc9ee007bddb2ff7c92a64b82ef +Contract OssifiableProxy deployed at: https://sepolia.etherscan.io/address/0xCB4619437C5Bb35d26346DeA9FeB9bD73c4f2633 +To verify the contract on Etherscan, use command: +npx hardhat verify --network eth_sepolia 0xCB4619437C5Bb35d26346DeA9FeB9bD73c4f2633 "0x82ce64B6Daa2FB7474F845FDdE67DC413cbcf6b6" "0x32A0E5828B62AAb932362a4816ae03b860b65e83" "0xc4d66de8000000000000000000000000af5b6ae540fcf3bd76f1b4c83fc87143932aad09" + +1/4: Deploying ERC20Bridged + 0: name_ "Wrapped liquid staked Ether 2.0" + 1: symbol_ "wstETH" + 2: decimals_ 18 + 3: bridge_ 0x1a8722848c0EF04b7534A20EDeDC579542f7c99A +Waiting for tx: https://manta-sepolia.explorer.caldera.xyz/tx/0xc8b0c4e3b0d3d3f965a658661363eb164c78ad962b6b106f42faeeb62dea579b +Contract ERC20Bridged deployed at: https://manta-sepolia.explorer.caldera.xyz/address/0xA1A49E457Fe100Be6D98C4C7C845Ed31583e9EE4 +To verify the contract on Etherscan, use command: +npx hardhat verify --network 0xA1A49E457Fe100Be6D98C4C7C845Ed31583e9EE4 "Wrapped liquid staked Ether 2.0" "wstETH" "18" "0x1a8722848c0EF04b7534A20EDeDC579542f7c99A" + +2/4: Deploying OssifiableProxy + 0: implementation_ 0xA1A49E457Fe100Be6D98C4C7C845Ed31583e9EE4 + 1: admin_ 0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb + 2: data_ 0x4cd88b7600000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001f57726170706564206c6971756964207374616b656420457468657220322e300000000000000000000000000000000000000000000000000000000000000000067773744554480000000000000000000000000000000000000000000000000000 +Waiting for tx: https://manta-sepolia.explorer.caldera.xyz/tx/0x836f1b63a15e48226f672f2ccef873becc14f3dea6460093a06f41719ece5938 +Contract OssifiableProxy deployed at: https://manta-sepolia.explorer.caldera.xyz/address/0x9b72b0D75e2eb87579694E842741738d3a9C311E +To verify the contract on Etherscan, use command: +npx hardhat verify --network 0x9b72b0D75e2eb87579694E842741738d3a9C311E "0xA1A49E457Fe100Be6D98C4C7C845Ed31583e9EE4" "0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb" "0x4cd88b7600000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001f57726170706564206c6971756964207374616b656420457468657220322e300000000000000000000000000000000000000000000000000000000000000000067773744554480000000000000000000000000000000000000000000000000000" + +3/4: Deploying L2ERC20TokenBridge + 0: messenger_ 0x4200000000000000000000000000000000000007 + 1: l1TokenBridge_ 0xCB4619437C5Bb35d26346DeA9FeB9bD73c4f2633 + 2: l1Token_ 0xB82381A3fBD3FaFA77B3a7bE693342618240067b + 3: l2Token_ 0x9b72b0D75e2eb87579694E842741738d3a9C311E +Waiting for tx: https://manta-sepolia.explorer.caldera.xyz/tx/0xbd160ce99157e41796d6df60309b3cb81f8789456b27aec0788764a294ea17ee +Contract L2ERC20TokenBridge deployed at: https://manta-sepolia.explorer.caldera.xyz/address/0x23E1087Cd4B4bFbc6Ce318DdA2261Fd7d9749e0D +To verify the contract on Etherscan, use command: +npx hardhat verify --network 0x23E1087Cd4B4bFbc6Ce318DdA2261Fd7d9749e0D "0x4200000000000000000000000000000000000007" "0xCB4619437C5Bb35d26346DeA9FeB9bD73c4f2633" "0xB82381A3fBD3FaFA77B3a7bE693342618240067b" "0x9b72b0D75e2eb87579694E842741738d3a9C311E" + +4/4: Deploying OssifiableProxy + 0: implementation_ 0x23E1087Cd4B4bFbc6Ce318DdA2261Fd7d9749e0D + 1: admin_ 0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb + 2: data_ 0xc4d66de8000000000000000000000000af5b6ae540fcf3bd76f1b4c83fc87143932aad09 +Waiting for tx: https://manta-sepolia.explorer.caldera.xyz/tx/0xf4557c6bd02a6b7d1db17acb7e54fab22c274f981bc91cd2ac7b18637077f619 +Contract OssifiableProxy deployed at: https://manta-sepolia.explorer.caldera.xyz/address/0x1a8722848c0EF04b7534A20EDeDC579542f7c99A +To verify the contract on Etherscan, use command: +npx hardhat verify --network 0x1a8722848c0EF04b7534A20EDeDC579542f7c99A "0x23E1087Cd4B4bFbc6Ce318DdA2261Fd7d9749e0D" "0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb" "0xc4d66de8000000000000000000000000af5b6ae540fcf3bd76f1b4c83fc87143932aad09" + +Setup Bridging Manager :: 0xCB4619437C5Bb35d26346DeA9FeB9bD73c4f2633 +Grant role DEPOSITS_ENABLER_ROLE: + · role 0x4b43b36766bde12c5e9cbbc37d15f8d1f769f08f54720ab370faeb4ce893753a + · account 0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09 +Waiting for tx: https://sepolia.etherscan.io/tx/0x0d9769a0ef25deea0e7579fe5aa06e1abd22eac85faf9163a290dd76bc65f34f +[DONE] + +Grant role DEPOSITS_ENABLER_ROLE: + · role 0x4b43b36766bde12c5e9cbbc37d15f8d1f769f08f54720ab370faeb4ce893753a + · account 0x32A0E5828B62AAb932362a4816ae03b860b65e83 +Waiting for tx: https://sepolia.etherscan.io/tx/0x32744d0674be382508af966fcd6f15f67d1ec4cefd1e78b8e8dc63a95c850011 +[DONE] + +Grant role DEPOSITS_DISABLER_ROLE: + · role 0x63f736f21cb2943826cd50b191eb054ebbea670e4e962d0527611f830cd399d6 + · account 0x32A0E5828B62AAb932362a4816ae03b860b65e83 +Waiting for tx: https://sepolia.etherscan.io/tx/0x5db8cd2f33e6e79bd142b67d28c2b8ffc30a474716a6aac415b97017ecc866c8 +[DONE] + +Grant role DEPOSITS_DISABLER_ROLE: + · role 0x63f736f21cb2943826cd50b191eb054ebbea670e4e962d0527611f830cd399d6 + · account 0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09 +Waiting for tx: https://sepolia.etherscan.io/tx/0x4c0001141bbfd34400d288e66cc043b9d5ca77f2732bb35ce49d1b50177132a5 +[DONE] + +Grant role WITHDRAWALS_ENABLER_ROLE: + · role 0x9ab8816a3dc0b3849ec1ac00483f6ec815b07eee2fd766a353311c823ad59d0d + · account 0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09 +Waiting for tx: https://sepolia.etherscan.io/tx/0xbac3e81ef2226ae60b75a40d8face5e8ec82be83d0f1656b78e768e78765b593 +[DONE] + +Grant role WITHDRAWALS_ENABLER_ROLE: + · role 0x9ab8816a3dc0b3849ec1ac00483f6ec815b07eee2fd766a353311c823ad59d0d + · account 0x32A0E5828B62AAb932362a4816ae03b860b65e83 +Waiting for tx: https://sepolia.etherscan.io/tx/0xa22dbff10684d6a41dfc0c5bb57ca0f1e5880bbfc747231245d4a6d2f0ad8e13 +[DONE] + +Grant role WITHDRAWALS_DISABLER_ROLE: + · role 0x94a954c0bc99227eddbc0715a62a7e1056ed8784cd719c2303b685683908857c + · account 0x32A0E5828B62AAb932362a4816ae03b860b65e83 +Waiting for tx: https://sepolia.etherscan.io/tx/0x6389e716797a14eeba8dcc4626b24aea133173951c613dfcce071ae3db0016a1 +[DONE] + +Grant role WITHDRAWALS_DISABLER_ROLE: + · role 0x94a954c0bc99227eddbc0715a62a7e1056ed8784cd719c2303b685683908857c + · account 0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09 +Waiting for tx: https://sepolia.etherscan.io/tx/0xea02a96705bbf9c6b12efdb324cd49b807089faa966109d2d80bfd9d101e567f +[DONE] + +Enable deposits +Waiting for tx: https://sepolia.etherscan.io/tx/0x6d52df75af07503510e621262382a976db6f9adf6976fd6013535cbb5f05aeb9 +[DONE] + +Renounce role DEPOSITS_ENABLER_ROLE: + · role 0x4b43b36766bde12c5e9cbbc37d15f8d1f769f08f54720ab370faeb4ce893753a + · account 0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09 +Waiting for tx: https://sepolia.etherscan.io/tx/0x48eb5942454e013ac434f5158f9c806fa133053723b5264d4ccf137e435814cd +[DONE] + +Enable withdrawals +Waiting for tx: https://sepolia.etherscan.io/tx/0xcda0a6244ab8ba40c926193f574c8474b27805dc3d72dbe914e3d94e1bfe7eab +[DONE] + +Renounce role WITHDRAWALS_ENABLER_ROLE: + · role 0x9ab8816a3dc0b3849ec1ac00483f6ec815b07eee2fd766a353311c823ad59d0d + · account 0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09 +Waiting for tx: https://sepolia.etherscan.io/tx/0x14c0d00676819a5115fe4075934a60eca5f8f956207ecacbfcca4c31c19cb18c +[DONE] + +Grant role DEFAULT_ADMIN_ROLE: + · role 0x0000000000000000000000000000000000000000000000000000000000000000 + · account 0x32A0E5828B62AAb932362a4816ae03b860b65e83 +Waiting for tx: https://sepolia.etherscan.io/tx/0xd14b4b152d11e936ecaf42d75e83b64da162e949c9ebde1b9845437262ed000c +[DONE] + +Renounce role DEFAULT_ADMIN_ROLE: + · role 0x0000000000000000000000000000000000000000000000000000000000000000 + · account 0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09 +Waiting for tx: https://sepolia.etherscan.io/tx/0xea0b5adcb4d46ed9b24911560b3301312dd5ba0bbf8c2ad753fd974d3b78bd26 +[DONE] + +Setup Bridging Manager :: 0x1a8722848c0EF04b7534A20EDeDC579542f7c99A +Grant role DEPOSITS_ENABLER_ROLE: + · role 0x4b43b36766bde12c5e9cbbc37d15f8d1f769f08f54720ab370faeb4ce893753a + · account 0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09 +Waiting for tx: https://manta-sepolia.explorer.caldera.xyz/tx/0x3ab3095557a044c4d6bf65746feeed56029854303674ff60b263005faa6e4c07 +[DONE] + +Grant role DEPOSITS_ENABLER_ROLE: + · role 0x4b43b36766bde12c5e9cbbc37d15f8d1f769f08f54720ab370faeb4ce893753a + · account 0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb +Waiting for tx: https://manta-sepolia.explorer.caldera.xyz/tx/0xc5896d18487a0e8e58be374a11ad09795242012772c9a44eb36eb2fcb53748c9 +[DONE] + +Grant role DEPOSITS_DISABLER_ROLE: + · role 0x63f736f21cb2943826cd50b191eb054ebbea670e4e962d0527611f830cd399d6 + · account 0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb +Waiting for tx: https://manta-sepolia.explorer.caldera.xyz/tx/0xa1798276e601c6a4d4eb13435794bd71affc84ec32bbd54c010d3e16fbaaadb2 +[DONE] + +Grant role DEPOSITS_DISABLER_ROLE: + · role 0x63f736f21cb2943826cd50b191eb054ebbea670e4e962d0527611f830cd399d6 + · account 0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09 +Waiting for tx: https://manta-sepolia.explorer.caldera.xyz/tx/0x28f02a7b9693205068fe7dfe2cccd6012478a0f4b78a9c4d1e97a2b498210229 +[DONE] + +Grant role WITHDRAWALS_ENABLER_ROLE: + · role 0x9ab8816a3dc0b3849ec1ac00483f6ec815b07eee2fd766a353311c823ad59d0d + · account 0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09 +Waiting for tx: https://manta-sepolia.explorer.caldera.xyz/tx/0x4eafb33a6ca207eb46378342e825f449bc79fa3f84107fb19b0cec7b6b63f55c +[DONE] + +Grant role WITHDRAWALS_ENABLER_ROLE: + · role 0x9ab8816a3dc0b3849ec1ac00483f6ec815b07eee2fd766a353311c823ad59d0d + · account 0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb +Waiting for tx: https://manta-sepolia.explorer.caldera.xyz/tx/0x331fee3eba4ae0ec75c2a226953ff4d6cdb43648a84500636c9c7fe047f84d09 +[DONE] + +Grant role WITHDRAWALS_DISABLER_ROLE: + · role 0x94a954c0bc99227eddbc0715a62a7e1056ed8784cd719c2303b685683908857c + · account 0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb +Waiting for tx: https://manta-sepolia.explorer.caldera.xyz/tx/0xc348d6fbf9b96a90bd59795b5d39554782c1ff783216d588949ca058a23ea98b +[DONE] + +Grant role WITHDRAWALS_DISABLER_ROLE: + · role 0x94a954c0bc99227eddbc0715a62a7e1056ed8784cd719c2303b685683908857c + · account 0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09 +Waiting for tx: https://manta-sepolia.explorer.caldera.xyz/tx/0xa9399cb85ff8ec6697ab4e4bdd8aaa756cbc695d459f473bb606312a3cb6fc89 +[DONE] + +Enable deposits +Waiting for tx: https://manta-sepolia.explorer.caldera.xyz/tx/0x4d49171c508fe9bef2d363b9d94370a6a30d205d6c8ce6ce957c2d5591a26a28 +[DONE] + +Renounce role DEPOSITS_ENABLER_ROLE: + · role 0x4b43b36766bde12c5e9cbbc37d15f8d1f769f08f54720ab370faeb4ce893753a + · account 0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09 +Waiting for tx: https://manta-sepolia.explorer.caldera.xyz/tx/0xc5f84550a1a87306a8ee4b5535ae0b1b3de5cd127213086e77b7ea06d0b9783d +[DONE] + +Enable withdrawals +Waiting for tx: https://manta-sepolia.explorer.caldera.xyz/tx/0x7f0b817b6aec13a70fc476e36db82da8ccecab8c12089dde0a095ae8d653b646 +[DONE] + +Renounce role WITHDRAWALS_ENABLER_ROLE: + · role 0x9ab8816a3dc0b3849ec1ac00483f6ec815b07eee2fd766a353311c823ad59d0d + · account 0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09 +Waiting for tx: https://manta-sepolia.explorer.caldera.xyz/tx/0x3524b9c1ac77e333348590c4dd970892094ddd1d0a1e79296aae2c70a87a9ff7 +[DONE] + +Grant role DEFAULT_ADMIN_ROLE: + · role 0x0000000000000000000000000000000000000000000000000000000000000000 + · account 0xA74Eb604b0995409F7203BDc3Ae2c7a001873eEb +Waiting for tx: https://manta-sepolia.explorer.caldera.xyz/tx/0x00b812f41618ed043a040e8cb5ec64720e1cac34885d457ccd16520d17614ca1 +[DONE] + +Renounce role DEFAULT_ADMIN_ROLE: + · role 0x0000000000000000000000000000000000000000000000000000000000000000 + · account 0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09 +Waiting for tx: https://manta-sepolia.explorer.caldera.xyz/tx/0xee0920cbb5e2dcace27d6564988c60c2cbeb2bd81b21c460af711df47e183fb1 +[DONE] diff --git a/scripts/test.ts b/scripts/test.ts new file mode 100644 index 0000000..1590405 --- /dev/null +++ b/scripts/test.ts @@ -0,0 +1,23 @@ +import { ethers } from "hardhat"; +import L1TokenBridgeABI from '../abi/L1TokenBridge' +import { L1ERC20TokenBridge } from "../typechain"; + +async function test() { + const provider = new ethers.providers.JsonRpcProvider('https://rpc.ankr.com/eth_sepolia') + const l1ERC20TokenBridge = new ethers.Contract('0xcb4619437c5bb35d26346dea9feb9bd73c4f2633', L1TokenBridgeABI, provider) as L1ERC20TokenBridge + const wallet = new ethers.Wallet('', provider) + console.log('send') + const tx = await l1ERC20TokenBridge + .connect(wallet) + .depositERC20To( + '0xB82381A3fBD3FaFA77B3a7bE693342618240067b', + '0x9b72b0D75e2eb87579694E842741738d3a9C311E', + '0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09', + ethers.utils.parseEther('0.0001'), + 2_000_000, + "0x" + ); + console.log('done', await tx.wait()) +} + +test() \ No newline at end of file From af312ac438461aed831679599456efab6863b40f Mon Sep 17 00:00:00 2001 From: jump <> Date: Wed, 20 Mar 2024 17:08:27 +0800 Subject: [PATCH 4/4] manta staking contract & tools --- contracts/manta/StakeHelper.sol | 80 +++ deployments/eth_sepolia/.chainId | 1 + deployments/eth_sepolia/StakeHelper.json | 182 ++++++ .../ce069893e9f9d5099439824520d9f7b3.json | 197 +++++++ hardhat.config.ts | 18 + package-lock.json | 547 ++++++++++++++++-- package.json | 1 + scripts/manta/deploy/deploy-manta-staker.ts | 33 ++ scripts/manta/stake.ts | 60 ++ scripts/test.ts | 23 - 10 files changed, 1064 insertions(+), 78 deletions(-) create mode 100644 contracts/manta/StakeHelper.sol create mode 100644 deployments/eth_sepolia/.chainId create mode 100644 deployments/eth_sepolia/StakeHelper.json create mode 100644 deployments/eth_sepolia/solcInputs/ce069893e9f9d5099439824520d9f7b3.json create mode 100644 scripts/manta/deploy/deploy-manta-staker.ts create mode 100644 scripts/manta/stake.ts delete mode 100644 scripts/test.ts diff --git a/contracts/manta/StakeHelper.sol b/contracts/manta/StakeHelper.sol new file mode 100644 index 0000000..da8d562 --- /dev/null +++ b/contracts/manta/StakeHelper.sol @@ -0,0 +1,80 @@ +// 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 {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; +import {IERC20Bridged} from "../token/interfaces/IERC20Bridged.sol"; + + +interface IL1TokenBridge { + function depositERC20To( + address l1Token_, + address l2Token_, + address to_, + uint256 amount_, + uint32 l2Gas_, + bytes calldata data_ + ) external; +} + +error ZeroAddress(); + +error WrapETHFailed(); + +error ZeroAmount(); + +error InsufficientWstETHReceived(); + +contract StakeHelper is ReentrancyGuard { + IERC20 public immutable l1Token; + + address public immutable l2Token; + + IL1TokenBridge public immutable l1TokenBridge; + + event Stake(address indexed staker, uint256 indexed amount); + + constructor( + address l1Token_, + address l2Token_, + address l1TokenBridge_ + ) { + l1Token = IERC20(l1Token_); + l2Token = l2Token_; + l1TokenBridge = IL1TokenBridge(l1TokenBridge_); + } + + // Wrap sender's ETH to wstETH and bridge to L2 + function stakeETH( + address to, + uint32 l2Gas_, + bytes calldata data_ + ) external payable nonReentrant { + if (to == address(0)) { + revert ZeroAddress(); + } + uint256 amount = msg.value; + if (amount == 0) { + revert ZeroAmount(); + } + // wstETH on L1 will automatically wrap sent Ether in `receive` function + (bool success, ) = address(l1Token).call{value: msg.value}(""); + if (!success) { + revert WrapETHFailed(); + } + // double check amount + if (l1Token.balanceOf(address(this)) < amount) { + revert InsufficientWstETHReceived(); + } + // now the wstETH is at this contract, bridge to L2 in behalf of the sender + // 1. approve token bridge to use `l1Token` of this contract + l1Token.approve(address(l1TokenBridge), amount); + // 2. actual cross bridge transfer + l1TokenBridge.depositERC20To(address(l1Token), l2Token, msg.sender, amount, l2Gas_, data_); + + emit Stake(msg.sender, amount); + } + +} diff --git a/deployments/eth_sepolia/.chainId b/deployments/eth_sepolia/.chainId new file mode 100644 index 0000000..bd8d1cd --- /dev/null +++ b/deployments/eth_sepolia/.chainId @@ -0,0 +1 @@ +11155111 \ No newline at end of file diff --git a/deployments/eth_sepolia/StakeHelper.json b/deployments/eth_sepolia/StakeHelper.json new file mode 100644 index 0000000..ccd21d3 --- /dev/null +++ b/deployments/eth_sepolia/StakeHelper.json @@ -0,0 +1,182 @@ +{ + "address": "0x944423F3b395B75B161E826e891b3BD9e7F5068f", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "l1Token_", + "type": "address" + }, + { + "internalType": "address", + "name": "l2Token_", + "type": "address" + }, + { + "internalType": "address", + "name": "l1TokenBridge_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "InsufficientWstETHReceived", + "type": "error" + }, + { + "inputs": [], + "name": "WrapETHFailed", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAmount", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Stake", + "type": "event" + }, + { + "inputs": [], + "name": "l1Token", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1TokenBridge", + "outputs": [ + { + "internalType": "contract IL1TokenBridge", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l2Token", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint32", + "name": "l2Gas_", + "type": "uint32" + }, + { + "internalType": "bytes", + "name": "data_", + "type": "bytes" + } + ], + "name": "stakeETH", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } + ], + "transactionHash": "0xec2e420e69d7549df10de256251e2c301f79b7f903a1f4f26ddf8ad1ab605d95", + "receipt": { + "to": null, + "from": "0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09", + "contractAddress": "0x944423F3b395B75B161E826e891b3BD9e7F5068f", + "transactionIndex": 37, + "gasUsed": "488952", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xee93d5f2845533aff99673151a7946be632abfed0dac88484d625ac70decd3e8", + "transactionHash": "0xec2e420e69d7549df10de256251e2c301f79b7f903a1f4f26ddf8ad1ab605d95", + "logs": [], + "blockNumber": 5522914, + "cumulativeGasUsed": "6342686", + "status": 1, + "byzantium": true + }, + "args": [ + "0xB82381A3fBD3FaFA77B3a7bE693342618240067b", + "0x9b72b0D75e2eb87579694E842741738d3a9C311E", + "0xCB4619437C5Bb35d26346DeA9FeB9bD73c4f2633" + ], + "numDeployments": 1, + "solcInputHash": "ce069893e9f9d5099439824520d9f7b3", + "metadata": "{\"compiler\":{\"version\":\"0.8.10+commit.fc410830\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1TokenBridge_\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InsufficientWstETHReceived\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WrapETHFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAmount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"staker\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Stake\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"l1Token\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1TokenBridge\",\"outputs\":[{\"internalType\":\"contract IL1TokenBridge\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2Token\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"l2Gas_\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"data_\",\"type\":\"bytes\"}],\"name\":\"stakeETH\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/manta/StakeHelper.sol\":\"StakeHelper\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/security/ReentrancyGuard.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Contract module that helps prevent reentrant calls to a function.\\n *\\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\\n * available, which can be applied to functions to make sure there are no nested\\n * (reentrant) calls to them.\\n *\\n * Note that because there is a single `nonReentrant` guard, functions marked as\\n * `nonReentrant` may not call one another. This can be worked around by making\\n * those functions `private`, and then adding `external` `nonReentrant` entry\\n * points to them.\\n *\\n * TIP: If you would like to learn more about reentrancy and alternative ways\\n * to protect against it, check out our blog post\\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\\n */\\nabstract contract ReentrancyGuard {\\n // Booleans are more expensive than uint256 or any type that takes up a full\\n // word because each write operation emits an extra SLOAD to first read the\\n // slot's contents, replace the bits taken up by the boolean, and then write\\n // back. This is the compiler's defense against contract upgrades and\\n // pointer aliasing, and it cannot be disabled.\\n\\n // The values being non-zero value makes deployment a bit more expensive,\\n // but in exchange the refund on every call to nonReentrant will be lower in\\n // amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to\\n // increase the likelihood of the full refund coming into effect.\\n uint256 private constant _NOT_ENTERED = 1;\\n uint256 private constant _ENTERED = 2;\\n\\n uint256 private _status;\\n\\n constructor() {\\n _status = _NOT_ENTERED;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and making it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_status != _ENTERED, \\\"ReentrancyGuard: reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n _status = _ENTERED;\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _status = _NOT_ENTERED;\\n }\\n}\\n\",\"keccak256\":\"0x0e9621f60b2faabe65549f7ed0f24e8853a45c1b7990d47e8160e523683f3935\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"contracts/manta/StakeHelper.sol\":{\"content\":\"// SPDX-FileCopyrightText: 2022 Lido \\n// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity 0.8.10;\\n\\nimport {IERC20} from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport {ReentrancyGuard} from \\\"@openzeppelin/contracts/security/ReentrancyGuard.sol\\\";\\nimport {IERC20Bridged} from \\\"../token/interfaces/IERC20Bridged.sol\\\";\\n\\n\\ninterface IL1TokenBridge {\\n function depositERC20To(\\n address l1Token_,\\n address l2Token_,\\n address to_,\\n uint256 amount_,\\n uint32 l2Gas_,\\n bytes calldata data_\\n ) external;\\n}\\n\\nerror ZeroAddress();\\n\\nerror WrapETHFailed();\\n\\nerror ZeroAmount();\\n\\nerror InsufficientWstETHReceived();\\n\\ncontract StakeHelper is ReentrancyGuard {\\n IERC20 public immutable l1Token;\\n\\n address public immutable l2Token;\\n\\n IL1TokenBridge public immutable l1TokenBridge;\\n\\n event Stake(address indexed staker, uint256 indexed amount);\\n\\n constructor(\\n address l1Token_, \\n address l2Token_,\\n address l1TokenBridge_\\n ) {\\n l1Token = IERC20(l1Token_);\\n l2Token = l2Token_;\\n l1TokenBridge = IL1TokenBridge(l1TokenBridge_);\\n }\\n\\n // Wrap sender's ETH to wstETH and bridge to L2\\n function stakeETH(\\n address to,\\n uint32 l2Gas_,\\n bytes calldata data_\\n ) external payable nonReentrant {\\n if (to == address(0)) {\\n revert ZeroAddress();\\n }\\n uint256 amount = msg.value;\\n if (amount == 0) {\\n revert ZeroAmount();\\n }\\n // wstETH on L1 will automatically wrap sent Ether in `receive` function\\n (bool success, ) = address(l1Token).call{value: msg.value}(\\\"\\\");\\n if (!success) {\\n revert WrapETHFailed();\\n }\\n // double check amount\\n if (l1Token.balanceOf(address(this)) < amount) {\\n revert InsufficientWstETHReceived();\\n }\\n // now the wstETH is at this contract, bridge to L2 in behalf of the sender\\n // 1. approve token bridge to use `l1Token` of this contract\\n l1Token.approve(address(l1TokenBridge), amount);\\n // 2. actual cross bridge transfer\\n l1TokenBridge.depositERC20To(address(l1Token), l2Token, msg.sender, amount, l2Gas_, data_);\\n\\n emit Stake(msg.sender, amount);\\n }\\n\\n}\\n\",\"keccak256\":\"0x6972fa20c6152cb1f2d99e82f7452a6e8cb150c58b00ddf2cd511019c0f34a69\",\"license\":\"GPL-3.0\"},\"contracts/token/interfaces/IERC20Bridged.sol\":{\"content\":\"// SPDX-FileCopyrightText: 2022 Lido \\n// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity 0.8.10;\\n\\nimport {IERC20} from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/// @author psirex\\n/// @notice Extends the ERC20 functionality that allows the bridge to mint/burn tokens\\ninterface IERC20Bridged is IERC20 {\\n /// @notice Returns bridge which can mint and burn tokens on L2\\n function bridge() external view returns (address);\\n\\n /// @notice Creates amount_ tokens and assigns them to account_, increasing the total supply\\n /// @param account_ An address of the account to mint tokens\\n /// @param amount_ An amount of tokens to mint\\n function bridgeMint(address account_, uint256 amount_) external;\\n\\n /// @notice Destroys amount_ tokens from account_, reducing the total supply\\n /// @param account_ An address of the account to burn tokens\\n /// @param amount_ An amount of tokens to burn\\n function bridgeBurn(address account_, uint256 amount_) external;\\n}\\n\",\"keccak256\":\"0xf530d522554422944e9ef5600209fa2cf85b64ae688323526eea4ae33e9de9ec\",\"license\":\"GPL-3.0\"}},\"version\":1}", + "bytecode": "0x60e060405234801561001057600080fd5b5060405161088d38038061088d83398101604081905261002f9161006d565b60016000556001600160a01b0392831660805290821660a0521660c0526100b0565b80516001600160a01b038116811461006857600080fd5b919050565b60008060006060848603121561008257600080fd5b61008b84610051565b925061009960208501610051565b91506100a760408501610051565b90509250925092565b60805160a05160c05161078061010d600039600081816056015281816103f801526104d201526000818160b3015261052101526000818160fc0152818161021d015281816103030152818161042701526104ff01526107806000f3fe60806040526004361061003f5760003560e01c806336c717c11461004457806356eff267146100a15780638fdb9202146100d5578063c01e1bd6146100ea575b600080fd5b34801561005057600080fd5b506100787f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100ad57600080fd5b506100787f000000000000000000000000000000000000000000000000000000000000000081565b6100e86100e33660046105bf565b61011e565b005b3480156100f657600080fd5b506100787f000000000000000000000000000000000000000000000000000000000000000081565b6002600054141561018f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640160405180910390fd5b600260005573ffffffffffffffffffffffffffffffffffffffff84166101e1576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3480610219576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163460405160006040518083038185875af1925050503d8060008114610293576040519150601f19603f3d011682016040523d82523d6000602084013e610298565b606091505b50509050806102d3576040517fe83092ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015282907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa15801561035f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103839190610673565b10156103bb576040517fcdfc39de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b3906044016020604051808303816000875af1158015610470573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610494919061068c565b506040517f838b252000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063838b252090610553907f0000000000000000000000000000000000000000000000000000000000000000907f000000000000000000000000000000000000000000000000000000000000000090339088908c908c908c906004016106b5565b600060405180830381600087803b15801561056d57600080fd5b505af1158015610581573d6000803e3d6000fd5b50506040518492503391507febedb8b3c678666e7f36970bc8f57abf6d8fa2e828c0da91ea5b75bf68ed101a90600090a35050600160005550505050565b600080600080606085870312156105d557600080fd5b843573ffffffffffffffffffffffffffffffffffffffff811681146105f957600080fd5b9350602085013563ffffffff8116811461061257600080fd5b9250604085013567ffffffffffffffff8082111561062f57600080fd5b818701915087601f83011261064357600080fd5b81358181111561065257600080fd5b88602082850101111561066457600080fd5b95989497505060200194505050565b60006020828403121561068557600080fd5b5051919050565b60006020828403121561069e57600080fd5b815180151581146106ae57600080fd5b9392505050565b600073ffffffffffffffffffffffffffffffffffffffff808a168352808916602084015280881660408401525085606083015263ffffffff8516608083015260c060a08301528260c0830152828460e0840137600060e0848401015260e07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85011683010190509897505050505050505056fea264697066735822122047d15268d50dbef14cae0af680a27eea742877bf5a2260f2a44a87162995250a64736f6c634300080a0033", + "deployedBytecode": "0x60806040526004361061003f5760003560e01c806336c717c11461004457806356eff267146100a15780638fdb9202146100d5578063c01e1bd6146100ea575b600080fd5b34801561005057600080fd5b506100787f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100ad57600080fd5b506100787f000000000000000000000000000000000000000000000000000000000000000081565b6100e86100e33660046105bf565b61011e565b005b3480156100f657600080fd5b506100787f000000000000000000000000000000000000000000000000000000000000000081565b6002600054141561018f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640160405180910390fd5b600260005573ffffffffffffffffffffffffffffffffffffffff84166101e1576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3480610219576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163460405160006040518083038185875af1925050503d8060008114610293576040519150601f19603f3d011682016040523d82523d6000602084013e610298565b606091505b50509050806102d3576040517fe83092ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015282907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa15801561035f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103839190610673565b10156103bb576040517fcdfc39de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b3906044016020604051808303816000875af1158015610470573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610494919061068c565b506040517f838b252000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063838b252090610553907f0000000000000000000000000000000000000000000000000000000000000000907f000000000000000000000000000000000000000000000000000000000000000090339088908c908c908c906004016106b5565b600060405180830381600087803b15801561056d57600080fd5b505af1158015610581573d6000803e3d6000fd5b50506040518492503391507febedb8b3c678666e7f36970bc8f57abf6d8fa2e828c0da91ea5b75bf68ed101a90600090a35050600160005550505050565b600080600080606085870312156105d557600080fd5b843573ffffffffffffffffffffffffffffffffffffffff811681146105f957600080fd5b9350602085013563ffffffff8116811461061257600080fd5b9250604085013567ffffffffffffffff8082111561062f57600080fd5b818701915087601f83011261064357600080fd5b81358181111561065257600080fd5b88602082850101111561066457600080fd5b95989497505060200194505050565b60006020828403121561068557600080fd5b5051919050565b60006020828403121561069e57600080fd5b815180151581146106ae57600080fd5b9392505050565b600073ffffffffffffffffffffffffffffffffffffffff808a168352808916602084015280881660408401525085606083015263ffffffff8516608083015260c060a08301528260c0830152828460e0840137600060e0848401015260e07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85011683010190509897505050505050505056fea264697066735822122047d15268d50dbef14cae0af680a27eea742877bf5a2260f2a44a87162995250a64736f6c634300080a0033", + "devdoc": { + "kind": "dev", + "methods": {}, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 846, + "contract": "contracts/manta/StakeHelper.sol:StakeHelper", + "label": "_status", + "offset": 0, + "slot": "0", + "type": "t_uint256" + } + ], + "types": { + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} \ No newline at end of file diff --git a/deployments/eth_sepolia/solcInputs/ce069893e9f9d5099439824520d9f7b3.json b/deployments/eth_sepolia/solcInputs/ce069893e9f9d5099439824520d9f7b3.json new file mode 100644 index 0000000..6a01d44 --- /dev/null +++ b/deployments/eth_sepolia/solcInputs/ce069893e9f9d5099439824520d9f7b3.json @@ -0,0 +1,197 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/access/AccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address => bool) members;\n bytes32 adminRole;\n }\n\n mapping(bytes32 => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with a standardized message including the required role.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n *\n * _Available since v4.1._\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\n return _roles[role].members[account];\n }\n\n /**\n * @dev Revert with a standard message if `_msgSender()` is missing `role`.\n * Overriding this function changes the behavior of the {onlyRole} modifier.\n *\n * Format of the revert message is described in {_checkRole}.\n *\n * _Available since v4.6._\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Revert with a standard message if `account` is missing `role`.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert(\n string(\n abi.encodePacked(\n \"AccessControl: account \",\n Strings.toHexString(uint160(account), 20),\n \" is missing role \",\n Strings.toHexString(uint256(role), 32)\n )\n )\n );\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) public virtual override {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn't perform any\n * checks on the calling account.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n *\n * NOTE: This function is deprecated in favor of {_grantRole}.\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * Internal function without access restriction.\n */\n function _grantRole(bytes32 role, address account) internal virtual {\n if (!hasRole(role, account)) {\n _roles[role].members[account] = true;\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * Internal function without access restriction.\n */\n function _revokeRole(bytes32 role, address account) internal virtual {\n if (hasRole(role, account)) {\n _roles[role].members[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "@openzeppelin/contracts/interfaces/draft-IERC1822.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\n * proxy whose upgrades are fully controlled by the current implementation.\n */\ninterface IERC1822Proxiable {\n /**\n * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\n * address.\n *\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\n * function revert if invoked through a proxy.\n */\n function proxiableUUID() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts/proxy/beacon/IBeacon.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\n */\ninterface IBeacon {\n /**\n * @dev Must return an address that can be used as a delegate call target.\n *\n * {BeaconProxy} will check that this address is a contract.\n */\n function implementation() external view returns (address);\n}\n" + }, + "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/ERC1967/ERC1967Proxy.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Proxy.sol\";\nimport \"./ERC1967Upgrade.sol\";\n\n/**\n * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an\n * implementation address that can be changed. This address is stored in storage in the location specified by\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the\n * implementation behind the proxy.\n */\ncontract ERC1967Proxy is Proxy, ERC1967Upgrade {\n /**\n * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.\n *\n * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded\n * function call, and allows initializating the storage of the proxy like a Solidity constructor.\n */\n constructor(address _logic, bytes memory _data) payable {\n assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256(\"eip1967.proxy.implementation\")) - 1));\n _upgradeToAndCall(_logic, _data, false);\n }\n\n /**\n * @dev Returns the current implementation address.\n */\n function _implementation() internal view virtual override returns (address impl) {\n return ERC1967Upgrade._getImplementation();\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../beacon/IBeacon.sol\";\nimport \"../../interfaces/draft-IERC1822.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/StorageSlot.sol\";\n\n/**\n * @dev This abstract contract provides getters and event emitting update functions for\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\n *\n * _Available since v4.1._\n *\n * @custom:oz-upgrades-unsafe-allow delegatecall\n */\nabstract contract ERC1967Upgrade {\n // This is the keccak-256 hash of \"eip1967.proxy.rollback\" subtracted by 1\n bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\n\n /**\n * @dev Storage slot with the address of the current implementation.\n * This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n /**\n * @dev Emitted when the implementation is upgraded.\n */\n event Upgraded(address indexed implementation);\n\n /**\n * @dev Returns the current implementation address.\n */\n function _getImplementation() internal view returns (address) {\n return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n }\n\n /**\n * @dev Stores a new address in the EIP1967 implementation slot.\n */\n function _setImplementation(address newImplementation) private {\n require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n }\n\n /**\n * @dev Perform implementation upgrade\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeTo(address newImplementation) internal {\n _setImplementation(newImplementation);\n emit Upgraded(newImplementation);\n }\n\n /**\n * @dev Perform implementation upgrade with additional setup call.\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeToAndCall(\n address newImplementation,\n bytes memory data,\n bool forceCall\n ) internal {\n _upgradeTo(newImplementation);\n if (data.length > 0 || forceCall) {\n Address.functionDelegateCall(newImplementation, data);\n }\n }\n\n /**\n * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeToAndCallUUPS(\n address newImplementation,\n bytes memory data,\n bool forceCall\n ) internal {\n // Upgrades from old implementations will perform a rollback test. This test requires the new\n // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\n // this special case will break upgrade paths from old UUPS implementation to new ones.\n if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {\n _setImplementation(newImplementation);\n } else {\n try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\n require(slot == _IMPLEMENTATION_SLOT, \"ERC1967Upgrade: unsupported proxiableUUID\");\n } catch {\n revert(\"ERC1967Upgrade: new implementation is not UUPS\");\n }\n _upgradeToAndCall(newImplementation, data, forceCall);\n }\n }\n\n /**\n * @dev Storage slot with the admin of the contract.\n * This is the keccak-256 hash of \"eip1967.proxy.admin\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\n\n /**\n * @dev Emitted when the admin account has changed.\n */\n event AdminChanged(address previousAdmin, address newAdmin);\n\n /**\n * @dev Returns the current admin.\n */\n function _getAdmin() internal view returns (address) {\n return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;\n }\n\n /**\n * @dev Stores a new address in the EIP1967 admin slot.\n */\n function _setAdmin(address newAdmin) private {\n require(newAdmin != address(0), \"ERC1967: new admin is the zero address\");\n StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;\n }\n\n /**\n * @dev Changes the admin of the proxy.\n *\n * Emits an {AdminChanged} event.\n */\n function _changeAdmin(address newAdmin) internal {\n emit AdminChanged(_getAdmin(), newAdmin);\n _setAdmin(newAdmin);\n }\n\n /**\n * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\n * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.\n */\n bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\n\n /**\n * @dev Emitted when the beacon is upgraded.\n */\n event BeaconUpgraded(address indexed beacon);\n\n /**\n * @dev Returns the current beacon.\n */\n function _getBeacon() internal view returns (address) {\n return StorageSlot.getAddressSlot(_BEACON_SLOT).value;\n }\n\n /**\n * @dev Stores a new beacon in the EIP1967 beacon slot.\n */\n function _setBeacon(address newBeacon) private {\n require(Address.isContract(newBeacon), \"ERC1967: new beacon is not a contract\");\n require(\n Address.isContract(IBeacon(newBeacon).implementation()),\n \"ERC1967: beacon implementation is not a contract\"\n );\n StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;\n }\n\n /**\n * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does\n * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).\n *\n * Emits a {BeaconUpgraded} event.\n */\n function _upgradeBeaconToAndCall(\n address newBeacon,\n bytes memory data,\n bool forceCall\n ) internal {\n _setBeacon(newBeacon);\n emit BeaconUpgraded(newBeacon);\n if (data.length > 0 || forceCall) {\n Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/Proxy.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM\n * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to\n * be specified by overriding the virtual {_implementation} function.\n *\n * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a\n * different contract through the {_delegate} function.\n *\n * The success and return data of the delegated call will be returned back to the caller of the proxy.\n */\nabstract contract Proxy {\n /**\n * @dev Delegates the current call to `implementation`.\n *\n * This function does not return to its internal call site, it will return directly to the external caller.\n */\n function _delegate(address implementation) internal virtual {\n assembly {\n // Copy msg.data. We take full control of memory in this inline assembly\n // block because it will not return to Solidity code. We overwrite the\n // Solidity scratch pad at memory position 0.\n calldatacopy(0, 0, calldatasize())\n\n // Call the implementation.\n // out and outsize are 0 because we don't know the size yet.\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\n\n // Copy the returned data.\n returndatacopy(0, 0, returndatasize())\n\n switch result\n // delegatecall returns 0 on error.\n case 0 {\n revert(0, returndatasize())\n }\n default {\n return(0, returndatasize())\n }\n }\n }\n\n /**\n * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function\n * and {_fallback} should delegate.\n */\n function _implementation() internal view virtual returns (address);\n\n /**\n * @dev Delegates the current call to the address returned by `_implementation()`.\n *\n * This function does not return to its internal call site, it will return directly to the external caller.\n */\n function _fallback() internal virtual {\n _beforeFallback();\n _delegate(_implementation());\n }\n\n /**\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\n * function in the contract matches the call data.\n */\n fallback() external payable virtual {\n _fallback();\n }\n\n /**\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data\n * is empty.\n */\n receive() external payable virtual {\n _fallback();\n }\n\n /**\n * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`\n * call, or as part of the Solidity `fallback` or `receive` functions.\n *\n * If overridden should call `super._beforeFallback()`.\n */\n function _beforeFallback() internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/security/ReentrancyGuard.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n constructor() {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n // On the first call to nonReentrant, _notEntered will be true\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n\n _;\n\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/StorageSlot.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC1967 implementation slot:\n * ```\n * contract ERC1967 {\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n * function _getImplementation() internal view returns (address) {\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n * }\n *\n * function _setImplementation(address newImplementation) internal {\n * require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n * }\n * }\n * ```\n *\n * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._\n */\nlibrary StorageSlot {\n struct AddressSlot {\n address value;\n }\n\n struct BooleanSlot {\n bool value;\n }\n\n struct Bytes32Slot {\n bytes32 value;\n }\n\n struct Uint256Slot {\n uint256 value;\n }\n\n /**\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n */\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\n */\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\n */\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\n */\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n assembly {\n r.slot := slot\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" + }, + "contracts/arbitrum/InterchainERC20TokenGateway.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {BridgingManager} from \"../BridgingManager.sol\";\nimport {BridgeableTokens} from \"../BridgeableTokens.sol\";\n\nimport {IInterchainTokenGateway} from \"./interfaces/IInterchainTokenGateway.sol\";\n\n/// @author psirex\n/// @notice The contract keeps logic shared among both L1 and L2 gateways, adding the methods for\n/// bridging management: enabling and disabling withdrawals/deposits\nabstract contract InterchainERC20TokenGateway is\n BridgingManager,\n BridgeableTokens,\n IInterchainTokenGateway\n{\n /// @notice Address of the router in the corresponding chain\n address public immutable router;\n\n /// @inheritdoc IInterchainTokenGateway\n address public immutable counterpartGateway;\n\n /// @param router_ Address of the router in the corresponding chain\n /// @param counterpartGateway_ Address of the counterpart gateway used in the bridging process\n /// @param l1Token_ Address of the bridged token in the Ethereum chain\n /// @param l2Token_ Address of the token minted on the Arbitrum chain when token bridged\n constructor(\n address router_,\n address counterpartGateway_,\n address l1Token_,\n address l2Token_\n ) BridgeableTokens(l1Token_, l2Token_) {\n router = router_;\n counterpartGateway = counterpartGateway_;\n }\n\n /// @inheritdoc IInterchainTokenGateway\n /// @dev The current implementation returns the l2Token address when passed l1Token_ equals\n /// to l1Token declared in the contract and address(0) in other cases\n function calculateL2TokenAddress(address l1Token_)\n external\n view\n returns (address)\n {\n if (l1Token_ == l1Token) {\n return l2Token;\n }\n return address(0);\n }\n\n /// @inheritdoc IInterchainTokenGateway\n function getOutboundCalldata(\n address l1Token_,\n address from_,\n address to_,\n uint256 amount_,\n bytes memory // data_\n ) public pure returns (bytes memory) {\n return\n abi.encodeWithSelector(\n IInterchainTokenGateway.finalizeInboundTransfer.selector,\n l1Token_,\n from_,\n to_,\n amount_,\n \"\"\n );\n }\n}\n" + }, + "contracts/arbitrum/interfaces/IArbSys.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\n/// @title Precompiled contract that exists in every Arbitrum chain at address(100),\n/// 0x0000000000000000000000000000000000000064. Exposes a variety of system-level functionality\ninterface IArbSys {\n /// @notice Send a transaction to L1\n /// @param destination_ Recipient address on L1\n /// @param calldataForL1_ (optional) Calldata for L1 contract call\n /// @return Unique identifier for this L2-to-L1 transaction\n function sendTxToL1(address destination_, bytes calldata calldataForL1_)\n external\n payable\n returns (uint256);\n}\n" + }, + "contracts/arbitrum/interfaces/IBridge.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\ninterface IBridge {\n function activeOutbox() external view returns (address);\n}\n" + }, + "contracts/arbitrum/interfaces/IInbox.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.4.21;\n\ninterface IInbox {\n /// @notice Put an message in the L2 inbox that can be reexecuted for some fixed amount of time\n /// if it reverts all msg.value will deposited to callValueRefundAddress on L2\n /// @param destAddr_ Destination L2 contract address\n /// @param arbTxCallValue_ Call value for retryable L2 message\n /// @param maxSubmissionCost_ Max gas deducted from user's L2 balance to cover base submission fee\n /// @param submissionRefundAddress_ maxGas x gasprice - execution cost gets credited here on L2 balance\n /// @param valueRefundAddress_ l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n /// @param maxGas_ Max gas deducted from user's L2 balance to cover L2 execution\n /// @param gasPriceBid_ Price bid for L2 execution\n /// @param data_ ABI encoded data of L2 message\n /// @return unique id for retryable transaction (keccak256(requestID, uint(0) )\n function createRetryableTicket(\n address destAddr_,\n uint256 arbTxCallValue_,\n uint256 maxSubmissionCost_,\n address submissionRefundAddress_,\n address valueRefundAddress_,\n uint256 maxGas_,\n uint256 gasPriceBid_,\n bytes calldata data_\n ) external payable returns (uint256);\n\n /// @notice Returns address of the Arbitumr's bridge\n function bridge() external view returns (address);\n}\n" + }, + "contracts/arbitrum/interfaces/IInterchainTokenGateway.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\n/// @author psirex\n/// @notice Keeps logic shared among both L1 and L2 gateways.\ninterface IInterchainTokenGateway {\n /// @notice Finalizes the bridging of the tokens between chains\n /// @param l1Token_ Address in the L1 chain of the token to withdraw\n /// @param from_ Address of the account initiated withdrawing\n /// @param to_ Address of the recipient of the tokens\n /// @param amount_ Amount of tokens to withdraw\n /// @param data_ Additional data required for the transaction\n function finalizeInboundTransfer(\n address l1Token_,\n address from_,\n address to_,\n uint256 amount_,\n bytes calldata data_\n ) external;\n\n /// @notice Calculates address of token, which will be minted on the Arbitrum chain,\n /// on l1Token_ bridging\n /// @param l1Token_ Address of the token on the Ethereum chain\n /// @return Address of the token minted on the L2 on bridging\n function calculateL2TokenAddress(address l1Token_)\n external\n view\n returns (address);\n\n /// @notice Returns address of the counterpart gateway used in the bridging process\n function counterpartGateway() external view returns (address);\n\n /// @notice Returns encoded transaction data to send into the counterpart gateway to finalize\n /// the tokens bridging process.\n /// @param l1Token_ Address in the Ethereum chain of the token to bridge\n /// @param from_ Address of the account initiated bridging in the current chain\n /// @param to_ Address of the recipient of the token in the counterpart chain\n /// @param amount_ Amount of tokens to bridge\n /// @param data_ Custom data to pass into finalizeInboundTransfer method\n /// @return Encoded transaction data of finalizeInboundTransfer call\n function getOutboundCalldata(\n address l1Token_,\n address from_,\n address to_,\n uint256 amount_,\n bytes memory data_\n ) external view returns (bytes memory);\n}\n" + }, + "contracts/arbitrum/interfaces/IL1TokenGateway.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {IInterchainTokenGateway} from \"./IInterchainTokenGateway.sol\";\n\n/// @author psirex\n/// @notice L1 part of the tokens bridge compatible with Arbitrum's GatewayRouter\ninterface IL1TokenGateway is IInterchainTokenGateway {\n /// @notice Initiates the tokens bridging from the Ethereum into the Arbitrum chain\n /// @param l1Token_ Address in the L1 chain of the token to bridge\n /// @param to_ Address of the recipient of the token on the corresponding chain\n /// @param amount_ Amount of tokens to bridge\n /// @param maxGas_ Gas limit for immediate L2 execution attempt\n /// @param gasPriceBid_ L2 gas price bid for immediate L2 execution attempt\n /// @param data_ Additional data required for the transaction\n function outboundTransfer(\n address l1Token_,\n address to_,\n uint256 amount_,\n uint256 maxGas_,\n uint256 gasPriceBid_,\n bytes calldata data_\n ) external payable returns (bytes memory);\n\n event DepositInitiated(\n address l1Token,\n address indexed from,\n address indexed to,\n uint256 indexed sequenceNumber,\n uint256 amount\n );\n\n event WithdrawalFinalized(\n address l1Token,\n address indexed from,\n address indexed to,\n uint256 indexed exitNum,\n uint256 amount\n );\n}\n" + }, + "contracts/arbitrum/interfaces/IL2TokenGateway.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {IInterchainTokenGateway} from \"./IInterchainTokenGateway.sol\";\n\n/// @author psirex\n/// @notice L2 part of the tokens bridge compatible with Arbitrum's GatewayRouter\ninterface IL2TokenGateway is IInterchainTokenGateway {\n /// @notice Initiates the withdrawing process from the Arbitrum chain into the Ethereum chain\n /// @param l1Token_ Address in the L1 chain of the token to withdraw\n /// @param to_ Address of the recipient of the token on the corresponding chain\n /// @param amount_ Amount of tokens to bridge\n /// @param data_ Additional data required for transaction\n function outboundTransfer(\n address l1Token_,\n address to_,\n uint256 amount_,\n uint256 maxGas_,\n uint256 gasPriceBid_,\n bytes calldata data_\n ) external returns (bytes memory);\n\n event DepositFinalized(\n address indexed l1Token,\n address indexed from,\n address indexed to,\n uint256 amount\n );\n\n event WithdrawalInitiated(\n address l1Token,\n address indexed from,\n address indexed to,\n uint256 indexed l2ToL1Id,\n uint256 exitNum,\n uint256 amount\n );\n}\n" + }, + "contracts/arbitrum/interfaces/IOutbox.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\ninterface IOutbox {\n function l2ToL1Sender() external view returns (address);\n}\n" + }, + "contracts/arbitrum/L1CrossDomainEnabled.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {IInbox} from \"./interfaces/IInbox.sol\";\nimport {IBridge} from \"./interfaces/IBridge.sol\";\nimport {IOutbox} from \"./interfaces/IOutbox.sol\";\n\n/// @author psirex\n/// @notice A helper contract to simplify Ethereum to Arbitrum communication process process\n/// via Retryable Tickets\ncontract L1CrossDomainEnabled {\n /// @notice Address of the Arbitrum's Inbox contract\n IInbox public immutable inbox;\n\n /// @param inbox_ Address of the Arbitrum's Inbox contract\n constructor(address inbox_) {\n inbox = IInbox(inbox_);\n }\n\n /// @dev Properties required to create RetryableTicket\n /// @param maxGas Gas limit for immediate L2 execution attempt\n /// @param callValue Call-value for L2 transaction\n /// @param gasPriceBid L2 Gas price bid for immediate L2 execution attempt\n /// @param maxSubmissionCost Amount of ETH allocated to pay for the base submission fee\n struct CrossDomainMessageOptions {\n uint256 maxGas;\n uint256 callValue;\n uint256 gasPriceBid;\n uint256 maxSubmissionCost;\n }\n\n /// @notice Creates a Retryable Ticket via Inbox.createRetryableTicket function using\n /// the provided arguments\n /// @param sender_ Address of the sender of the message\n /// @param recipient_ Address of the recipient of the message on the L2 chain\n /// @param data_ Data passed to the recipient_ in the message\n /// @param msgOptions_ Instance of the `CrossDomainMessageOptions` struct\n /// @return seqNum Unique id of created Retryable Ticket.\n function sendCrossDomainMessage(\n address sender_,\n address recipient_,\n bytes memory data_,\n CrossDomainMessageOptions memory msgOptions_\n ) internal returns (uint256 seqNum) {\n if (msgOptions_.maxSubmissionCost == 0) {\n revert ErrorNoMaxSubmissionCost();\n }\n\n uint256 minEthValue = msgOptions_.callValue +\n msgOptions_.maxSubmissionCost +\n (msgOptions_.maxGas * msgOptions_.gasPriceBid);\n\n if (msg.value < minEthValue) {\n revert ErrorETHValueTooLow();\n }\n\n seqNum = inbox.createRetryableTicket{value: msg.value}(\n recipient_,\n msgOptions_.callValue,\n msgOptions_.maxSubmissionCost,\n sender_,\n sender_,\n msgOptions_.maxGas,\n msgOptions_.gasPriceBid,\n data_\n );\n\n emit TxToL2(sender_, recipient_, seqNum, data_);\n }\n\n /// @notice Validates that transaction was initiated by the crossDomainAccount_ address from\n /// the L2 chain\n modifier onlyFromCrossDomainAccount(address crossDomainAccount_) {\n address bridge = inbox.bridge();\n\n // a message coming from the counterpart gateway was executed by the bridge\n if (msg.sender != bridge) {\n revert ErrorUnauthorizedBridge();\n }\n\n address l2ToL1Sender = IOutbox(IBridge(bridge).activeOutbox())\n .l2ToL1Sender();\n\n // and the outbox reports that the L2 address of the sender is the counterpart gateway\n if (l2ToL1Sender != crossDomainAccount_) {\n revert ErrorWrongCrossDomainSender();\n }\n _;\n }\n\n event TxToL2(\n address indexed from,\n address indexed to,\n uint256 indexed seqNum,\n bytes data\n );\n\n error ErrorETHValueTooLow();\n error ErrorUnauthorizedBridge();\n error ErrorNoMaxSubmissionCost();\n error ErrorWrongCrossDomainSender();\n}\n" + }, + "contracts/arbitrum/L1ERC20TokenGateway.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport {IL1TokenGateway, IInterchainTokenGateway} from \"./interfaces/IL1TokenGateway.sol\";\n\nimport {L1CrossDomainEnabled} from \"./L1CrossDomainEnabled.sol\";\nimport {L1OutboundDataParser} from \"./libraries/L1OutboundDataParser.sol\";\nimport {InterchainERC20TokenGateway} from \"./InterchainERC20TokenGateway.sol\";\n\n/// @author psirex\n/// @notice Contract implements ITokenGateway interface and with counterpart L2ERC20TokenGatewy\n/// allows bridging registered ERC20 compatible tokens between Ethereum and Arbitrum chains\ncontract L1ERC20TokenGateway is\n InterchainERC20TokenGateway,\n L1CrossDomainEnabled,\n IL1TokenGateway\n{\n using SafeERC20 for IERC20;\n\n /// @param inbox_ Address of the Arbitrum’s Inbox contract in the L1 chain\n /// @param router_ Address of the router in the L1 chain\n /// @param counterpartGateway_ Address of the counterpart L2 gateway\n /// @param l1Token_ Address of the bridged token in the L1 chain\n /// @param l2Token_ Address of the token minted on the Arbitrum chain when token bridged\n constructor(\n address inbox_,\n address router_,\n address counterpartGateway_,\n address l1Token_,\n address l2Token_\n )\n InterchainERC20TokenGateway(\n router_,\n counterpartGateway_,\n l1Token_,\n l2Token_\n )\n L1CrossDomainEnabled(inbox_)\n {}\n\n /// @inheritdoc IL1TokenGateway\n function outboundTransfer(\n address l1Token_,\n address to_,\n uint256 amount_,\n uint256 maxGas_,\n uint256 gasPriceBid_,\n bytes calldata data_\n )\n external\n payable\n whenDepositsEnabled\n onlyNonZeroAccount(to_)\n onlySupportedL1Token(l1Token_)\n returns (bytes memory)\n {\n (address from, uint256 maxSubmissionCost) = L1OutboundDataParser.decode(\n router,\n data_\n );\n\n IERC20(l1Token_).safeTransferFrom(from, address(this), amount_);\n\n uint256 retryableTicketId = _sendOutboundTransferMessage(\n from,\n to_,\n amount_,\n CrossDomainMessageOptions({\n maxGas: maxGas_,\n callValue: 0,\n gasPriceBid: gasPriceBid_,\n maxSubmissionCost: maxSubmissionCost\n })\n );\n\n emit DepositInitiated(l1Token, from, to_, retryableTicketId, amount_);\n\n return abi.encode(retryableTicketId);\n }\n\n /// @inheritdoc IInterchainTokenGateway\n function finalizeInboundTransfer(\n address l1Token_,\n address from_,\n address to_,\n uint256 amount_,\n bytes calldata // data_\n )\n external\n whenWithdrawalsEnabled\n onlySupportedL1Token(l1Token_)\n onlyFromCrossDomainAccount(counterpartGateway)\n {\n IERC20(l1Token_).safeTransfer(to_, amount_);\n\n // The current implementation doesn't support fast withdrawals, so we\n // always use 0 for the exitNum argument in the event\n emit WithdrawalFinalized(l1Token_, from_, to_, 0, amount_);\n }\n\n function _sendOutboundTransferMessage(\n address from_,\n address to_,\n uint256 amount_,\n CrossDomainMessageOptions memory messageOptions\n ) private returns (uint256) {\n return\n sendCrossDomainMessage(\n from_,\n counterpartGateway,\n getOutboundCalldata(l1Token, from_, to_, amount_, \"\"),\n messageOptions\n );\n }\n}\n" + }, + "contracts/arbitrum/L2CrossDomainEnabled.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {IArbSys} from \"./interfaces/IArbSys.sol\";\n\n/// @author psirex\n/// @notice A helper contract to simplify Arbitrum to Ethereum communication process\ncontract L2CrossDomainEnabled {\n uint160 private constant ADDRESS_OFFSET =\n uint160(0x1111000000000000000000000000000000001111);\n\n /// @notice Address of the Arbitrum’s ArbSys contract\n IArbSys public immutable arbSys;\n\n /// @param arbSys_ Address of the Arbitrum’s ArbSys contract\n constructor(address arbSys_) {\n arbSys = IArbSys(arbSys_);\n }\n\n /// @notice Sends the message to the Ethereum chain\n /// @param sender_ Address of the sender of the message\n /// @param recipient_ Address of the recipient of the message on the Ethereum chain\n /// @param data_ Data passed to the recipient in the message\n /// @return id Unique identifier for this L2-to-L1 transaction\n function sendCrossDomainMessage(\n address sender_,\n address recipient_,\n bytes memory data_\n ) internal returns (uint256 id) {\n id = IArbSys(arbSys).sendTxToL1(recipient_, data_);\n emit TxToL1(sender_, recipient_, id, data_);\n }\n\n /// @dev L1 addresses are transformed durng l1 -> l2 calls\n function applyL1ToL2Alias(address l1Address_)\n private\n pure\n returns (address l1Address)\n {\n unchecked {\n l1Address = address(uint160(l1Address_) + ADDRESS_OFFSET);\n }\n }\n\n /// @notice Validates that the sender address with applied Arbitrum's aliasing is equal to\n /// the crossDomainAccount_ address\n modifier onlyFromCrossDomainAccount(address crossDomainAccount_) {\n if (msg.sender != applyL1ToL2Alias(crossDomainAccount_)) {\n revert ErrorWrongCrossDomainSender();\n }\n _;\n }\n\n event TxToL1(\n address indexed from,\n address indexed to,\n uint256 indexed id,\n bytes data\n );\n\n error ErrorWrongCrossDomainSender();\n}\n" + }, + "contracts/arbitrum/L2ERC20TokenGateway.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {IERC20Bridged} from \"../token/interfaces/IERC20Bridged.sol\";\nimport {IL2TokenGateway, IInterchainTokenGateway} from \"./interfaces/IL2TokenGateway.sol\";\n\nimport {L2CrossDomainEnabled} from \"./L2CrossDomainEnabled.sol\";\nimport {L2OutboundDataParser} from \"./libraries/L2OutboundDataParser.sol\";\nimport {InterchainERC20TokenGateway} from \"./InterchainERC20TokenGateway.sol\";\n\n/// @author psirex\n/// @notice Contract implements ITokenGateway interface and with counterpart L1ERC20TokenGateway\n/// allows bridging registered ERC20 compatible tokens between Arbitrum and Ethereum chains\ncontract L2ERC20TokenGateway is\n InterchainERC20TokenGateway,\n L2CrossDomainEnabled,\n IL2TokenGateway\n{\n /// @param arbSys_ Address of the Arbitrum’s ArbSys contract in the L2 chain\n /// @param router_ Address of the router in the L2 chain\n /// @param counterpartGateway_ Address of the counterpart L1 gateway\n /// @param l1Token_ Address of the bridged token in the L1 chain\n /// @param l2Token_ Address of the token minted on the Arbitrum chain when token bridged\n constructor(\n address arbSys_,\n address router_,\n address counterpartGateway_,\n address l1Token_,\n address l2Token_\n )\n InterchainERC20TokenGateway(\n router_,\n counterpartGateway_,\n l1Token_,\n l2Token_\n )\n L2CrossDomainEnabled(arbSys_)\n {}\n\n /// @inheritdoc IL2TokenGateway\n function outboundTransfer(\n address l1Token_,\n address to_,\n uint256 amount_,\n uint256, // maxGas\n uint256, // gasPriceBid\n bytes calldata data_\n )\n external\n whenWithdrawalsEnabled\n onlySupportedL1Token(l1Token_)\n returns (bytes memory res)\n {\n address from = L2OutboundDataParser.decode(router, data_);\n\n IERC20Bridged(l2Token).bridgeBurn(from, amount_);\n\n uint256 id = sendCrossDomainMessage(\n from,\n counterpartGateway,\n getOutboundCalldata(l1Token_, from, to_, amount_, \"\")\n );\n\n // The current implementation doesn't support fast withdrawals, so we\n // always use 0 for the exitNum argument in the event\n emit WithdrawalInitiated(l1Token_, from, to_, id, 0, amount_);\n\n return abi.encode(id);\n }\n\n /// @inheritdoc IInterchainTokenGateway\n function finalizeInboundTransfer(\n address l1Token_,\n address from_,\n address to_,\n uint256 amount_,\n bytes calldata\n )\n external\n whenDepositsEnabled\n onlySupportedL1Token(l1Token_)\n onlyFromCrossDomainAccount(counterpartGateway)\n {\n IERC20Bridged(l2Token).bridgeMint(to_, amount_);\n\n emit DepositFinalized(l1Token_, from_, to_, amount_);\n }\n}\n" + }, + "contracts/arbitrum/libraries/L1OutboundDataParser.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\n/// @author psirex\n/// @notice A helper library to parse data passed to outboundTransfer() of L1TokensGateway\nlibrary L1OutboundDataParser {\n /// @dev Decodes value contained in data_ bytes array and returns it\n /// @param router_ Address of the Arbitrum’s L1GatewayRouter\n /// @param data_ Data encoded for the outboundTransfer() method\n /// @return Decoded (from, maxSubmissionCost) values\n function decode(address router_, bytes memory data_)\n internal\n view\n returns (address, uint256)\n {\n if (msg.sender != router_) {\n return (msg.sender, _parseSubmissionCostData(data_));\n }\n (address from, bytes memory extraData) = abi.decode(\n data_,\n (address, bytes)\n );\n return (from, _parseSubmissionCostData(extraData));\n }\n\n /// @dev Extracts the maxSubmissionCost value from the outboundTransfer() data\n function _parseSubmissionCostData(bytes memory data_)\n private\n pure\n returns (uint256)\n {\n (uint256 maxSubmissionCost, bytes memory extraData) = abi.decode(\n data_,\n (uint256, bytes)\n );\n if (extraData.length != 0) {\n revert ExtraDataNotEmpty();\n }\n return maxSubmissionCost;\n }\n\n error ExtraDataNotEmpty();\n}\n" + }, + "contracts/arbitrum/libraries/L2OutboundDataParser.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\n/// @author psirex\n/// @notice A helper library to parse data passed to outboundTransfer() of L2ERC20TokenGateway\nlibrary L2OutboundDataParser {\n /// @dev Decodes value contained in data_ bytes array and returns it\n /// @param router_ Address of the Arbitrum’s L2GatewayRouter\n /// @param data_ Data encoded for the outboundTransfer() method\n /// @return from_ address of the sender\n function decode(address router_, bytes memory data_)\n internal\n view\n returns (address from_)\n {\n bytes memory extraData;\n if (msg.sender == router_) {\n (from_, extraData) = abi.decode(data_, (address, bytes));\n } else {\n (from_, extraData) = (msg.sender, data_);\n }\n if (extraData.length != 0) {\n revert ExtraDataNotEmpty();\n }\n }\n\n error ExtraDataNotEmpty();\n}\n" + }, + "contracts/arbitrum/stubs/ArbSysStub.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\ncontract ArbSysStub {\n uint256 public l2ToL1TxId;\n\n function setl2ToL1TxId(uint256 l2ToL1TxId_) public {\n l2ToL1TxId = l2ToL1TxId_;\n }\n\n function sendTxToL1(address recipient, bytes calldata data)\n external\n payable\n returns (uint256)\n {\n l2ToL1TxId += 1;\n emit CreateL2ToL1Tx(recipient, data);\n return l2ToL1TxId;\n }\n\n event CreateL2ToL1Tx(address recipient, bytes data);\n}\n" + }, + "contracts/arbitrum/stubs/BridgeStub.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {IBridge} from \"../interfaces/IBridge.sol\";\n\ncontract BridgeStub is IBridge {\n address public activeOutbox;\n\n constructor(address activeOutbox_) payable {\n activeOutbox = activeOutbox_;\n }\n\n function setOutbox(address outbox_) external {\n activeOutbox = outbox_;\n }\n}\n" + }, + "contracts/arbitrum/stubs/InboxStub.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {IInbox} from \"../interfaces/IInbox.sol\";\n\ncontract InboxStub is IInbox {\n uint256 public retryableTicketId;\n address public immutable bridge;\n\n constructor(address bridge_) {\n bridge = bridge_;\n }\n\n function setRetryableTicketId(uint256 retryableTicketId_) public {\n retryableTicketId = retryableTicketId_;\n }\n\n function createRetryableTicket(\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes calldata data\n ) external payable returns (uint256) {\n emit CreateRetryableTicketCalled(\n msg.value,\n destAddr,\n arbTxCallValue,\n maxSubmissionCost,\n submissionRefundAddress,\n valueRefundAddress,\n maxGas,\n gasPriceBid,\n data\n );\n return retryableTicketId;\n }\n\n event CreateRetryableTicketCalled(\n uint256 value,\n address destAddr,\n uint256 arbTxCallValue,\n uint256 maxSubmissionCost,\n address submissionRefundAddress,\n address valueRefundAddress,\n uint256 maxGas,\n uint256 gasPriceBid,\n bytes data\n );\n}\n" + }, + "contracts/arbitrum/stubs/OutboxStub.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {IOutbox} from \"../interfaces/IOutbox.sol\";\n\ncontract OutboxStub is IOutbox {\n address public l2ToL1Sender;\n\n function setL2ToL1Sender(address l2ToL1Sender_) external {\n l2ToL1Sender = l2ToL1Sender_;\n }\n}\n" + }, + "contracts/BridgeableTokens.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\n/// @author psirex\n/// @notice Contains the logic for validation of tokens used in the bridging process\ncontract BridgeableTokens {\n /// @notice Address of the bridged token in the L1 chain\n address public immutable l1Token;\n\n /// @notice Address of the token minted on the L2 chain when token bridged\n address public immutable l2Token;\n\n /// @param l1Token_ Address of the bridged token in the L1 chain\n /// @param l2Token_ Address of the token minted on the L2 chain when token bridged\n constructor(address l1Token_, address l2Token_) {\n l1Token = l1Token_;\n l2Token = l2Token_;\n }\n\n /// @dev Validates that passed l1Token_ is supported by the bridge\n modifier onlySupportedL1Token(address l1Token_) {\n if (l1Token_ != l1Token) {\n revert ErrorUnsupportedL1Token();\n }\n _;\n }\n\n /// @dev Validates that passed l2Token_ is supported by the bridge\n modifier onlySupportedL2Token(address l2Token_) {\n if (l2Token_ != l2Token) {\n revert ErrorUnsupportedL2Token();\n }\n _;\n }\n\n /// @dev validates that account_ is not zero address\n modifier onlyNonZeroAccount(address account_) {\n if (account_ == address(0)) {\n revert ErrorAccountIsZeroAddress();\n }\n _;\n }\n\n error ErrorUnsupportedL1Token();\n error ErrorUnsupportedL2Token();\n error ErrorAccountIsZeroAddress();\n}\n" + }, + "contracts/BridgingManager.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {AccessControl} from \"@openzeppelin/contracts/access/AccessControl.sol\";\n\n/// @author psirex\n/// @notice Contains administrative methods to retrieve and control the state of the bridging\ncontract BridgingManager is AccessControl {\n /// @dev Stores the state of the bridging\n /// @param isInitialized Shows whether the contract is initialized or not\n /// @param isDepositsEnabled Stores the state of the deposits\n /// @param isWithdrawalsEnabled Stores the state of the withdrawals\n struct State {\n bool isInitialized;\n bool isDepositsEnabled;\n bool isWithdrawalsEnabled;\n }\n\n bytes32 public constant DEPOSITS_ENABLER_ROLE =\n keccak256(\"BridgingManager.DEPOSITS_ENABLER_ROLE\");\n bytes32 public constant DEPOSITS_DISABLER_ROLE =\n keccak256(\"BridgingManager.DEPOSITS_DISABLER_ROLE\");\n bytes32 public constant WITHDRAWALS_ENABLER_ROLE =\n keccak256(\"BridgingManager.WITHDRAWALS_ENABLER_ROLE\");\n bytes32 public constant WITHDRAWALS_DISABLER_ROLE =\n keccak256(\"BridgingManager.WITHDRAWALS_DISABLER_ROLE\");\n\n /// @dev The location of the slot with State\n bytes32 private constant STATE_SLOT =\n keccak256(\"BridgingManager.bridgingState\");\n\n /// @notice Initializes the contract to grant DEFAULT_ADMIN_ROLE to the admin_ address\n /// @dev This method might be called only once\n /// @param admin_ Address of the account to grant the DEFAULT_ADMIN_ROLE\n function initialize(address admin_) external {\n State storage s = _loadState();\n if (s.isInitialized) {\n revert ErrorAlreadyInitialized();\n }\n _setupRole(DEFAULT_ADMIN_ROLE, admin_);\n s.isInitialized = true;\n emit Initialized(admin_);\n }\n\n /// @notice Returns whether the contract is initialized or not\n function isInitialized() public view returns (bool) {\n return _loadState().isInitialized;\n }\n\n /// @notice Returns whether the deposits are enabled or not\n function isDepositsEnabled() public view returns (bool) {\n return _loadState().isDepositsEnabled;\n }\n\n /// @notice Returns whether the withdrawals are enabled or not\n function isWithdrawalsEnabled() public view returns (bool) {\n return _loadState().isWithdrawalsEnabled;\n }\n\n /// @notice Enables the deposits if they are disabled\n function enableDeposits() external onlyRole(DEPOSITS_ENABLER_ROLE) {\n if (isDepositsEnabled()) {\n revert ErrorDepositsEnabled();\n }\n _loadState().isDepositsEnabled = true;\n emit DepositsEnabled(msg.sender);\n }\n\n /// @notice Disables the deposits if they aren't disabled yet\n function disableDeposits()\n external\n whenDepositsEnabled\n onlyRole(DEPOSITS_DISABLER_ROLE)\n {\n _loadState().isDepositsEnabled = false;\n emit DepositsDisabled(msg.sender);\n }\n\n /// @notice Enables the withdrawals if they are disabled\n function enableWithdrawals() external onlyRole(WITHDRAWALS_ENABLER_ROLE) {\n if (isWithdrawalsEnabled()) {\n revert ErrorWithdrawalsEnabled();\n }\n _loadState().isWithdrawalsEnabled = true;\n emit WithdrawalsEnabled(msg.sender);\n }\n\n /// @notice Disables the withdrawals if they aren't disabled yet\n function disableWithdrawals()\n external\n whenWithdrawalsEnabled\n onlyRole(WITHDRAWALS_DISABLER_ROLE)\n {\n _loadState().isWithdrawalsEnabled = false;\n emit WithdrawalsDisabled(msg.sender);\n }\n\n /// @dev Returns the reference to the slot with State struct\n function _loadState() private pure returns (State storage r) {\n bytes32 slot = STATE_SLOT;\n assembly {\n r.slot := slot\n }\n }\n\n /// @dev Validates that deposits are enabled\n modifier whenDepositsEnabled() {\n if (!isDepositsEnabled()) {\n revert ErrorDepositsDisabled();\n }\n _;\n }\n\n /// @dev Validates that withdrawals are enabled\n modifier whenWithdrawalsEnabled() {\n if (!isWithdrawalsEnabled()) {\n revert ErrorWithdrawalsDisabled();\n }\n _;\n }\n\n event DepositsEnabled(address indexed enabler);\n event DepositsDisabled(address indexed disabler);\n event WithdrawalsEnabled(address indexed enabler);\n event WithdrawalsDisabled(address indexed disabler);\n event Initialized(address indexed admin);\n\n error ErrorDepositsEnabled();\n error ErrorDepositsDisabled();\n error ErrorWithdrawalsEnabled();\n error ErrorWithdrawalsDisabled();\n error ErrorAlreadyInitialized();\n}\n" + }, + "contracts/manta/StakeHelper.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {ReentrancyGuard} from \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport {IERC20Bridged} from \"../token/interfaces/IERC20Bridged.sol\";\n\n\ninterface IL1TokenBridge {\n function depositERC20To(\n address l1Token_,\n address l2Token_,\n address to_,\n uint256 amount_,\n uint32 l2Gas_,\n bytes calldata data_\n ) external;\n}\n\nerror ZeroAddress();\n\nerror WrapETHFailed();\n\nerror ZeroAmount();\n\nerror InsufficientWstETHReceived();\n\ncontract StakeHelper is ReentrancyGuard {\n IERC20 public immutable l1Token;\n\n address public immutable l2Token;\n\n IL1TokenBridge public immutable l1TokenBridge;\n\n event Stake(address indexed staker, uint256 indexed amount);\n\n constructor(\n address l1Token_, \n address l2Token_,\n address l1TokenBridge_\n ) {\n l1Token = IERC20(l1Token_);\n l2Token = l2Token_;\n l1TokenBridge = IL1TokenBridge(l1TokenBridge_);\n }\n\n // Wrap sender's ETH to wstETH and bridge to L2\n function stakeETH(\n address to,\n uint32 l2Gas_,\n bytes calldata data_\n ) external payable nonReentrant {\n if (to == address(0)) {\n revert ZeroAddress();\n }\n uint256 amount = msg.value;\n if (amount == 0) {\n revert ZeroAmount();\n }\n // wstETH on L1 will automatically wrap sent Ether in `receive` function\n (bool success, ) = address(l1Token).call{value: msg.value}(\"\");\n if (!success) {\n revert WrapETHFailed();\n }\n // double check amount\n if (l1Token.balanceOf(address(this)) < amount) {\n revert InsufficientWstETHReceived();\n }\n // now the wstETH is at this contract, bridge to L2 in behalf of the sender\n // 1. approve token bridge to use `l1Token` of this contract\n l1Token.approve(address(l1TokenBridge), amount);\n // 2. actual cross bridge transfer\n l1TokenBridge.depositERC20To(address(l1Token), l2Token, msg.sender, amount, l2Gas_, data_);\n\n emit Stake(msg.sender, amount);\n }\n\n}\n" + }, + "contracts/optimism/CrossDomainEnabled.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {ICrossDomainMessenger} from \"./interfaces/ICrossDomainMessenger.sol\";\n\n/// @dev Helper contract for contracts performing cross-domain communications\ncontract CrossDomainEnabled {\n /// @notice Messenger contract used to send and receive messages from the other domain\n ICrossDomainMessenger public immutable messenger;\n\n /// @param messenger_ Address of the CrossDomainMessenger on the current layer\n constructor(address messenger_) {\n messenger = ICrossDomainMessenger(messenger_);\n }\n\n /// @dev Sends a message to an account on another domain\n /// @param crossDomainTarget_ Intended recipient on the destination domain\n /// @param message_ Data to send to the target (usually calldata to a function with\n /// `onlyFromCrossDomainAccount()`)\n /// @param gasLimit_ gasLimit for the receipt of the message on the target domain.\n function sendCrossDomainMessage(\n address crossDomainTarget_,\n uint32 gasLimit_,\n bytes memory message_\n ) internal {\n messenger.sendMessage(crossDomainTarget_, message_, gasLimit_);\n }\n\n /// @dev Enforces that the modified function is only callable by a specific cross-domain account\n /// @param sourceDomainAccount_ The only account on the originating domain which is\n /// authenticated to call this function\n modifier onlyFromCrossDomainAccount(address sourceDomainAccount_) {\n if (msg.sender != address(messenger)) {\n revert ErrorUnauthorizedMessenger();\n }\n if (messenger.xDomainMessageSender() != sourceDomainAccount_) {\n revert ErrorWrongCrossDomainSender();\n }\n _;\n }\n\n error ErrorUnauthorizedMessenger();\n error ErrorWrongCrossDomainSender();\n}\n" + }, + "contracts/optimism/interfaces/ICrossDomainMessenger.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\ninterface ICrossDomainMessenger {\n function xDomainMessageSender() external view returns (address);\n\n /// Sends a cross domain message to the target messenger.\n /// @param _target Target contract address.\n /// @param _message Message to send to the target.\n /// @param _gasLimit Gas limit for the provided message.\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external;\n}\n" + }, + "contracts/optimism/interfaces/IL1ERC20Bridge.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\n/// @notice The L1 Standard bridge locks bridged tokens on the L1 side, sends deposit messages\n/// on the L2 side, and finalizes token withdrawals from L2.\ninterface IL1ERC20Bridge {\n event ERC20DepositInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event ERC20WithdrawalFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /// @notice get the address of the corresponding L2 bridge contract.\n /// @return Address of the corresponding L2 bridge contract.\n function l2TokenBridge() external returns (address);\n\n /// @notice deposit an amount of the ERC20 to the caller's balance on L2.\n /// @param l1Token_ Address of the L1 ERC20 we are depositing\n /// @param l2Token_ Address of the L1 respective L2 ERC20\n /// @param amount_ Amount of the ERC20 to deposit\n /// @param l2Gas_ Gas limit required to complete the deposit on L2.\n /// @param data_ Optional data to forward to L2. This data is provided\n /// solely as a convenience for external contracts. Aside from enforcing a maximum\n /// length, these contracts provide no guarantees about its content.\n function depositERC20(\n address l1Token_,\n address l2Token_,\n uint256 amount_,\n uint32 l2Gas_,\n bytes calldata data_\n ) external;\n\n /// @notice deposit an amount of ERC20 to a recipient's balance on L2.\n /// @param l1Token_ Address of the L1 ERC20 we are depositing\n /// @param l2Token_ Address of the L1 respective L2 ERC20\n /// @param to_ L2 address to credit the withdrawal to.\n /// @param amount_ Amount of the ERC20 to deposit.\n /// @param l2Gas_ Gas limit required to complete the deposit on L2.\n /// @param data_ Optional data to forward to L2. This data is provided\n /// solely as a convenience for external contracts. Aside from enforcing a maximum\n /// length, these contracts provide no guarantees about its content.\n function depositERC20To(\n address l1Token_,\n address l2Token_,\n address to_,\n uint256 amount_,\n uint32 l2Gas_,\n bytes calldata data_\n ) external;\n\n /// @notice Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the\n /// L1 ERC20 token.\n /// @dev This call will fail if the initialized withdrawal from L2 has not been finalized.\n /// @param l1Token_ Address of L1 token to finalizeWithdrawal for.\n /// @param l2Token_ Address of L2 token where withdrawal was initiated.\n /// @param from_ L2 address initiating the transfer.\n /// @param to_ L1 address to credit the withdrawal to.\n /// @param amount_ Amount of the ERC20 to deposit.\n /// @param data_ Data provided by the sender on L2. This data is provided\n /// solely as a convenience for external contracts. Aside from enforcing a maximum\n /// length, these contracts provide no guarantees about its content.\n function finalizeERC20Withdrawal(\n address l1Token_,\n address l2Token_,\n address from_,\n address to_,\n uint256 amount_,\n bytes calldata data_\n ) external;\n}\n" + }, + "contracts/optimism/interfaces/IL2ERC20Bridge.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\n/// @notice The L2 token bridge works with the L1 token bridge to enable ERC20 token bridging\n/// between L1 and L2. It acts as a minter for new tokens when it hears about\n/// deposits into the L1 token bridge. It also acts as a burner of the tokens\n/// intended for withdrawal, informing the L1 bridge to release L1 funds.\ninterface IL2ERC20Bridge {\n event WithdrawalInitiated(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event DepositFinalized(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n event DepositFailed(\n address indexed _l1Token,\n address indexed _l2Token,\n address indexed _from,\n address _to,\n uint256 _amount,\n bytes _data\n );\n\n /// @notice Returns the address of the corresponding L1 bridge contract\n function l1TokenBridge() external returns (address);\n\n /// @notice Initiates a withdraw of some tokens to the caller's account on L1\n /// @param l2Token_ Address of L2 token where withdrawal was initiated.\n /// @param amount_ Amount of the token to withdraw.\n /// @param l1Gas_ Unused, but included for potential forward compatibility considerations.\n /// @param data_ Optional data to forward to L1. This data is provided\n /// solely as a convenience for external contracts. Aside from enforcing a maximum\n /// length, these contracts provide no guarantees about its content.\n function withdraw(\n address l2Token_,\n uint256 amount_,\n uint32 l1Gas_,\n bytes calldata data_\n ) external;\n\n /// @notice Initiates a withdraw of some token to a recipient's account on L1.\n /// @param l2Token_ Address of L2 token where withdrawal is initiated.\n /// @param to_ L1 adress to credit the withdrawal to.\n /// @param amount_ Amount of the token to withdraw.\n /// @param l1Gas_ Unused, but included for potential forward compatibility considerations.\n /// @param data_ Optional data to forward to L1. This data is provided\n /// solely as a convenience for external contracts. Aside from enforcing a maximum\n /// length, these contracts provide no guarantees about its content.\n function withdrawTo(\n address l2Token_,\n address to_,\n uint256 amount_,\n uint32 l1Gas_,\n bytes calldata data_\n ) external;\n\n /// @notice Completes a deposit from L1 to L2, and credits funds to the recipient's balance of\n /// this L2 token. This call will fail if it did not originate from a corresponding deposit\n /// in L1StandardTokenBridge.\n /// @param l1Token_ Address for the l1 token this is called with\n /// @param l2Token_ Address for the l2 token this is called with\n /// @param from_ Account to pull the deposit from on L2.\n /// @param to_ Address to receive the withdrawal at\n /// @param amount_ Amount of the token to withdraw\n /// @param data_ Data provider by the sender on L1. This data is provided\n /// solely as a convenience for external contracts. Aside from enforcing a maximum\n /// length, these contracts provide no guarantees about its content.\n function finalizeDeposit(\n address l1Token_,\n address l2Token_,\n address from_,\n address to_,\n uint256 amount_,\n bytes calldata data_\n ) external;\n}\n" + }, + "contracts/optimism/L1ERC20TokenBridge.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {Address} from \"@openzeppelin/contracts/utils/Address.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport {IL1ERC20Bridge} from \"./interfaces/IL1ERC20Bridge.sol\";\nimport {IL2ERC20Bridge} from \"./interfaces/IL2ERC20Bridge.sol\";\n\nimport {BridgingManager} from \"../BridgingManager.sol\";\nimport {BridgeableTokens} from \"../BridgeableTokens.sol\";\nimport {CrossDomainEnabled} from \"./CrossDomainEnabled.sol\";\n\n/// @author psirex\n/// @notice The L1 ERC20 token bridge locks bridged tokens on the L1 side, sends deposit messages\n/// on the L2 side, and finalizes token withdrawals from L2. Additionally, adds the methods for\n/// bridging management: enabling and disabling withdrawals/deposits\ncontract L1ERC20TokenBridge is\n IL1ERC20Bridge,\n BridgingManager,\n BridgeableTokens,\n CrossDomainEnabled\n{\n using SafeERC20 for IERC20;\n\n /// @inheritdoc IL1ERC20Bridge\n address public immutable l2TokenBridge;\n\n /// @param messenger_ L1 messenger address being used for cross-chain communications\n /// @param l2TokenBridge_ Address of the corresponding L2 bridge\n /// @param l1Token_ Address of the bridged token in the L1 chain\n /// @param l2Token_ Address of the token minted on the L2 chain when token bridged\n constructor(\n address messenger_,\n address l2TokenBridge_,\n address l1Token_,\n address l2Token_\n ) CrossDomainEnabled(messenger_) BridgeableTokens(l1Token_, l2Token_) {\n l2TokenBridge = l2TokenBridge_;\n }\n\n /// @inheritdoc IL1ERC20Bridge\n function depositERC20(\n address l1Token_,\n address l2Token_,\n uint256 amount_,\n uint32 l2Gas_,\n bytes calldata data_\n )\n external\n whenDepositsEnabled\n onlySupportedL1Token(l1Token_)\n onlySupportedL2Token(l2Token_)\n {\n if (Address.isContract(msg.sender)) {\n revert ErrorSenderNotEOA();\n }\n _initiateERC20Deposit(msg.sender, msg.sender, amount_, l2Gas_, data_);\n }\n\n /// @inheritdoc IL1ERC20Bridge\n function depositERC20To(\n address l1Token_,\n address l2Token_,\n address to_,\n uint256 amount_,\n uint32 l2Gas_,\n bytes calldata data_\n )\n external\n whenDepositsEnabled\n onlyNonZeroAccount(to_)\n onlySupportedL1Token(l1Token_)\n onlySupportedL2Token(l2Token_)\n {\n _initiateERC20Deposit(msg.sender, to_, amount_, l2Gas_, data_);\n }\n\n /// @inheritdoc IL1ERC20Bridge\n function finalizeERC20Withdrawal(\n address l1Token_,\n address l2Token_,\n address from_,\n address to_,\n uint256 amount_,\n bytes calldata data_\n )\n external\n whenWithdrawalsEnabled\n onlySupportedL1Token(l1Token_)\n onlySupportedL2Token(l2Token_)\n onlyFromCrossDomainAccount(l2TokenBridge)\n {\n IERC20(l1Token_).safeTransfer(to_, amount_);\n\n emit ERC20WithdrawalFinalized(\n l1Token_,\n l2Token_,\n from_,\n to_,\n amount_,\n data_\n );\n }\n\n /// @dev Performs the logic for deposits by informing the L2 token bridge contract\n /// of the deposit and calling safeTransferFrom to lock the L1 funds.\n /// @param from_ Account to pull the deposit from on L1\n /// @param to_ Account to give the deposit to on L2\n /// @param amount_ Amount of the ERC20 to deposit.\n /// @param l2Gas_ Gas limit required to complete the deposit on L2.\n /// @param data_ Optional data to forward to L2. This data is provided\n /// solely as a convenience for external contracts. Aside from enforcing a maximum\n /// length, these contracts provide no guarantees about its content.\n function _initiateERC20Deposit(\n address from_,\n address to_,\n uint256 amount_,\n uint32 l2Gas_,\n bytes calldata data_\n ) internal {\n IERC20(l1Token).safeTransferFrom(from_, address(this), amount_);\n\n bytes memory message = abi.encodeWithSelector(\n IL2ERC20Bridge.finalizeDeposit.selector,\n l1Token,\n l2Token,\n from_,\n to_,\n amount_,\n data_\n );\n\n sendCrossDomainMessage(l2TokenBridge, l2Gas_, message);\n\n emit ERC20DepositInitiated(\n l1Token,\n l2Token,\n from_,\n to_,\n amount_,\n data_\n );\n }\n\n error ErrorSenderNotEOA();\n}\n" + }, + "contracts/optimism/L2ERC20TokenBridge.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {IL1ERC20Bridge} from \"./interfaces/IL1ERC20Bridge.sol\";\nimport {IL2ERC20Bridge} from \"./interfaces/IL2ERC20Bridge.sol\";\nimport {IERC20Bridged} from \"../token/interfaces/IERC20Bridged.sol\";\n\nimport {BridgingManager} from \"../BridgingManager.sol\";\nimport {BridgeableTokens} from \"../BridgeableTokens.sol\";\nimport {CrossDomainEnabled} from \"./CrossDomainEnabled.sol\";\n\n/// @author psirex\n/// @notice The L2 token bridge works with the L1 token bridge to enable ERC20 token bridging\n/// between L1 and L2. It acts as a minter for new tokens when it hears about\n/// deposits into the L1 token bridge. It also acts as a burner of the tokens\n/// intended for withdrawal, informing the L1 bridge to release L1 funds. Additionally, adds\n/// the methods for bridging management: enabling and disabling withdrawals/deposits\ncontract L2ERC20TokenBridge is\n IL2ERC20Bridge,\n BridgingManager,\n BridgeableTokens,\n CrossDomainEnabled\n{\n /// @inheritdoc IL2ERC20Bridge\n address public immutable l1TokenBridge;\n\n /// @param messenger_ L2 messenger address being used for cross-chain communications\n /// @param l1TokenBridge_ Address of the corresponding L1 bridge\n /// @param l1Token_ Address of the bridged token in the L1 chain\n /// @param l2Token_ Address of the token minted on the L2 chain when token bridged\n constructor(\n address messenger_,\n address l1TokenBridge_,\n address l1Token_,\n address l2Token_\n ) CrossDomainEnabled(messenger_) BridgeableTokens(l1Token_, l2Token_) {\n l1TokenBridge = l1TokenBridge_;\n }\n\n /// @inheritdoc IL2ERC20Bridge\n function withdraw(\n address l2Token_,\n uint256 amount_,\n uint32 l1Gas_,\n bytes calldata data_\n ) external whenWithdrawalsEnabled onlySupportedL2Token(l2Token_) {\n _initiateWithdrawal(msg.sender, msg.sender, amount_, l1Gas_, data_);\n }\n\n /// @inheritdoc IL2ERC20Bridge\n function withdrawTo(\n address l2Token_,\n address to_,\n uint256 amount_,\n uint32 l1Gas_,\n bytes calldata data_\n ) external whenWithdrawalsEnabled onlySupportedL2Token(l2Token_) {\n _initiateWithdrawal(msg.sender, to_, amount_, l1Gas_, data_);\n }\n\n /// @inheritdoc IL2ERC20Bridge\n function finalizeDeposit(\n address l1Token_,\n address l2Token_,\n address from_,\n address to_,\n uint256 amount_,\n bytes calldata data_\n )\n external\n whenDepositsEnabled\n onlySupportedL1Token(l1Token_)\n onlySupportedL2Token(l2Token_)\n onlyFromCrossDomainAccount(l1TokenBridge)\n {\n IERC20Bridged(l2Token_).bridgeMint(to_, amount_);\n emit DepositFinalized(l1Token_, l2Token_, from_, to_, amount_, data_);\n }\n\n /// @notice Performs the logic for withdrawals by burning the token and informing\n /// the L1 token Gateway of the withdrawal\n /// @param from_ Account to pull the withdrawal from on L2\n /// @param to_ Account to give the withdrawal to on L1\n /// @param amount_ Amount of the token to withdraw\n /// @param l1Gas_ Unused, but included for potential forward compatibility considerations\n /// @param data_ Optional data to forward to L1. This data is provided\n /// solely as a convenience for external contracts. Aside from enforcing a maximum\n /// length, these contracts provide no guarantees about its content\n function _initiateWithdrawal(\n address from_,\n address to_,\n uint256 amount_,\n uint32 l1Gas_,\n bytes calldata data_\n ) internal {\n IERC20Bridged(l2Token).bridgeBurn(from_, amount_);\n\n bytes memory message = abi.encodeWithSelector(\n IL1ERC20Bridge.finalizeERC20Withdrawal.selector,\n l1Token,\n l2Token,\n from_,\n to_,\n amount_,\n data_\n );\n\n sendCrossDomainMessage(l1TokenBridge, l1Gas_, message);\n\n emit WithdrawalInitiated(l1Token, l2Token, from_, to_, amount_, data_);\n }\n}\n" + }, + "contracts/optimism/stubs/CrossDomainMessengerStub.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {ICrossDomainMessenger} from \"../interfaces/ICrossDomainMessenger.sol\";\n\ncontract CrossDomainMessengerStub is ICrossDomainMessenger {\n address public xDomainMessageSender;\n uint256 public messageNonce;\n\n constructor() payable {}\n\n function setXDomainMessageSender(address value) external {\n xDomainMessageSender = value;\n }\n\n function sendMessage(\n address _target,\n bytes calldata _message,\n uint32 _gasLimit\n ) external {\n messageNonce += 1;\n emit SentMessage(\n _target,\n msg.sender,\n _message,\n messageNonce,\n _gasLimit\n );\n }\n\n function relayMessage(\n address _target,\n address, // sender\n bytes memory _message,\n uint256 // _messageNonce\n ) public {\n (bool success, ) = _target.call(_message);\n require(success, \"CALL_FAILED\");\n }\n\n event SentMessage(\n address indexed target,\n address sender,\n bytes message,\n uint256 messageNonce,\n uint256 gasLimit\n );\n}\n" + }, + "contracts/proxy/OssifiableProxy.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {Address} from \"@openzeppelin/contracts/utils/Address.sol\";\nimport {StorageSlot} from \"@openzeppelin/contracts/utils/StorageSlot.sol\";\nimport {ERC1967Proxy} from \"@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol\";\n\n/// @notice An ossifiable proxy contract. Extends the ERC1967Proxy contract by\n/// adding admin functionality\ncontract OssifiableProxy is ERC1967Proxy {\n /// @dev Initializes the upgradeable proxy with the initial implementation and admin\n /// @param implementation_ Address of the implementation\n /// @param admin_ Address of the admin of the proxy\n /// @param data_ Data used in a delegate call to implementation. The delegate call will be\n /// skipped if the data is empty bytes\n constructor(\n address implementation_,\n address admin_,\n bytes memory data_\n ) ERC1967Proxy(implementation_, data_) {\n _changeAdmin(admin_);\n }\n\n /// @notice Returns the current admin of the proxy\n function proxy__getAdmin() external view returns (address) {\n return _getAdmin();\n }\n\n /// @notice Returns the current implementation address\n function proxy__getImplementation() external view returns (address) {\n return _implementation();\n }\n\n /// @notice Returns whether the implementation is locked forever\n function proxy__getIsOssified() external view returns (bool) {\n return _getAdmin() == address(0);\n }\n\n /// @notice Allows to transfer admin rights to zero address and prevent future\n /// upgrades of the proxy\n function proxy__ossify() external onlyAdmin {\n address prevAdmin = _getAdmin();\n StorageSlot.getAddressSlot(_ADMIN_SLOT).value = address(0);\n emit AdminChanged(prevAdmin, address(0));\n emit ProxyOssified();\n }\n\n /// @notice Changes the admin of the proxy\n /// @param newAdmin_ Address of the new admin\n function proxy__changeAdmin(address newAdmin_) external onlyAdmin {\n _changeAdmin(newAdmin_);\n }\n\n /// @notice Upgrades the implementation of the proxy\n /// @param newImplementation_ Address of the new implementation\n function proxy__upgradeTo(address newImplementation_) external onlyAdmin {\n _upgradeTo(newImplementation_);\n }\n\n /// @notice Upgrades the proxy to a new implementation, optionally performing an additional\n /// setup call.\n /// @param newImplementation_ Address of the new implementation\n /// @param setupCalldata_ Data for the setup call. The call is skipped if setupCalldata_ is\n /// empty and forceCall_ is false\n /// @param forceCall_ Forces make delegate call to the implementation even with empty data_\n function proxy__upgradeToAndCall(\n address newImplementation_,\n bytes memory setupCalldata_,\n bool forceCall_\n ) external onlyAdmin {\n _upgradeToAndCall(newImplementation_, setupCalldata_, forceCall_);\n }\n\n /// @dev Validates that proxy is not ossified and that method is called by the admin\n /// of the proxy\n modifier onlyAdmin() {\n address admin = _getAdmin();\n if (admin == address(0)) {\n revert ErrorProxyIsOssified();\n }\n if (admin != msg.sender) {\n revert ErrorNotAdmin();\n }\n _;\n }\n\n event ProxyOssified();\n\n error ErrorNotAdmin();\n error ErrorProxyIsOssified();\n}\n" + }, + "contracts/proxy/stubs/VersionizedImplementationStub.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\ncontract InitializableImplementationStub {\n uint8 public version;\n\n function initialize(uint8 version_) external {\n version = version_;\n emit Initialized(version);\n }\n\n fallback() external {\n emit FallbackIsFired();\n }\n\n event Initialized(uint256 version);\n event FallbackIsFired();\n}\n" + }, + "contracts/stubs/EmptyContractStub.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\ncontract EmptyContractStub {\n constructor() payable {}\n}\n" + }, + "contracts/stubs/ERC20BridgedStub.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {IERC20Bridged} from \"../token/interfaces/IERC20Bridged.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract ERC20BridgedStub is IERC20Bridged, ERC20 {\n address public bridge;\n\n constructor(string memory name_, string memory symbol_)\n ERC20(name_, symbol_)\n {\n _mint(msg.sender, 1000000 * 10**18);\n }\n\n function setBridge(address bridge_) external {\n bridge = bridge_;\n }\n\n function bridgeMint(address account, uint256 amount) external {\n _mint(account, amount);\n }\n\n function bridgeBurn(address account, uint256 amount) external {\n _burn(account, amount);\n }\n}\n" + }, + "contracts/token/ERC20Bridged.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {IERC20Bridged} from \"./interfaces/IERC20Bridged.sol\";\n\nimport {ERC20Core} from \"./ERC20Core.sol\";\nimport {ERC20Metadata} from \"./ERC20Metadata.sol\";\n\n/// @author psirex\n/// @notice Extends the ERC20 functionality that allows the bridge to mint/burn tokens\ncontract ERC20Bridged is IERC20Bridged, ERC20Core, ERC20Metadata {\n /// @inheritdoc IERC20Bridged\n address public immutable bridge;\n\n /// @param name_ The name of the token\n /// @param symbol_ The symbol of the token\n /// @param decimals_ The decimals places of the token\n /// @param bridge_ The bridge address which allowd to mint/burn tokens\n constructor(\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address bridge_\n ) ERC20Metadata(name_, symbol_, decimals_) {\n bridge = bridge_;\n }\n\n /// @notice Sets the name and the symbol of the tokens if they both are empty\n /// @param name_ The name of the token\n /// @param symbol_ The symbol of the token\n function initialize(string memory name_, string memory symbol_) external {\n _setERC20MetadataName(name_);\n _setERC20MetadataSymbol(symbol_);\n }\n\n /// @inheritdoc IERC20Bridged\n function bridgeMint(address account_, uint256 amount_) external onlyBridge {\n _mint(account_, amount_);\n }\n\n /// @inheritdoc IERC20Bridged\n function bridgeBurn(address account_, uint256 amount_) external onlyBridge {\n _burn(account_, amount_);\n }\n\n /// @dev Validates that sender of the transaction is the bridge\n modifier onlyBridge() {\n if (msg.sender != bridge) {\n revert ErrorNotBridge();\n }\n _;\n }\n\n error ErrorNotBridge();\n}\n" + }, + "contracts/token/ERC20Core.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/// @author psirex\n/// @notice Contains the required logic of the ERC20 standard as defined in the EIP. Additionally\n/// provides methods for direct allowance increasing/decreasing.\ncontract ERC20Core is IERC20 {\n /// @inheritdoc IERC20\n uint256 public totalSupply;\n\n /// @inheritdoc IERC20\n mapping(address => uint256) public balanceOf;\n\n /// @inheritdoc IERC20\n mapping(address => mapping(address => uint256)) public allowance;\n\n /// @inheritdoc IERC20\n function approve(address spender_, uint256 amount_)\n external\n returns (bool)\n {\n _approve(msg.sender, spender_, amount_);\n return true;\n }\n\n /// @inheritdoc IERC20\n function transfer(address to_, uint256 amount_) external returns (bool) {\n _transfer(msg.sender, to_, amount_);\n return true;\n }\n\n /// @inheritdoc IERC20\n function transferFrom(\n address from_,\n address to_,\n uint256 amount_\n ) external returns (bool) {\n _spendAllowance(from_, msg.sender, amount_);\n _transfer(from_, to_, amount_);\n return true;\n }\n\n /// @notice Atomically increases the allowance granted to spender by the caller.\n /// @param spender_ An address of the tokens spender\n /// @param addedValue_ An amount to increase the allowance\n function increaseAllowance(address spender_, uint256 addedValue_)\n external\n returns (bool)\n {\n _approve(\n msg.sender,\n spender_,\n allowance[msg.sender][spender_] + addedValue_\n );\n return true;\n }\n\n /// @notice Atomically decreases the allowance granted to spender by the caller.\n /// @param spender_ An address of the tokens spender\n /// @param subtractedValue_ An amount to decrease the allowance\n function decreaseAllowance(address spender_, uint256 subtractedValue_)\n external\n returns (bool)\n {\n uint256 currentAllowance = allowance[msg.sender][spender_];\n if (currentAllowance < subtractedValue_) {\n revert ErrorDecreasedAllowanceBelowZero();\n }\n unchecked {\n _approve(msg.sender, spender_, currentAllowance - subtractedValue_);\n }\n return true;\n }\n\n /// @dev Moves amount_ of tokens from sender_ to recipient_\n /// @param from_ An address of the sender of the tokens\n /// @param to_ An address of the recipient of the tokens\n /// @param amount_ An amount of tokens to transfer\n function _transfer(\n address from_,\n address to_,\n uint256 amount_\n ) internal onlyNonZeroAccount(from_) onlyNonZeroAccount(to_) {\n _decreaseBalance(from_, amount_);\n balanceOf[to_] += amount_;\n emit Transfer(from_, to_, amount_);\n }\n\n /// @dev Updates owner_'s allowance for spender_ based on spent amount_. Does not update\n /// the allowance amount in case of infinite allowance\n /// @param owner_ An address of the account to spend allowance\n /// @param spender_ An address of the spender of the tokens\n /// @param amount_ An amount of allowance spend\n function _spendAllowance(\n address owner_,\n address spender_,\n uint256 amount_\n ) internal {\n uint256 currentAllowance = allowance[owner_][spender_];\n if (currentAllowance == type(uint256).max) {\n return;\n }\n if (amount_ > currentAllowance) {\n revert ErrorNotEnoughAllowance();\n }\n unchecked {\n _approve(owner_, spender_, currentAllowance - amount_);\n }\n }\n\n /// @dev Sets amount_ as the allowance of spender_ over the owner_'s tokens\n /// @param owner_ An address of the account to set allowance\n /// @param spender_ An address of the tokens spender\n /// @param amount_ An amount of tokens to allow to spend\n function _approve(\n address owner_,\n address spender_,\n uint256 amount_\n ) internal virtual onlyNonZeroAccount(owner_) onlyNonZeroAccount(spender_) {\n allowance[owner_][spender_] = amount_;\n emit Approval(owner_, spender_, amount_);\n }\n\n /// @dev Creates amount_ tokens and assigns them to account_, increasing the total supply\n /// @param account_ An address of the account to mint tokens\n /// @param amount_ An amount of tokens to mint\n function _mint(address account_, uint256 amount_)\n internal\n onlyNonZeroAccount(account_)\n {\n totalSupply += amount_;\n balanceOf[account_] += amount_;\n emit Transfer(address(0), account_, amount_);\n }\n\n /// @dev Destroys amount_ tokens from account_, reducing the total supply.\n /// @param account_ An address of the account to mint tokens\n /// @param amount_ An amount of tokens to mint\n function _burn(address account_, uint256 amount_)\n internal\n onlyNonZeroAccount(account_)\n {\n _decreaseBalance(account_, amount_);\n totalSupply -= amount_;\n emit Transfer(account_, address(0), amount_);\n }\n\n /// @dev Decreases the balance of the account_\n /// @param account_ An address of the account to decrease balance\n /// @param amount_ An amount of balance decrease\n function _decreaseBalance(address account_, uint256 amount_) internal {\n uint256 balance = balanceOf[account_];\n\n if (amount_ > balance) {\n revert ErrorNotEnoughBalance();\n }\n unchecked {\n balanceOf[account_] = balance - amount_;\n }\n }\n\n /// @dev validates that account_ is not zero address\n modifier onlyNonZeroAccount(address account_) {\n if (account_ == address(0)) {\n revert ErrorAccountIsZeroAddress();\n }\n _;\n }\n\n error ErrorNotEnoughBalance();\n error ErrorNotEnoughAllowance();\n error ErrorAccountIsZeroAddress();\n error ErrorDecreasedAllowanceBelowZero();\n}\n" + }, + "contracts/token/ERC20Metadata.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {IERC20Metadata} from \"./interfaces/IERC20Metadata.sol\";\n\n/// @author psirex\n/// @notice Contains the optional metadata functions from the ERC20 standard\n/// @dev Uses the UnstructuredStorage pattern to store dynamic name and symbol data. Might be used\n/// with the upgradable proxies\ncontract ERC20Metadata is IERC20Metadata {\n /// @dev Stores the dynamic metadata of the ERC20 token. Allows safely use of this\n /// contract with upgradable proxies\n struct DynamicMetadata {\n string name;\n string symbol;\n }\n\n /// @dev Location of the slot with DynamicMetdata\n bytes32 private constant DYNAMIC_METADATA_SLOT =\n keccak256(\"ERC20Metdata.dynamicMetadata\");\n\n /// @inheritdoc IERC20Metadata\n uint8 public immutable decimals;\n\n /// @param name_ Name of the token\n /// @param symbol_ Symbol of the token\n /// @param decimals_ Decimals places of the token\n constructor(\n string memory name_,\n string memory symbol_,\n uint8 decimals_\n ) {\n decimals = decimals_;\n _setERC20MetadataName(name_);\n _setERC20MetadataSymbol(symbol_);\n }\n\n /// @inheritdoc IERC20Metadata\n function name() public view returns (string memory) {\n return _loadDynamicMetadata().name;\n }\n\n /// @inheritdoc IERC20Metadata\n function symbol() public view returns (string memory) {\n return _loadDynamicMetadata().symbol;\n }\n\n /// @dev Sets the name of the token. Might be called only when the name is empty\n function _setERC20MetadataName(string memory name_) internal {\n if (bytes(name()).length > 0) {\n revert ErrorNameAlreadySet();\n }\n _loadDynamicMetadata().name = name_;\n }\n\n /// @dev Sets the symbol of the token. Might be called only when the symbol is empty\n function _setERC20MetadataSymbol(string memory symbol_) internal {\n if (bytes(symbol()).length > 0) {\n revert ErrorSymbolAlreadySet();\n }\n _loadDynamicMetadata().symbol = symbol_;\n }\n\n /// @dev Returns the reference to the slot with DynamicMetadta struct\n function _loadDynamicMetadata()\n private\n pure\n returns (DynamicMetadata storage r)\n {\n bytes32 slot = DYNAMIC_METADATA_SLOT;\n assembly {\n r.slot := slot\n }\n }\n\n error ErrorNameAlreadySet();\n error ErrorSymbolAlreadySet();\n}\n" + }, + "contracts/token/interfaces/IERC20Bridged.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/// @author psirex\n/// @notice Extends the ERC20 functionality that allows the bridge to mint/burn tokens\ninterface IERC20Bridged is IERC20 {\n /// @notice Returns bridge which can mint and burn tokens on L2\n function bridge() external view returns (address);\n\n /// @notice Creates amount_ tokens and assigns them to account_, increasing the total supply\n /// @param account_ An address of the account to mint tokens\n /// @param amount_ An amount of tokens to mint\n function bridgeMint(address account_, uint256 amount_) external;\n\n /// @notice Destroys amount_ tokens from account_, reducing the total supply\n /// @param account_ An address of the account to burn tokens\n /// @param amount_ An amount of tokens to burn\n function bridgeBurn(address account_, uint256 amount_) external;\n}\n" + }, + "contracts/token/interfaces/IERC20Metadata.sol": { + "content": "// SPDX-FileCopyrightText: 2022 Lido \n// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.10;\n\n/// @author psirex\n/// @notice Interface for the optional metadata functions from the ERC20 standard.\ninterface IERC20Metadata {\n /// @dev Returns the name of the token.\n function name() external view returns (string memory);\n\n /// @dev Returns the symbol of the token.\n function symbol() external view returns (string memory);\n\n /// @dev Returns the decimals places of the token.\n function decimals() external view returns (uint8);\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 100000 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/hardhat.config.ts b/hardhat.config.ts index 6c80b0c..f702ba9 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -6,13 +6,24 @@ import "@nomiclabs/hardhat-waffle"; import "@typechain/hardhat"; import "hardhat-gas-reporter"; import "solidity-coverage"; +import "hardhat-deploy" import "./tasks/fork-node"; import env from "./utils/env"; dotenv.config(); +const ethDeployerPk: string | undefined = process.env.ETH_DEPLOYER_PRIVATE_KEY; +if (!ethDeployerPk) { + throw new Error('Please set your ETH_DEPLOYER_PRIVATE_KEY in a .env file'); +} + const config: HardhatUserConfig = { + namedAccounts: { + deployer: { + default: 0, // here this will by default take the first account as deployer + }, + }, solidity: { compilers: [ { @@ -39,9 +50,13 @@ const config: HardhatUserConfig = { // Ethereum Public Chains eth_mainnet: { url: env.string("RPC_ETH_MAINNET", ""), + deploy: ['./scripts/manta/deploy'], + accounts: [`0x${ethDeployerPk}`], }, eth_sepolia: { url: env.string("RPC_ETH_SEPOLIA", ""), + deploy: ['./scripts/manta/deploy'], + accounts: [`0x${ethDeployerPk}`], }, // Ethereum Fork Chains @@ -72,6 +87,7 @@ const config: HardhatUserConfig = { opt_mainnet: { url: env.string("RPC_OPT_MAINNET", ""), }, + // @NOTE: currently used for manta L2 opt_sepolia: { url: env.string("RPC_OPT_SEPOLIA", ""), }, @@ -92,6 +108,8 @@ const config: HardhatUserConfig = { apiKey: { mainnet: env.string("ETHERSCAN_API_KEY_ETH", ""), sepolia: env.string("ETHERSCAN_API_KEY_ETH", ""), + eth_sepolia: env.string("ETHERSCAN_API_KEY_ETH", ""), + eth_mainnet: 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", ""), diff --git a/package-lock.json b/package-lock.json index cfddd6b..66dc85d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,6 +39,7 @@ "ethereum-waffle": "^3.4.4", "ethers": "^5.6.2", "hardhat": "^2.12.2", + "hardhat-deploy": "^0.12.2", "hardhat-gas-reporter": "^1.0.8", "prettier": "^2.6.1", "prettier-plugin-solidity": "^1.0.0-beta.13", @@ -4354,6 +4355,15 @@ "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", "dev": true }, + "node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -4779,13 +4789,19 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5565,6 +5581,23 @@ "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", "dev": true }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/define-properties": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", @@ -5745,6 +5778,12 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "node_modules/encode-utf8": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", + "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==", + "dev": true + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -5852,6 +5891,27 @@ "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", "dev": true }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-set-tostringtag": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", @@ -7802,6 +7862,15 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/fmix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/fmix/-/fmix-0.1.0.tgz", + "integrity": "sha512-Y6hyofImk9JdzU8k5INtTXX1cu8LDlePWDFU5sftm9H+zKCr5SGrVjdhkvsim646cw5zD0nADj8oHyXMZmCZ9w==", + "dev": true, + "dependencies": { + "imul": "^1.0.0" + } + }, "node_modules/follow-redirects": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", @@ -7934,10 +8003,13 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/function.prototype.name": { "version": "1.1.5", @@ -17168,15 +17240,19 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -17619,6 +17695,102 @@ } } }, + "node_modules/hardhat-deploy": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/hardhat-deploy/-/hardhat-deploy-0.12.2.tgz", + "integrity": "sha512-Xp/4Lb5lC/j3kvitaWW5IZN5Meqv5D3kTIifc3ZwBoQtFLN26/fDfRV6MWAAcRO9gH64hZVokvtcDdl/fd7w3A==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/contracts": "^5.7.0", + "@ethersproject/providers": "^5.7.2", + "@ethersproject/solidity": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wallet": "^5.7.0", + "@types/qs": "^6.9.7", + "axios": "^0.21.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.2", + "debug": "^4.3.2", + "enquirer": "^2.3.6", + "ethers": "^5.7.0", + "form-data": "^4.0.0", + "fs-extra": "^10.0.0", + "match-all": "^1.2.6", + "murmur-128": "^0.2.1", + "qs": "^6.9.4", + "zksync-ethers": "^5.0.0" + } + }, + "node_modules/hardhat-deploy/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/hardhat-deploy/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/hardhat-deploy/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/hardhat-deploy/node_modules/qs": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.0.tgz", + "integrity": "sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hardhat-deploy/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/hardhat-gas-reporter": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.9.tgz", @@ -17812,12 +17984,12 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.1" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -17903,6 +18075,18 @@ "minimalistic-assert": "^1.0.1" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -18101,6 +18285,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/imul": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/imul/-/imul-1.0.1.tgz", + "integrity": "sha512-WFAgfwPLAjU66EKt6vRdTlKj4nAgIDQzh29JonLa4Bqtl6D8JrIMvWjCnx7xEjVNmP3U0fM5o8ZObk7d0f62bA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -19001,6 +19194,12 @@ "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", "dev": true }, + "node_modules/match-all": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/match-all/-/match-all-1.2.6.tgz", + "integrity": "sha512-0EESkXiTkWzrQQntBu2uzKvLu6vVkUGz40nGPbSZuegcfE5UuSzNjLaIu76zJWuaT/2I3Z/8M06OlUOZLGwLlQ==", + "dev": true + }, "node_modules/mcl-wasm": { "version": "0.7.9", "resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz", @@ -19549,6 +19748,17 @@ "buffer": "^5.5.0" } }, + "node_modules/murmur-128": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/murmur-128/-/murmur-128-0.2.1.tgz", + "integrity": "sha512-WseEgiRkI6aMFBbj8Cg9yBj/y+OdipwVC7zUo3W2W1JAJITwouUOtpqsmGSg67EQmwwSyod7hsVsWY5LsrfQVg==", + "dev": true, + "dependencies": { + "encode-utf8": "^1.0.2", + "fmix": "^0.1.0", + "imul": "^1.0.0" + } + }, "node_modules/nano-json-stream-parser": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", @@ -19774,9 +19984,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -21334,6 +21544,23 @@ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -21409,14 +21636,18 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -24814,6 +25045,21 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zksync-ethers": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/zksync-ethers/-/zksync-ethers-5.6.0.tgz", + "integrity": "sha512-+lw1dhURpVZos6+g82HdXVw2i/OI+S2nTqyNvBK2xwnQYv8vqxv0Ux/cMPV2AflswTG1/zrMmseRp+UJUCaw9g==", + "dev": true, + "dependencies": { + "ethers": "~5.7.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "ethers": "~5.7.0" + } } }, "dependencies": { @@ -28156,6 +28402,15 @@ "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", "dev": true }, + "axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dev": true, + "requires": { + "follow-redirects": "^1.14.0" + } + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -28497,13 +28752,16 @@ } }, "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" } }, "callsites": { @@ -29113,6 +29371,17 @@ "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", "dev": true }, + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } + }, "define-properties": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", @@ -29265,6 +29534,12 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "encode-utf8": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", + "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==", + "dev": true + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -29357,6 +29632,21 @@ "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", "dev": true }, + "es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.4" + } + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true + }, "es-set-tostringtag": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", @@ -30911,6 +31201,15 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "fmix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/fmix/-/fmix-0.1.0.tgz", + "integrity": "sha512-Y6hyofImk9JdzU8k5INtTXX1cu8LDlePWDFU5sftm9H+zKCr5SGrVjdhkvsim646cw5zD0nADj8oHyXMZmCZ9w==", + "dev": true, + "requires": { + "imul": "^1.0.0" + } + }, "follow-redirects": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", @@ -31007,9 +31306,9 @@ "optional": true }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true }, "function.prototype.name": { @@ -38099,15 +38398,16 @@ "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==" }, "get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" } }, "get-port": { @@ -38565,6 +38865,87 @@ } } }, + "hardhat-deploy": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/hardhat-deploy/-/hardhat-deploy-0.12.2.tgz", + "integrity": "sha512-Xp/4Lb5lC/j3kvitaWW5IZN5Meqv5D3kTIifc3ZwBoQtFLN26/fDfRV6MWAAcRO9gH64hZVokvtcDdl/fd7w3A==", + "dev": true, + "requires": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/contracts": "^5.7.0", + "@ethersproject/providers": "^5.7.2", + "@ethersproject/solidity": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wallet": "^5.7.0", + "@types/qs": "^6.9.7", + "axios": "^0.21.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.2", + "debug": "^4.3.2", + "enquirer": "^2.3.6", + "ethers": "^5.7.0", + "form-data": "^4.0.0", + "fs-extra": "^10.0.0", + "match-all": "^1.2.6", + "murmur-128": "^0.2.1", + "qs": "^6.9.4", + "zksync-ethers": "^5.0.0" + }, + "dependencies": { + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "qs": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.0.tgz", + "integrity": "sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==", + "dev": true, + "requires": { + "side-channel": "^1.0.6" + } + }, + "universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true + } + } + }, "hardhat-gas-reporter": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.9.tgz", @@ -38597,12 +38978,12 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "requires": { - "get-intrinsic": "^1.1.1" + "es-define-property": "^1.0.0" } }, "has-proto": { @@ -38652,6 +39033,15 @@ "minimalistic-assert": "^1.0.1" } }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -38804,6 +39194,12 @@ "resolve-from": "^4.0.0" } }, + "imul": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/imul/-/imul-1.0.1.tgz", + "integrity": "sha512-WFAgfwPLAjU66EKt6vRdTlKj4nAgIDQzh29JonLa4Bqtl6D8JrIMvWjCnx7xEjVNmP3U0fM5o8ZObk7d0f62bA==", + "dev": true + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -39481,6 +39877,12 @@ "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", "dev": true }, + "match-all": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/match-all/-/match-all-1.2.6.tgz", + "integrity": "sha512-0EESkXiTkWzrQQntBu2uzKvLu6vVkUGz40nGPbSZuegcfE5UuSzNjLaIu76zJWuaT/2I3Z/8M06OlUOZLGwLlQ==", + "dev": true + }, "mcl-wasm": { "version": "0.7.9", "resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz", @@ -39895,6 +40297,17 @@ } } }, + "murmur-128": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/murmur-128/-/murmur-128-0.2.1.tgz", + "integrity": "sha512-WseEgiRkI6aMFBbj8Cg9yBj/y+OdipwVC7zUo3W2W1JAJITwouUOtpqsmGSg67EQmwwSyod7hsVsWY5LsrfQVg==", + "dev": true, + "requires": { + "encode-utf8": "^1.0.2", + "fmix": "^0.1.0", + "imul": "^1.0.0" + } + }, "nano-json-stream-parser": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", @@ -40070,9 +40483,9 @@ "dev": true }, "object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "dev": true }, "object-keys": { @@ -41247,6 +41660,20 @@ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + } + }, "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -41304,14 +41731,15 @@ } }, "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" } }, "simple-concat": { @@ -44062,6 +44490,15 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true + }, + "zksync-ethers": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/zksync-ethers/-/zksync-ethers-5.6.0.tgz", + "integrity": "sha512-+lw1dhURpVZos6+g82HdXVw2i/OI+S2nTqyNvBK2xwnQYv8vqxv0Ux/cMPV2AflswTG1/zrMmseRp+UJUCaw9g==", + "dev": true, + "requires": { + "ethers": "~5.7.0" + } } } } diff --git a/package.json b/package.json index 820a38e..4b564b1 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "ethereum-waffle": "^3.4.4", "ethers": "^5.6.2", "hardhat": "^2.12.2", + "hardhat-deploy": "^0.12.2", "hardhat-gas-reporter": "^1.0.8", "prettier": "^2.6.1", "prettier-plugin-solidity": "^1.0.0-beta.13", diff --git a/scripts/manta/deploy/deploy-manta-staker.ts b/scripts/manta/deploy/deploy-manta-staker.ts new file mode 100644 index 0000000..c54a04a --- /dev/null +++ b/scripts/manta/deploy/deploy-manta-staker.ts @@ -0,0 +1,33 @@ +// npx hardhat deploy --network eth_sepolia + +import { ethers } from 'hardhat'; +import { DeployFunction } from 'hardhat-deploy/dist/types'; +import { HardhatRuntimeEnvironment } from 'hardhat/types'; + +const func: DeployFunction = async function ({ + getNamedAccounts, + deployments, + network, +}: HardhatRuntimeEnvironment) { + const { deploy } = deployments; + const { deployer } = await getNamedAccounts(); + + console.log(`network: ${network.name}`); + + // deploy board manager + const stakeHelper = await deploy('StakeHelper', { + from: deployer, + log: true, + deterministicDeployment: false, + args: [ + '0xB82381A3fBD3FaFA77B3a7bE693342618240067b', + '0x9b72b0D75e2eb87579694E842741738d3a9C311E', + '0xCB4619437C5Bb35d26346DeA9FeB9bD73c4f2633', + ] + }); +}; + +func.id = 'StakeHelper'; +func.tags = ['StakeHelper']; + +export default func; diff --git a/scripts/manta/stake.ts b/scripts/manta/stake.ts new file mode 100644 index 0000000..e656d34 --- /dev/null +++ b/scripts/manta/stake.ts @@ -0,0 +1,60 @@ +// npx hardhat run scripts/manta/stake.ts --network eth_sepolia +import { ethers, getNamedAccounts, config } from 'hardhat' +import { CrossChainMessenger, MessageDirection, MessageStatus } from '@eth-optimism/sdk' +import { address, abi } from '../../deployments/eth_sepolia/StakeHelper.json' +import { StakeHelper } from '../../typechain' + +async function run() { + const l1Provider = new ethers.providers.JsonRpcProvider('https://rpc.ankr.com/eth_sepolia') + const l2Provider = new ethers.providers.JsonRpcProvider('https://rpc.ankr.com/eth_sepolia') + + const crossDomainMessenger = new CrossChainMessenger({ + l1ChainId: (await l1Provider.getNetwork()).chainId, + l2ChainId: (await l2Provider.getNetwork()).chainId, + l1SignerOrProvider: l1Provider, + l2SignerOrProvider: l2Provider, + contracts: { + l1: { + L1CrossDomainMessenger: '0xFe7cF31c4579bb1C578716e04E1Ae16Ac5549fF0', + AddressManager: '0x0691B7aaAc9B903c9a99B2371bCFB43601B45711', + L1StandardBridge: '0xCAD25C95679839996F3162d8657B1CAe4517F78f', + OptimismPortal: '0x80f86c5d3AE8cF84596FF22DB2829F1b7a9Fe83d', + L2OutputOracle: '0x2dd44d1b04170C5623cCc55DD5ed43FAB08b0B46', + // l1RPCUrl: + // 'https://eth-sepolia.g.alchemy.com/v2/BQ43RWiHw-hqyM4NVLrzcYSm-ybT5tYN', + // l2RPCUrl: 'https://pacific-rpc.sepolia-testnet.manta.network/http', + StateCommitmentChain: '0x0000000000000000000000000000000000000000', + CanonicalTransactionChain: '0x0000000000000000000000000000000000000000', + BondManager: '0x0000000000000000000000000000000000000000', + }, + l2: { + L2CrossDomainMessenger: '0x4200000000000000000000000000000000000007' + } + } + }); + + const stakeHelper = new ethers.Contract(address, abi, l1Provider) as StakeHelper + + const { deployer: deployerAddress } = await getNamedAccounts() + const deployer = await ethers.getSigner(deployerAddress) + console.log('start staking') + const tx = await stakeHelper.connect(deployer).stakeETH( + deployer.address, + 2_000_000, + '0x', + { + value: ethers.utils.parseEther('0.00001') + } + ) + await tx.wait() + console.log('tx hash', tx.hash) + + const messages = await crossDomainMessenger.getMessagesByTransaction('0x79d0e5e5b6977d108b1e5e5c289e2a4ce67b0411e03bc92ae01a74bfcf4f9d4e', { + direction: MessageDirection.L1_TO_L2 + }); + console.log('messages', messages) + const status = await crossDomainMessenger.getMessageStatus(messages[0]) + console.log('message status', status) +} + +run() \ No newline at end of file diff --git a/scripts/test.ts b/scripts/test.ts deleted file mode 100644 index 1590405..0000000 --- a/scripts/test.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ethers } from "hardhat"; -import L1TokenBridgeABI from '../abi/L1TokenBridge' -import { L1ERC20TokenBridge } from "../typechain"; - -async function test() { - const provider = new ethers.providers.JsonRpcProvider('https://rpc.ankr.com/eth_sepolia') - const l1ERC20TokenBridge = new ethers.Contract('0xcb4619437c5bb35d26346dea9feb9bd73c4f2633', L1TokenBridgeABI, provider) as L1ERC20TokenBridge - const wallet = new ethers.Wallet('', provider) - console.log('send') - const tx = await l1ERC20TokenBridge - .connect(wallet) - .depositERC20To( - '0xB82381A3fBD3FaFA77B3a7bE693342618240067b', - '0x9b72b0D75e2eb87579694E842741738d3a9C311E', - '0xAf5B6AE540fCf3BD76f1b4C83fC87143932AAd09', - ethers.utils.parseEther('0.0001'), - 2_000_000, - "0x" - ); - console.log('done', await tx.wait()) -} - -test() \ No newline at end of file