From bcc11fd25f1c8cbaac63511a3603f79e8da348d3 Mon Sep 17 00:00:00 2001 From: TucksonDev Date: Mon, 4 Nov 2024 15:00:34 +0000 Subject: [PATCH 1/3] Update tutorials 3 --- packages/delayedInbox-l2msg/.env-sample | 18 +-- packages/delayedInbox-l2msg/README.md | 29 ++-- .../delayedInbox-l2msg/contracts/greeter.sol | 4 +- packages/delayedInbox-l2msg/hardhat.config.js | 1 - packages/delayedInbox-l2msg/package.json | 6 +- .../delayedInbox-l2msg/scripts/normalTx.js | 142 ++++++++++-------- .../scripts/withdrawFunds.js | 116 +++++++------- .../.env-sample | 18 +-- .../.gitignore | 4 - .../README.md | 32 ++-- .../package.json | 9 +- .../scripts/exec.js | 106 +++++++------ packages/eth-deposit/.env-sample | 18 +-- packages/eth-deposit/.gitignore | 4 - packages/eth-deposit/README.md | 26 ++-- packages/eth-deposit/package.json | 9 +- packages/eth-deposit/scripts/exec.js | 109 ++++++++------ packages/eth-withdraw/.env-sample | 18 +-- packages/eth-withdraw/.gitignore | 5 - packages/eth-withdraw/README.md | 36 ++--- packages/eth-withdraw/package.json | 9 +- packages/eth-withdraw/scripts/exec.js | 64 ++++---- yarn.lock | 4 +- 23 files changed, 390 insertions(+), 397 deletions(-) delete mode 100644 packages/eth-deposit-to-different-address/.gitignore delete mode 100644 packages/eth-deposit/.gitignore delete mode 100644 packages/eth-withdraw/.gitignore diff --git a/packages/delayedInbox-l2msg/.env-sample b/packages/delayedInbox-l2msg/.env-sample index d5c0a54..146828e 100644 --- a/packages/delayedInbox-l2msg/.env-sample +++ b/packages/delayedInbox-l2msg/.env-sample @@ -1,15 +1,13 @@ # This is a sample .env file for use in local development. - # Duplicate this file as .env here -# Your Private key - -DEVNET_PRIVKEY ='0x your key here' - -# Hosted Aggregator Node (JSON-RPC Endpoint) - -L2RPC="https://sepolia-rollup.arbitrum.io/rpc" +# Your private key +PRIVATE_KEY="0x your key here" -# Ethereum RPC; i.e., for Sepolia https://sepolia.infura.io/v3/ +# The main chain's RPC +# (this can be an Arbitrum network, or your Orbit chain) +CHAIN_RPC="https://sepolia-rollup.arbitrum.io/rpc" -L1RPC= +# The parent chain's RPC +# (this can be Ethereum, or the chain your Orbit chain settles to) +PARENT_CHAIN_RPC="https://sepolia.infura.io/v3/" diff --git a/packages/delayedInbox-l2msg/README.md b/packages/delayedInbox-l2msg/README.md index e56d00c..ac8bf29 100644 --- a/packages/delayedInbox-l2msg/README.md +++ b/packages/delayedInbox-l2msg/README.md @@ -1,14 +1,17 @@ -# delayedInbox-l2msg Tutorial +# Tutorial: send a message from the parent chain -(Note this can only be done in nitro stack, not in Arbitrum classic.) +`delayedInbox-l2msg` shows how to send a message to your chain (also referred to as an L2Message) only using an RPC of the parent chain. This demo has 2 parts: -delayedInbox-l2msg is a simple sample example that allows you to send a l2 msg without using sequencer way, this can be used when a sequencer censors your tx or when a sequencer is down. +1. how to send a normal transaction using the delayed inbox ([./scripts/normalTx.js](./scripts/normalTx.js)) +2. how to withdraw your funds back without sending a transaction directly to the sequencer ([./scripts/withdrawFunds.js](./scripts/withdrawFunds.js)) -The demo allows you to send an L2 message without having to use the L2 RPC (only using the L1 RPC). This demo has 2 parts; (1) one part will show how to send a normal L2 transaction using the delayed inbox, (2) another will show how to withdraw your funds back without the sequencer. +## Bypassing the sequencer -If the sequencer goes down when running the `Withdraw Funds`, you need to use our [Arbitrum SDK](https://github.com/OffchainLabs/arbitrum-sdk/blob/master/src/lib/inbox/inbox.ts#L256) to force include your tx to continue. (example [here](https://github.com/OffchainLabs/arbitrum-sdk/blob/401fa424bb4c21b54b77d95fbc95faec15787fe2/fork_test/inbox.test.ts#L131)) +This tutorial also shows the initial step to take if the [sequencer is misbehaving](https://docs.arbitrum.io/how-arbitrum-works/sequencer#unhappyuncommon-case-sequencer-isnt-doing-its-job). In that case, after 24 hours have passed from the moment the message was sent from the parent chain, you can use the SequencerInbox's `forceInclusion` method to move it from the delayed inbox into the core inbox, at which point it's considered finalized. -## Config Environment Variables +You can also use the [Arbitrum SDK](https://github.com/OffchainLabs/arbitrum-sdk/blob/v4.0.1/src/lib/inbox/inbox.ts#L349-L355) to force include your transaction. See an example [here](https://github.com/OffchainLabs/arbitrum-sdk/blob/v4.0.1/tests/fork/inbox.test.ts#L112). + +## Set environment variables Set the values shown in `.env-sample` as environmental variables. To copy it into a `.env` file: @@ -16,26 +19,24 @@ Set the values shown in `.env-sample` as environmental variables. To copy it int cp .env-sample .env ``` -(you'll still need to edit some variables, i.e., `DEVNET_PRIVKEY`) +You'll still need to edit some variables, i.e., `PRIVATE_KEY`, `CHAIN_RPC` and `PARENT_CHAIN_RPC`. + +Note that you can also set the environment variables in an `.env` file in the root of the monorepo, which will be available in all tutorials. -### Run Demo +## Run -Normal Transaction: +Normal transaction: ```bash yarn normalTx ``` -Withdraw Funds: +Withdraw funds: ```bash yarn withdrawFunds ``` -## Curious to see the output on the Arbitrum chain? - -Once the script is successfully executed, you can go to the [Arbitrum nitro block explorer](https://sepolia.arbiscan.io), enter your L2 address, and see the corresponding transactions on the Arbitrum chain! -

diff --git a/packages/delayedInbox-l2msg/contracts/greeter.sol b/packages/delayedInbox-l2msg/contracts/greeter.sol index 2881afe..5492150 100644 --- a/packages/delayedInbox-l2msg/contracts/greeter.sol +++ b/packages/delayedInbox-l2msg/contracts/greeter.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity >=0.6.11; +pragma solidity ^0.8.0; contract Greeter { string greeting; @@ -11,7 +11,7 @@ contract Greeter { _; } - constructor(string memory _greeting) public { + constructor(string memory _greeting) { greeting = _greeting; deployer = msg.sender; } diff --git a/packages/delayedInbox-l2msg/hardhat.config.js b/packages/delayedInbox-l2msg/hardhat.config.js index ec4c60d..fcdc441 100644 --- a/packages/delayedInbox-l2msg/hardhat.config.js +++ b/packages/delayedInbox-l2msg/hardhat.config.js @@ -1,5 +1,4 @@ require('@nomiclabs/hardhat-ethers') - const { hardhatConfig } = require('arb-shared-dependencies') module.exports = hardhatConfig diff --git a/packages/delayedInbox-l2msg/package.json b/packages/delayedInbox-l2msg/package.json index d2a1590..e48cd4e 100644 --- a/packages/delayedInbox-l2msg/package.json +++ b/packages/delayedInbox-l2msg/package.json @@ -13,11 +13,7 @@ }, "author": "Offchain Labs, Inc.", "license": "Apache-2.0", - "devDependencies": { - "hardhat": "^2.10.1" - }, "dependencies": { - "hardhat": "^2.10.1", - "@arbitrum/sdk": "^v3.1.9" + "@arbitrum/sdk": "^v4.0.1" } } diff --git a/packages/delayedInbox-l2msg/scripts/normalTx.js b/packages/delayedInbox-l2msg/scripts/normalTx.js index e8206c5..3130ede 100644 --- a/packages/delayedInbox-l2msg/scripts/normalTx.js +++ b/packages/delayedInbox-l2msg/scripts/normalTx.js @@ -1,112 +1,122 @@ -const { providers, Wallet, ethers } = require('ethers') -const hre = require('hardhat') -const { arbLog, requireEnvVariables } = require('arb-shared-dependencies') +const { ethers } = require('hardhat') +const { providers, Wallet } = require('ethers') const { - getL2Network, - addDefaultLocalNetwork, -} = require('@arbitrum/sdk/dist/lib/dataEntities/networks') -const { InboxTools } = require('@arbitrum/sdk') -requireEnvVariables(['DEVNET_PRIVKEY', 'L2RPC', 'L1RPC']) + arbLog, + requireEnvVariables, + addCustomNetworkFromFile, +} = require('arb-shared-dependencies') +const { getArbitrumNetwork, InboxTools } = require('@arbitrum/sdk') +require('dotenv').config() +requireEnvVariables(['PRIVATE_KEY', 'CHAIN_RPC', 'PARENT_CHAIN_RPC']) /** - * Set up: instantiate L1 / L2 wallets connected to providers + * Set up: instantiate wallets connected to providers */ -const walletPrivateKey = process.env.DEVNET_PRIVKEY +const walletPrivateKey = process.env.PRIVATE_KEY -const l1Provider = new providers.JsonRpcProvider(process.env.L1RPC) -const l2Provider = new providers.JsonRpcProvider(process.env.L2RPC) +const parentChainProvider = new providers.JsonRpcProvider( + process.env.PARENT_CHAIN_RPC +) +const childChainProvider = new providers.JsonRpcProvider(process.env.CHAIN_RPC) -const l1Wallet = new Wallet(walletPrivateKey, l1Provider) -const l2Wallet = new Wallet(walletPrivateKey, l2Provider) +const parentChainWallet = new Wallet(walletPrivateKey, parentChainProvider) +const childChainWallet = new Wallet(walletPrivateKey, childChainProvider) const main = async () => { await arbLog('DelayedInbox normal contract call (L2MSG_signedTx)') /** - * Add the default local network configuration to the SDK - * to allow this script to run on a local node + * Add the custom network configuration to the SDK if present */ - addDefaultLocalNetwork() - - const l2Network = await getL2Network(await l2Wallet.getChainId()) - - const inboxSdk = new InboxTools(l1Wallet, l2Network) + addCustomNetworkFromFile() /** - * We deploy greeter to L2, to see if delayed inbox tx can be executed as we thought + * Use childChainNetwork to create an Arbitrum SDK InboxTools instance */ - const L2Greeter = await ( - await hre.ethers.getContractFactory('Greeter') - ).connect(l2Wallet) - - console.log('Deploying Greeter on L2 👋👋') - - const l2Greeter = await L2Greeter.deploy('Hello world') - await l2Greeter.deployed() - console.log(`deployed to ${l2Greeter.address}`) + const childChainNetwork = await getArbitrumNetwork(childChainProvider) + const inboxTools = new InboxTools(parentChainWallet, childChainNetwork) /** - * Let's log the L2 greeting string + * We deploy greeter to the child chain, to interact with it from the parent chain */ - const currentL2Greeting = await l2Greeter.greet() - console.log(`Current L2 greeting: "${currentL2Greeting}"`) + console.log('Deploying Greeter to the child chain 👋👋') - console.log( - `Now we send a l2 tx through l1 delayed inbox (Please don't send any tx on l2 using ${l2Wallet.address} during this time):` + const Greeter = (await ethers.getContractFactory('Greeter')).connect( + childChainWallet ) + const greeter = await Greeter.deploy('Hello world') + await greeter.deployed() + console.log(`Greeter deployed to ${greeter.address}`) /** - * Here we have a new greeting message that we want to set as the L2 greeting; we'll be setting it by sending it as a message from delayed inbox!!! + * Let's log the starting greeting string */ - const newGreeting = 'Greeting from delayedInbox' - - const GreeterIface = l2Greeter.interface + const currentGreeting = await greeter.greet() + console.log(`Current greeting: "${currentGreeting}"`) - const calldatal2 = GreeterIface.encodeFunctionData('setGreeting', [ - newGreeting, + /** + * Here we have a new greeting message that we want to set in the contract; + * we'll be setting it by sending it as a message from the parent chain through the delayed inbox!!! + */ + console.log( + `Now we send a message to be executed on the child chain, through the delayed inbox of the parent chain (make sure you don't send any transaction directly on the child chain using ${childChainWallet.address} during this time):` + ) + const newGreetingToSet = 'Greeting from delayedInbox' + const GreeterIface = greeter.interface + const calldata = GreeterIface.encodeFunctionData('setGreeting', [ + newGreetingToSet, ]) - - const transactionl2Request = { - data: calldatal2, - to: l2Greeter.address, + const transactionRequest = { + data: calldata, + to: greeter.address, value: 0, } /** - * We need extract l2's tx hash first so we can check if this tx executed on l2 later. + * We need to extract the transaction hash in the child chain first so we can check later if it was executed */ - const l2SignedTx = await inboxSdk.signL2Tx(transactionl2Request, l2Wallet) - - const l2Txhash = ethers.utils.parseTransaction(l2SignedTx).hash - - const l1Tx = await inboxSdk.sendL2SignedTx(l2SignedTx) - - const inboxRec = await l1Tx.wait() - - console.log(`Greeting txn confirmed on L1! 🙌 ${inboxRec.transactionHash}`) + const signedTransaction = await inboxTools.signChildTx( + transactionRequest, + childChainWallet + ) + const transactionHash = ethers.utils.parseTransaction(signedTransaction).hash /** - * Now we successfully send the tx to l1 delayed inbox, then we need to wait the tx executed on l2 + * We now send the transaction through the Delayed Inbox on the parent chain */ + const sendMessageParentChainTransactionRequest = + await inboxTools.sendChildSignedTx(signedTransaction) + const sendMessageParentChainTransactionReceipt = + await sendMessageParentChainTransactionRequest.wait() console.log( - `Now we need to wait tx: ${l2Txhash} to be included on l2 (may take 15 minutes) ....... ` + `Greeting transaction confirmed on the parent chain! 🙌 ${sendMessageParentChainTransactionReceipt.transactionHash}` ) - const l2TxReceipt = await l2Provider.waitForTransaction(l2Txhash) - - const status = l2TxReceipt.status + /** + * Now we successfully send the transaction to the delayed inbox on the parent chain + * We wait for the transaction to be executed on the child chain + */ + console.log( + `Now we need to wait tx: ${transactionHash} to be executed on the child chain (may take ~15 minutes) ... ` + ) + const transactionReceipt = await childChainProvider.waitForTransaction( + transactionHash + ) + const status = transactionReceipt.status if (status == true) { - console.log(`L2 txn executed!!! 🥳 `) + console.log(`Transaction executed on the child chain!!! 🥳`) } else { - console.log(`L2 txn failed, see if your gas is enough?`) + console.log( + `The transaction failed to execute on the child chain. Please verify if the gas provided was enough` + ) return } /** - * Now when we call greet again, we should see our new string on L2! + * Now when we call greet again, we should see our new string! */ - const newGreetingL2 = await l2Greeter.greet() - console.log(`Updated L2 greeting: "${newGreetingL2}"`) + const newGreeting = await greeter.greet() + console.log(`Updated greeting: "${newGreeting}"`) console.log('✌️') } diff --git a/packages/delayedInbox-l2msg/scripts/withdrawFunds.js b/packages/delayedInbox-l2msg/scripts/withdrawFunds.js index 1e8e0cf..366a253 100644 --- a/packages/delayedInbox-l2msg/scripts/withdrawFunds.js +++ b/packages/delayedInbox-l2msg/scripts/withdrawFunds.js @@ -1,89 +1,103 @@ -const { providers, Wallet, ethers } = require('ethers') -const { arbLog, requireEnvVariables } = require('arb-shared-dependencies') +const { ethers } = require('hardhat') +const { providers, Wallet } = require('ethers') const { - getL2Network, - addDefaultLocalNetwork, -} = require('@arbitrum/sdk/dist/lib/dataEntities/networks') -const { InboxTools } = require('@arbitrum/sdk') -const { - ArbSys__factory, -} = require('@arbitrum/sdk/dist/lib/abi/factories/ArbSys__factory') - + arbLog, + requireEnvVariables, + addCustomNetworkFromFile, +} = require('arb-shared-dependencies') +const { getArbitrumNetwork, InboxTools } = require('@arbitrum/sdk') const { ARB_SYS_ADDRESS, } = require('@arbitrum/sdk/dist/lib/dataEntities/constants') -requireEnvVariables(['DEVNET_PRIVKEY', 'L2RPC', 'L1RPC']) +const { + ArbSys__factory, +} = require('@arbitrum/sdk/dist/lib/abi/factories/ArbSys__factory') +require('dotenv').config() +requireEnvVariables(['PRIVATE_KEY', 'CHAIN_RPC', 'PARENT_CHAIN_RPC']) /** - * Set up: instantiate L1 / L2 wallets connected to providers + * Set up: instantiate wallets connected to providers */ -const walletPrivateKey = process.env.DEVNET_PRIVKEY +const walletPrivateKey = process.env.PRIVATE_KEY -const l1Provider = new providers.JsonRpcProvider(process.env.L1RPC) -const l2Provider = new providers.JsonRpcProvider(process.env.L2RPC) +const parentChainProvider = new providers.JsonRpcProvider( + process.env.PARENT_CHAIN_RPC +) +const childChainProvider = new providers.JsonRpcProvider(process.env.CHAIN_RPC) -const l1Wallet = new Wallet(walletPrivateKey, l1Provider) -const l2Wallet = new Wallet(walletPrivateKey, l2Provider) +const parentChainWallet = new Wallet(walletPrivateKey, parentChainProvider) +const childChainWallet = new Wallet(walletPrivateKey, childChainProvider) const main = async () => { - await arbLog('DelayedInbox withdraw funds from l2 (L2MSG_signedTx)') + await arbLog( + 'DelayedInbox withdraw funds from the parent chain (L2MSG_signedTx)' + ) /** - * Add the default local network configuration to the SDK - * to allow this script to run on a local node + * Add the custom network configuration to the SDK if present */ - addDefaultLocalNetwork() - - const l2Network = await getL2Network(await l2Wallet.getChainId()) - - const inboxSdk = new InboxTools(l1Wallet, l2Network) + addCustomNetworkFromFile() /** - * Here we have a arbsys abi to withdraw our funds; we'll be setting it by sending it as a message from delayed inbox!!! + * Use childChainNetwork to create an Arbitrum SDK InboxTools instance */ + const childChainNetwork = await getArbitrumNetwork(childChainProvider) + const inboxTools = new InboxTools(parentChainWallet, childChainNetwork) - const arbSys = ArbSys__factory.connect(ARB_SYS_ADDRESS, l2Provider) - + /** + * Here we use the ArbSys precompile to withdraw our funds; + * we'll be setting it by sending it as a message from delayed inbox on the parent chain!!! + */ + const arbSys = ArbSys__factory.connect(ARB_SYS_ADDRESS, childChainProvider) const arbsysIface = arbSys.interface - const calldatal2 = arbsysIface.encodeFunctionData('withdrawEth', [ - l1Wallet.address, + const calldata = arbsysIface.encodeFunctionData('withdrawEth', [ + parentChainWallet.address, ]) - - const transactionl2Request = { - data: calldatal2, + const transactionRequest = { + data: calldata, to: ARB_SYS_ADDRESS, - value: 1, // Only set 1 wei since it just a test tutorial, you can set whatever you want in real runtime. + value: 1, // Only set 1 wei since it just a test tutorial, but you can set any amount } /** - * We need extract l2's tx hash first so we can check if this tx executed on l2 later. + * We need to extract the transaction hash in the child chain first so we can check later if it was executed */ - const l2SignedTx = await inboxSdk.signL2Tx(transactionl2Request, l2Wallet) - - const l2Txhash = ethers.utils.parseTransaction(l2SignedTx).hash - - const resultsL1 = await inboxSdk.sendL2SignedTx(l2SignedTx) - - const inboxRec = await resultsL1.wait() - - console.log(`Withdraw txn initiated on L1! 🙌 ${inboxRec.transactionHash}`) + const signedTransaction = await inboxTools.signChildTx( + transactionRequest, + childChainWallet + ) + const transactionHash = ethers.utils.parseTransaction(signedTransaction).hash /** - * Now we successfully send the tx to l1 delayed inbox, then we need to wait the tx to be executed on l2 + * We now send the transaction through the Delayed Inbox on the parent chain */ + const sendMessageParentChainTransactionRequest = + await inboxTools.sendChildSignedTx(signedTransaction) + const sendMessageParentChainTransactionReceipt = + await sendMessageParentChainTransactionRequest.wait() console.log( - `Now we need to wait tx: ${l2Txhash} to be included on l2 (may take 15 minutes, if longer than 1 day, you can use sdk to force include) ....... ` + `Withdraw txn initiated on the parent chain! 🙌 ${sendMessageParentChainTransactionReceipt.transactionHash}` ) - const l2TxReceipt = await l2Provider.waitForTransaction(l2Txhash) - - const status = l2TxReceipt.status + /** + * Now we successfully send the transaction to the delayed inbox on the parent chain + * We wait for the transaction to be executed on the child chain + */ + console.log( + `Now we need to wait tx: ${transactionHash} to be executed on the child chain (may take ~15 minutes) ... ` + ) + const transactionReceipt = await childChainProvider.waitForTransaction( + transactionHash + ) + const status = transactionReceipt.status if (status == true) { console.log( - `L2 txn executed!!! 🥳 , you can go to https://bridge.arbitrum.io/ to execute your withdrawal and recieve your funds after challenge period!` + `Transaction executed on the child chain!!! 🥳 After a challenge period has passed, you can go to https://bridge.arbitrum.io/ to execute your withdrawal and receive your funds!` ) } else { - console.log(`L2 txn failed, see if your gas is enough?`) + console.log( + `The transaction failed to execute on the child chain. Please verify if the gas provided was enough` + ) return } } diff --git a/packages/eth-deposit-to-different-address/.env-sample b/packages/eth-deposit-to-different-address/.env-sample index b5db02e..146828e 100644 --- a/packages/eth-deposit-to-different-address/.env-sample +++ b/packages/eth-deposit-to-different-address/.env-sample @@ -1,15 +1,13 @@ # This is a sample .env file for use in local development. - # Duplicate this file as .env here -# Your Private key - -DEVNET_PRIVKEY="0x your key here" - -# Hosted Aggregator Node (JSON-RPC Endpoint). This is Arbitrum Sepolia Testnet, can use any Arbitrum chain - -L2RPC="https://sepolia-rollup.arbitrum.io/rpc" +# Your private key +PRIVATE_KEY="0x your key here" -# Ethereum RPC; i.e., for Sepolia https://sepolia.infura.io/v3/ +# The main chain's RPC +# (this can be an Arbitrum network, or your Orbit chain) +CHAIN_RPC="https://sepolia-rollup.arbitrum.io/rpc" -L1RPC="" +# The parent chain's RPC +# (this can be Ethereum, or the chain your Orbit chain settles to) +PARENT_CHAIN_RPC="https://sepolia.infura.io/v3/" diff --git a/packages/eth-deposit-to-different-address/.gitignore b/packages/eth-deposit-to-different-address/.gitignore deleted file mode 100644 index bf60924..0000000 --- a/packages/eth-deposit-to-different-address/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -artifacts/ -cache/ -build/ -node_modules/ diff --git a/packages/eth-deposit-to-different-address/README.md b/packages/eth-deposit-to-different-address/README.md index 7b26868..68869b5 100644 --- a/packages/eth-deposit-to-different-address/README.md +++ b/packages/eth-deposit-to-different-address/README.md @@ -1,25 +1,21 @@ -# eth-deposit-to-different-address Tutorial +# eth-deposit-to-different-address tutorial -`eth-deposit-to-different-address` shows how to move Ether from Ethereum (Layer 1) into the Arbitrum (Layer 2) chain, to an address different than the depositor. +`eth-deposit-to-different-address` shows how to move Ether from the parent chain into an Arbitrum or Orbit chain, to an address different than the depositor. -## How it works (Under the hood) +## How it works (under the hood) -For the common case of depositing ETH to the same account on L2, use the tutorial [eth-deposit](../eth-deposit/README.md). -In this specific case, we will use the retryable tickets (Arbitrum's canonical method for creating L1 to L2 messages) to deposit ETH into a different address. We will use the parameter `l2CallValue` of the retryable ticket to specify the amount of ETH to deposit, and `callValueRefundAddress` to specify the destination address. For more info on retryable tickets, see [retryable tickets documentation](https://developer.offchainlabs.com/docs/l1_l2_messages#depositing-eth-via-retryables). +For the common case of depositing ETH to the same account on the child chain, use the tutorial [eth-deposit](../eth-deposit/README.md). -### **Using Arbitrum SDK tooling** +In this specific case, we will use a retryable ticket (Arbitrum's canonical method for creating cross-chain messages) to deposit ETH into a different address. We will use the parameter `l2CallValue` of the retryable ticket to specify the amount of ETH to deposit, and `callValueRefundAddress` to specify the destination address. For more info on retryable tickets, see [this page of the Arbitrum documentation](https://docs.arbitrum.io/how-arbitrum-works/arbos/l1-l2-messaging#eth-deposits). -Our [Arbitrum SDK](https://github.com/OffchainLabs/arbitrum-sdk) provides a simple convenient method for creating a retryable ticket, abstracting away the need for the client to connect to any contracts manually. +## Using the Arbitrum SDK -See [./exec.js](./scripts/exec.js) for inline explanation. +Our [Arbitrum SDK](https://github.com/OffchainLabs/arbitrum-sdk) provides a simply convenience method for depositing Ether, abstracting away the need for the client to connect to any contracts manually. -To run: +See [./exec.js](./scripts/exec.js) for inline explanation. -``` -yarn run exec -``` -## Config Environment Variables +## Set environment variables Set the values shown in `.env-sample` as environmental variables. To copy it into a `.env` file: @@ -27,10 +23,14 @@ Set the values shown in `.env-sample` as environmental variables. To copy it int cp .env-sample .env ``` -(you'll still need to edit some variables, i.e., `DEVNET_PRIVKEY`) +You'll still need to edit some variables, i.e., `PRIVATE_KEY`, `CHAIN_RPC` and `PARENT_CHAIN_RPC`. ---- +Note that you can also set the environment variables in an `.env` file in the root of the monorepo, which will be available in all tutorials. -Once the script is successfully executed, you can go to the [Arbitrum block explorer](https://sepolia.arbiscan.io), enter your address, and see the amount of ETH that has been assigned to the specified address on the Arbitrum chain! +## Run + +``` +yarn run exec +```

diff --git a/packages/eth-deposit-to-different-address/package.json b/packages/eth-deposit-to-different-address/package.json index 6c6ab12..e787f63 100644 --- a/packages/eth-deposit-to-different-address/package.json +++ b/packages/eth-deposit-to-different-address/package.json @@ -3,16 +3,9 @@ "license": "Apache-2.0", "version": "1.0.0", "scripts": { - "build": "hardhat compile", "exec": "hardhat run scripts/exec.js" }, - "devDependencies": { - "@nomiclabs/hardhat-ethers": "^2.0.2", - "ethers": "^5.4.1", - "hardhat": "^2.2.0" - }, "dependencies": { - "@arbitrum/sdk": "^v3.1.9", - "dotenv": "^8.2.0" + "@arbitrum/sdk": "^v4.0.1" } } diff --git a/packages/eth-deposit-to-different-address/scripts/exec.js b/packages/eth-deposit-to-different-address/scripts/exec.js index 8adee34..06da7fd 100644 --- a/packages/eth-deposit-to-different-address/scripts/exec.js +++ b/packages/eth-deposit-to-different-address/scripts/exec.js @@ -1,102 +1,112 @@ const { utils, providers, Wallet } = require('ethers') const { + getArbitrumNetwork, EthBridger, - getL2Network, - EthDepositStatus, - addDefaultLocalNetwork, + EthDepositMessageStatus, } = require('@arbitrum/sdk') -const { parseEther } = utils -const { arbLog, requireEnvVariables } = require('arb-shared-dependencies') +const { + arbLog, + requireEnvVariables, + addCustomNetworkFromFile, +} = require('arb-shared-dependencies') require('dotenv').config() -requireEnvVariables(['DEVNET_PRIVKEY', 'L1RPC', 'L2RPC']) +requireEnvVariables(['PRIVATE_KEY', 'CHAIN_RPC', 'PARENT_CHAIN_RPC']) /** - * Set up: Connect to L1/L2 providers and instantiate an L1 wallet + * Set up: instantiate wallets connected to providers */ -const walletPrivateKey = process.env.DEVNET_PRIVKEY +const walletPrivateKey = process.env.PRIVATE_KEY -const l1Provider = new providers.JsonRpcProvider(process.env.L1RPC) -const l2Provider = new providers.JsonRpcProvider(process.env.L2RPC) +const parentChainProvider = new providers.JsonRpcProvider( + process.env.PARENT_CHAIN_RPC +) +const childChainProvider = new providers.JsonRpcProvider(process.env.CHAIN_RPC) -const l1Wallet = new Wallet(walletPrivateKey, l1Provider) +const parentChainWallet = new Wallet(walletPrivateKey, parentChainProvider) +const childChainWallet = new Wallet(walletPrivateKey, childChainProvider) /** - * Set the destination address and amount to be deposited in L2 (in wei) + * Set the destination address and amount to be deposited in the child chain (in wei) */ const destAddress = '0x2D98cBc6f944c4bD36EdfE9f98cd7CB57faEC8d6' -const ethToL2DepositAmount = parseEther('0.0001') +const depositAmount = utils.parseEther('0.0001') const main = async () => { await arbLog('Deposit Eth via Arbitrum SDK on a different address') /** - * Add the default local network configuration to the SDK - * to allow this script to run on a local node + * Add the custom network configuration to the SDK if present */ - addDefaultLocalNetwork() + addCustomNetworkFromFile() /** - * Use l2Network to create an Arbitrum SDK EthBridger instance - * We'll use EthBridger for its convenience methods around transferring ETH to L2 + * Use childChainNetwork to create an Arbitrum SDK EthBridger instance + * We'll use EthBridger for its convenience methods around transferring ETH to the child chain */ - const l2Network = await getL2Network(l2Provider) - const ethBridger = new EthBridger(l2Network) + const childChainNetwork = await getArbitrumNetwork(childChainProvider) + const ethBridger = new EthBridger(childChainNetwork) /** * First, let's check the ETH balance of the destination address */ - const destinationAddressInitialEthBalance = await l2Provider.getBalance( - destAddress - ) + const destinationAddressInitialEthBalance = + await childChainProvider.getBalance(destAddress) /** - * Transfer ether from L1 to L2 - * This convenience method automatically queries for the retryable's max submission cost and forwards the appropriate amount to the specified address on L2 + * Transfer ether from parent chain to a different address on child chain + * This convenience method automatically queries for the retryable's max submission cost and forwards the appropriate amount to the specified address on the child chain * Arguments required are: - * (1) amount: The amount of ETH to be transferred to L2 - * (2) l1Signer: The L1 address transferring ETH to L2 - * (3) l2Provider: An l2 provider + * (1) amount: The amount of ETH to be transferred + * (2) parentSigner: The address on the parent chain of the account transferring ETH to the child chain + * (3) childProvider: A provider of the child chain * (4) destinationAddress: The address where the ETH will be sent to */ - const depositTx = await ethBridger.depositTo({ - amount: ethToL2DepositAmount, - l1Signer: l1Wallet, - l2Provider: l2Provider, + const depositTransaction = await ethBridger.depositTo({ + amount: depositAmount, + parentSigner: parentChainWallet, + childProvider: childChainProvider, destinationAddress: destAddress, }) - const depositRec = await depositTx.wait() - console.warn('Deposit L1 receipt is:', depositRec.transactionHash) + const depositTransactionReceipt = await depositTransaction.wait() + console.log( + 'Deposit receipt on the parent chain is:', + depositTransactionReceipt.transactionHash + ) /** - * With the transaction confirmed on L1, we now wait for the L2 side (i.e., balance credited to L2) to be confirmed as well. - * Here we're waiting for the Sequencer to include the L2 message in its off-chain queue. The Sequencer should include it in under 15 minutes. + * With the transaction confirmed on the parent chain, we now wait for the child chain's side (i.e., balance credited to the child chain) to be confirmed as well. + * Here we're waiting for the sequencer to include the message in its off-chain queue. The sequencer should include it in around 15 minutes. */ - console.warn('Now we wait for L2 side of the transaction to be executed ⏳') - const l2Result = await depositRec.waitForL2(l2Provider) + console.log( + `Now we wait for child chain's side of the transaction to be executed ⏳` + ) + const transactionResult = + await depositTransactionReceipt.waitForChildTransactionReceipt( + childChainProvider + ) /** - * The `complete` boolean tells us if the l1 to l2 message was successful + * The `complete` boolean tells us if the cross-chain message was successful */ - l2Result.complete + transactionResult.complete ? console.log( - `L2 message successful: status: ${ - EthDepositStatus[await l2Result.message.status()] + `Message successfully executed on the child chain. Status: ${ + EthDepositMessageStatus[await transactionResult.message.status()] }` ) : console.log( - `L2 message failed: status ${ - EthDepositStatus[await l2Result.message.status()] + `Message failed execution on the child chain . Status ${ + EthDepositMessageStatus[await transactionResult.message.status()] }` ) /** * Our destination address ETH balance should be updated now */ - const destinationAddressUpdatedEthBalance = await l2Provider.getBalance( - destAddress - ) + const destinationAddressUpdatedEthBalance = + await childChainProvider.getBalance(destAddress) console.log( - `L2 ETH balance of the destination address has been updated from ${destinationAddressInitialEthBalance.toString()} to ${destinationAddressUpdatedEthBalance.toString()}` + `ETH balance of the destination address has been updated from ${destinationAddressInitialEthBalance.toString()} to ${destinationAddressUpdatedEthBalance.toString()}` ) } main() diff --git a/packages/eth-deposit/.env-sample b/packages/eth-deposit/.env-sample index b5db02e..146828e 100644 --- a/packages/eth-deposit/.env-sample +++ b/packages/eth-deposit/.env-sample @@ -1,15 +1,13 @@ # This is a sample .env file for use in local development. - # Duplicate this file as .env here -# Your Private key - -DEVNET_PRIVKEY="0x your key here" - -# Hosted Aggregator Node (JSON-RPC Endpoint). This is Arbitrum Sepolia Testnet, can use any Arbitrum chain - -L2RPC="https://sepolia-rollup.arbitrum.io/rpc" +# Your private key +PRIVATE_KEY="0x your key here" -# Ethereum RPC; i.e., for Sepolia https://sepolia.infura.io/v3/ +# The main chain's RPC +# (this can be an Arbitrum network, or your Orbit chain) +CHAIN_RPC="https://sepolia-rollup.arbitrum.io/rpc" -L1RPC="" +# The parent chain's RPC +# (this can be Ethereum, or the chain your Orbit chain settles to) +PARENT_CHAIN_RPC="https://sepolia.infura.io/v3/" diff --git a/packages/eth-deposit/.gitignore b/packages/eth-deposit/.gitignore deleted file mode 100644 index bf60924..0000000 --- a/packages/eth-deposit/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -artifacts/ -cache/ -build/ -node_modules/ diff --git a/packages/eth-deposit/README.md b/packages/eth-deposit/README.md index 05795d1..69b486f 100644 --- a/packages/eth-deposit/README.md +++ b/packages/eth-deposit/README.md @@ -1,24 +1,18 @@ # eth-deposit Tutorial -`eth-deposit` shows how to move Ether from Ethereum (Layer 1) into the Arbitrum (Layer 2) chain. +`eth-deposit` shows how to move Ether from the parent chain into an Arbitrum or Orbit chain. -## How it works (Under the hood) +## How it works (under the hood) -A user deposits Ether onto Arbitrum using Arbitrum's general L1-to-L2 message passing system, and simply passing the desired Ether as callvalue and no additional data. For more info, see [Retryable Tickets documentation](https://developer.offchainlabs.com/docs/l1_l2_messages#depositing-eth-via-retryables). +A user deposits Ether onto an Arbitrum chain using Arbitrum's general Parent-to-child message passing system, and simply passing the desired Ether as callvalue and no additional data. For more info, see [this page of the Arbitrum documentation](https://docs.arbitrum.io/how-arbitrum-works/arbos/l1-l2-messaging#eth-deposits). -### **Using Arbitrum SDK tooling** +## Using the Arbitrum SDK Our [Arbitrum SDK](https://github.com/OffchainLabs/arbitrum-sdk) provides a simply convenience method for depositing Ether, abstracting away the need for the client to connect to any contracts manually. See [./exec.js](./scripts/exec.js) for inline explanation. -To run: - -``` -yarn run depositETH -``` - -## Config Environment Variables +## Set environment variables Set the values shown in `.env-sample` as environmental variables. To copy it into a `.env` file: @@ -26,11 +20,15 @@ Set the values shown in `.env-sample` as environmental variables. To copy it int cp .env-sample .env ``` -(you'll still need to edit some variables, i.e., `DEVNET_PRIVKEY`) +You'll still need to edit some variables, i.e., `PRIVATE_KEY`, `CHAIN_RPC` and `PARENT_CHAIN_RPC`. ---- +Note that you can also set the environment variables in an `.env` file in the root of the monorepo, which will be available in all tutorials. -Once the script is successfully executed, you can go to the [Arbitrum block explorer](https://sepolia.arbiscan.io), enter your address, and see the amount of ETH that has been assigned to your address on the Arbitrum chain! +## Run + +``` +yarn run depositETH +```

diff --git a/packages/eth-deposit/package.json b/packages/eth-deposit/package.json index 50bbe9e..e94dfc7 100644 --- a/packages/eth-deposit/package.json +++ b/packages/eth-deposit/package.json @@ -3,16 +3,9 @@ "license": "Apache-2.0", "version": "1.0.0", "scripts": { - "build": "hardhat compile", "depositETH": "hardhat run scripts/exec.js" }, - "devDependencies": { - "@nomiclabs/hardhat-ethers": "^2.0.2", - "ethers": "^5.4.1", - "hardhat": "^2.2.0" - }, "dependencies": { - "@arbitrum/sdk": "^v3.1.9", - "dotenv": "^8.2.0" + "@arbitrum/sdk": "^v4.0.1" } } diff --git a/packages/eth-deposit/scripts/exec.js b/packages/eth-deposit/scripts/exec.js index ea65d87..ad372a0 100644 --- a/packages/eth-deposit/scripts/exec.js +++ b/packages/eth-deposit/scripts/exec.js @@ -1,97 +1,108 @@ const { utils, providers, Wallet } = require('ethers') const { + getArbitrumNetwork, EthBridger, - getL2Network, - EthDepositStatus, - addDefaultLocalNetwork, + EthDepositMessageStatus, } = require('@arbitrum/sdk') -const { parseEther } = utils -const { arbLog, requireEnvVariables } = require('arb-shared-dependencies') +const { + arbLog, + requireEnvVariables, + addCustomNetworkFromFile, +} = require('arb-shared-dependencies') require('dotenv').config() -requireEnvVariables(['DEVNET_PRIVKEY', 'L1RPC', 'L2RPC']) +requireEnvVariables(['PRIVATE_KEY', 'CHAIN_RPC', 'PARENT_CHAIN_RPC']) /** - * Set up: instantiate L1 / L2 wallets connected to providers + * Set up: instantiate wallets connected to providers */ -const walletPrivateKey = process.env.DEVNET_PRIVKEY +const walletPrivateKey = process.env.PRIVATE_KEY -const l1Provider = new providers.JsonRpcProvider(process.env.L1RPC) -const l2Provider = new providers.JsonRpcProvider(process.env.L2RPC) +const parentChainProvider = new providers.JsonRpcProvider( + process.env.PARENT_CHAIN_RPC +) +const childChainProvider = new providers.JsonRpcProvider(process.env.CHAIN_RPC) -const l1Wallet = new Wallet(walletPrivateKey, l1Provider) -const l2Wallet = new Wallet(walletPrivateKey, l2Provider) +const parentChainWallet = new Wallet(walletPrivateKey, parentChainProvider) +const childChainWallet = new Wallet(walletPrivateKey, childChainProvider) /** - * Set the amount to be deposited in L2 (in wei) + * Set the amount to be deposited in the child chain (in wei) */ -const ethToL2DepositAmount = parseEther('0.0001') +const depositAmount = utils.parseEther('0.0001') const main = async () => { await arbLog('Deposit Eth via Arbitrum SDK') /** - * Add the default local network configuration to the SDK - * to allow this script to run on a local node + * Add the custom network configuration to the SDK if present */ - addDefaultLocalNetwork() + addCustomNetworkFromFile() /** - * Use l2Network to create an Arbitrum SDK EthBridger instance - * We'll use EthBridger for its convenience methods around transferring ETH to L2 + * Use childChainNetwork to create an Arbitrum SDK EthBridger instance + * We'll use EthBridger for its convenience methods around transferring ETH to the child chain */ - - const l2Network = await getL2Network(l2Provider) - const ethBridger = new EthBridger(l2Network) + const childChainNetwork = await getArbitrumNetwork(childChainProvider) + const ethBridger = new EthBridger(childChainNetwork) /** - * First, let's check the l2Wallet initial ETH balance + * First, let's check the wallet's initial ETH balance in the child chain */ - const l2WalletInitialEthBalance = await l2Wallet.getBalance() + const initialEthBalance = await childChainWallet.getBalance() /** - * transfer ether from L1 to L2 - * This convenience method automatically queries for the retryable's max submission cost and forwards the appropriate amount to L2 + * Transfer ether from parent to child chain + * This convenience method automatically queries for the retryable's max submission cost and forwards the appropriate amount to the child chain * Arguments required are: - * (1) amount: The amount of ETH to be transferred to L2 - * (2) l1Signer: The L1 address transferring ETH to L2 - * (3) l2Provider: An l2 provider + * (1) amount: The amount of ETH to be transferred + * (2) parentSigner: The address on the parent chain of the account transferring ETH to the child chain + * (3) childProvider: A provider of the child chain */ - const depositTx = await ethBridger.deposit({ - amount: ethToL2DepositAmount, - l1Signer: l1Wallet, - l2Provider: l2Provider, + const depositTransaction = await ethBridger.deposit({ + amount: depositAmount, + parentSigner: parentChainWallet, + childProvider: childChainProvider, }) - const depositRec = await depositTx.wait() - console.warn('deposit L1 receipt is:', depositRec.transactionHash) + const depositTransactionReceipt = await depositTransaction.wait() + console.log( + 'Deposit receipt on the parent chain is:', + depositTransactionReceipt.transactionHash + ) /** - * With the transaction confirmed on L1, we now wait for the L2 side (i.e., balance credited to L2) to be confirmed as well. - * Here we're waiting for the Sequencer to include the L2 message in its off-chain queue. The Sequencer should include it in under 10 minutes. + * With the transaction confirmed on the parent chain, we now wait for the child chain's side (i.e., balance credited to the child chain) to be confirmed as well. + * Here we're waiting for the sequencer to include the message in its off-chain queue. The sequencer should include it in around 15 minutes. */ - console.warn('Now we wait for L2 side of the transaction to be executed ⏳') - const l2Result = await depositRec.waitForL2(l2Provider) + console.log( + `Now we wait for child chain's side of the transaction to be executed ⏳` + ) + const transactionResult = + await depositTransactionReceipt.waitForChildTransactionReceipt( + childChainProvider + ) + /** - * The `complete` boolean tells us if the l1 to l2 message was successful + * The `complete` boolean tells us if the cross-chain message was successful */ - l2Result.complete + transactionResult.complete ? console.log( - `L2 message successful: status: ${ - EthDepositStatus[await l2Result.message.status()] + `Message successfully executed on the child chain. Status: ${ + EthDepositMessageStatus[await transactionResult.message.status()] }` ) : console.log( - `L2 message failed: status ${ - EthDepositStatus[await l2Result.message.status()] + `Message failed execution on the child chain . Status ${ + EthDepositMessageStatus[await transactionResult.message.status()] }` ) /** - * Our l2Wallet ETH balance should be updated now + * Our wallet's ETH balance on the child chain should be updated now */ - const l2WalletUpdatedEthBalance = await l2Wallet.getBalance() + const updatedEthBalance = await childChainWallet.getBalance() console.log( - `your L2 ETH balance is updated from ${l2WalletInitialEthBalance.toString()} to ${l2WalletUpdatedEthBalance.toString()}` + `Your ETH balance in the child chain is updated from ${initialEthBalance.toString()} to ${updatedEthBalance.toString()}` ) } main() @@ -99,4 +110,4 @@ main() .catch(error => { console.error(error) process.exit(1) - }) \ No newline at end of file + }) diff --git a/packages/eth-withdraw/.env-sample b/packages/eth-withdraw/.env-sample index b5db02e..146828e 100644 --- a/packages/eth-withdraw/.env-sample +++ b/packages/eth-withdraw/.env-sample @@ -1,15 +1,13 @@ # This is a sample .env file for use in local development. - # Duplicate this file as .env here -# Your Private key - -DEVNET_PRIVKEY="0x your key here" - -# Hosted Aggregator Node (JSON-RPC Endpoint). This is Arbitrum Sepolia Testnet, can use any Arbitrum chain - -L2RPC="https://sepolia-rollup.arbitrum.io/rpc" +# Your private key +PRIVATE_KEY="0x your key here" -# Ethereum RPC; i.e., for Sepolia https://sepolia.infura.io/v3/ +# The main chain's RPC +# (this can be an Arbitrum network, or your Orbit chain) +CHAIN_RPC="https://sepolia-rollup.arbitrum.io/rpc" -L1RPC="" +# The parent chain's RPC +# (this can be Ethereum, or the chain your Orbit chain settles to) +PARENT_CHAIN_RPC="https://sepolia.infura.io/v3/" diff --git a/packages/eth-withdraw/.gitignore b/packages/eth-withdraw/.gitignore deleted file mode 100644 index de213b9..0000000 --- a/packages/eth-withdraw/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ - -artifacts/ -cache/ -build/ -node_modules/ diff --git a/packages/eth-withdraw/README.md b/packages/eth-withdraw/README.md index 8cb3c13..88d6b5e 100644 --- a/packages/eth-withdraw/README.md +++ b/packages/eth-withdraw/README.md @@ -1,30 +1,20 @@ -# eth-withdraw Tutorial +# eth-withdraw tutorial -`eth-withdraw` shows how to move Ether from Arbitrum (Layer 2) into the Ethereum (Layer 1) chain. +`eth-withdraw` shows how to move Ether from an Arbitrum or Orbit chain into its parent chain. -Note that this repo covers initiating and Ether withdrawal; for a demo on (later) releasing the funds from the Outbox, see [outbox-execute](../outbox-execute/README.md) +Note that this repo covers initiating an Ether withdrawal. For a demo on releasing the funds from the Outbox, see [outbox-execute](../outbox-execute/README.md) -## How it works (Under the hood) +## How it works (under the hood) -To withdraw Ether from Arbitrum, a client creates an outgoing / L2 to L1 message using the `ArbSys` interface that later lets them release Ether from its escrow in the L1 Bridge.sol contract. For more info, see [Outgoing messages documentation](https://developer.offchainlabs.com/docs/l1_l2_messages#l2-to-l1-messages-lifecycle). +To withdraw Ether from an Arbitrum chain, a client creates an outgoing / child to parent message using the `ArbSys` precompile that later lets them release Ether from its escrow in the parent chain's Bridge contract. For more info, see [this page of the Arbitrum documentation](https://docs.arbitrum.io/how-arbitrum-works/arbos/l2-l1-messaging). ---- - -_Note: Executing scripts will require your L2 account be funded with .000001 Eth._ - -### **Using Arbitrum SDK tooling** +## Using the Arbitrum SDK Our [Arbitrum SDK](https://github.com/OffchainLabs/arbitrum-sdk) provides a simply convenience method for withdrawing Ether, abstracting away the need for the client to connect to any contracts manually. See [./exec.js](./scripts/exec.js) for inline explanation. -To run: - -``` -yarn run withdrawETH -``` - -## Config Environment Variables +## Set environment variables Set the values shown in `.env-sample` as environmental variables. To copy it into a `.env` file: @@ -32,13 +22,17 @@ Set the values shown in `.env-sample` as environmental variables. To copy it int cp .env-sample .env ``` -(you'll still need to edit some variables, i.e., `DEVNET_PRIVKEY`) +You'll still need to edit some variables, i.e., `PRIVATE_KEY`, `CHAIN_RPC` and `PARENT_CHAIN_RPC`. + +Note that you can also set the environment variables in an `.env` file in the root of the monorepo, which will be available in all tutorials. ---- +## Run -## Curious to see the output on the Arbitrum chain? +``` +yarn run withdrawETH +``` -Once the script is successfully executed, you can go to the [Arbitrum block explorer](https://sepolia.arbiscan.io), enter your address and see the amount of ETH has been deducted from your Layer 2 balance. Note that your Layer 1 balance will only be updated after rollup's confirmation period is over. +_Note: Executing scripts will require your account be funded with .000001 Eth in the child chain._

diff --git a/packages/eth-withdraw/package.json b/packages/eth-withdraw/package.json index 241eb5c..cbb4900 100644 --- a/packages/eth-withdraw/package.json +++ b/packages/eth-withdraw/package.json @@ -3,16 +3,9 @@ "license": "Apache-2.0", "version": "1.0.0", "scripts": { - "build": "hardhat compile", "withdrawETH": "hardhat run scripts/exec.js" }, - "devDependencies": { - "@nomiclabs/hardhat-ethers": "^2.0.2", - "ethers": "^5.1.2", - "hardhat": "^2.2.0" - }, "dependencies": { - "@arbitrum/sdk": "^v3.1.9", - "dotenv": "^8.2.0" + "@arbitrum/sdk": "^v4.0.1" } } diff --git a/packages/eth-withdraw/scripts/exec.js b/packages/eth-withdraw/scripts/exec.js index d55c7a9..b10b1c3 100644 --- a/packages/eth-withdraw/scripts/exec.js +++ b/packages/eth-withdraw/scripts/exec.js @@ -1,51 +1,52 @@ const { utils, providers, Wallet } = require('ethers') const { + getArbitrumNetwork, EthBridger, - getL2Network, - addDefaultLocalNetwork, + EthDepositMessageStatus, } = require('@arbitrum/sdk') -const { parseEther } = utils -const { arbLog, requireEnvVariables } = require('arb-shared-dependencies') +const { + arbLog, + requireEnvVariables, + addCustomNetworkFromFile, +} = require('arb-shared-dependencies') require('dotenv').config() -requireEnvVariables(['DEVNET_PRIVKEY', 'L2RPC', 'L1RPC']) +requireEnvVariables(['PRIVATE_KEY', 'CHAIN_RPC', 'PARENT_CHAIN_RPC']) /** - * Set up: instantiate L2 wallet connected to provider + * Set up: instantiate wallets connected to providers */ -const walletPrivateKey = process.env.DEVNET_PRIVKEY -const l2Provider = new providers.JsonRpcProvider(process.env.L2RPC) -const l2Wallet = new Wallet(walletPrivateKey, l2Provider) +const walletPrivateKey = process.env.PRIVATE_KEY +const childChainProvider = new providers.JsonRpcProvider(process.env.CHAIN_RPC) +const childChainWallet = new Wallet(walletPrivateKey, childChainProvider) /** - * Set the amount to be withdrawn from L2 (in wei) + * Set the amount to be withdrawn from the child chain (in wei) */ -const ethFromL2WithdrawAmount = parseEther('0.000001') +const withdrawAmount = utils.parseEther('0.000001') const main = async () => { await arbLog('Withdraw Eth via Arbitrum SDK') /** - * Add the default local network configuration to the SDK - * to allow this script to run on a local node + * Add the custom network configuration to the SDK if present */ - addDefaultLocalNetwork() + addCustomNetworkFromFile() /** - * Use l2Network to create an Arbitrum SDK EthBridger instance - * We'll use EthBridger for its convenience methods around transferring ETH from L2 to L1 + * Use childChainNetwork to create an Arbitrum SDK EthBridger instance + * We'll use EthBridger for its convenience methods around transferring ETH to the parent chain */ - - const l2Network = await getL2Network(l2Provider) - const ethBridger = new EthBridger(l2Network) + const childChainNetwork = await getArbitrumNetwork(childChainProvider) + const ethBridger = new EthBridger(childChainNetwork) /** - * First, let's check our L2 wallet's initial ETH balance and ensure there's some ETH to withdraw + * First, let's check our wallet's initial ETH balance in the child chain and ensure there's some ETH to withdraw */ - const l2WalletInitialEthBalance = await l2Wallet.getBalance() + const initialEthBalance = await childChainWallet.getBalance() - if (l2WalletInitialEthBalance.lt(ethFromL2WithdrawAmount)) { + if (initialEthBalance.lt(withdrawAmount)) { console.log( - `Oops - not enough ether; fund your account L2 wallet currently ${l2Wallet.address} with at least 0.000001 ether` + `Oops - not enough ether; fund your wallet on the child chain ${childChainWallet.address} with at least 0.000001 ether` ) process.exit(1) } @@ -55,22 +56,23 @@ const main = async () => { * We're ready to withdraw ETH using the ethBridger instance from Arbitrum SDK * It will use our current wallet's address as the default destination */ - - const withdrawTx = await ethBridger.withdraw({ - amount: ethFromL2WithdrawAmount, - l2Signer: l2Wallet, - destinationAddress: l2Wallet.address, + const withdrawTransaction = await ethBridger.withdraw({ + amount: withdrawAmount, + childSigner: childChainWallet, + destinationAddress: childChainWallet.address, }) - const withdrawRec = await withdrawTx.wait() + const withdrawTransactionReceipt = await withdrawTransaction.wait() /** * And with that, our withdrawal is initiated! No additional time-sensitive actions are required. * Any time after the transaction's assertion is confirmed, funds can be transferred out of the bridge via the outbox contract * We'll display the withdrawals event data here: */ - console.log(`Ether withdrawal initiated! 🥳 ${withdrawRec.transactionHash}`) + console.log( + `Ether withdrawal initiated! 🥳 ${withdrawTransactionReceipt.transactionHash}` + ) - const withdrawEventsData = await withdrawRec.getL2ToL1Events() + const withdrawEventsData = withdrawTransactionReceipt.getChildToParentEvents() console.log('Withdrawal data:', withdrawEventsData) console.log( `To claim funds (after dispute period), see outbox-execute repo 🫡` diff --git a/yarn.lock b/yarn.lock index 54a6c20..a9f90de 100644 --- a/yarn.lock +++ b/yarn.lock @@ -39,7 +39,7 @@ optionalDependencies: sol2uml "2.2.0" -"@arbitrum/sdk@^4.0.1": +"@arbitrum/sdk@^4.0.1", "@arbitrum/sdk@^v4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@arbitrum/sdk/-/sdk-4.0.1.tgz#b51c7bb8ecef0143a35b7f3ab8538031bb1830d2" integrity sha512-uW0Pe/oICbmlHpIpYOaHHWsNQRG+3UbCa3s0SJsp2O1Kt9b0M0CX/fEdFOFLyAi3OxHonNEfzhfvQrALy9C3Yw== @@ -2638,7 +2638,7 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== -hardhat@^2.10.1, hardhat@^2.2.0, hardhat@^2.6.6, hardhat@^2.9.1: +hardhat@^2.2.0, hardhat@^2.6.6, hardhat@^2.9.1: version "2.15.0" resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.15.0.tgz#0cacb2b44c4c4651aa8ab649fef12804848b0267" integrity sha512-cC9tM/N10YaES04zPOp7yR13iX3YibqaNmi0//Ep40Nt9ELIJx3kFpQmucur0PAIfXYpGnw5RuXHNLkxpnVHEw== From a0028fea2dd05cbfb4d343f71db5b651196c4c48 Mon Sep 17 00:00:00 2001 From: TucksonDev Date: Wed, 6 Nov 2024 12:29:47 +0000 Subject: [PATCH 2/3] Smol adjustments to README files and comments --- README.md | 3 ++- packages/delayedInbox-l2msg/README.md | 6 +++--- packages/eth-deposit-to-different-address/scripts/exec.js | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 96c7391..c1ca8da 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ yarn install #### :white_check_mark: Moving stuff around - ⤴️ 🔹 [Deposit Ether](./packages/eth-deposit/) +- ⤴️ 🔹 [Deposit Ether to a different address](./packages/eth-deposit-to-different-address/) - ⤵️ 🔹 [Withdraw Ether](./packages/eth-withdraw/) - ⤴️ 💸 [Deposit Token](./packages/token-deposit/) - ⤵️ 💸 [Withdraw token](./packages/token-withdraw/) @@ -38,7 +39,7 @@ yarn install - ®️ [Arb Address Table](./packages/address-table/) - 🌉 [Bridging Custom Token](./packages/custom-token-bridging/) -- ✈️ [Delayed inbox message(l2MSG)](./packages/delayedInbox-l2msg/) +- ✈️ [Send a signed transaction from the parent chain](./packages/delayedInbox-l2msg/) - 🎁 [Redeem Retryable Ticket](./packages/redeem-failed-retryable/) - 🌀 [Deposit Ether or Tokens from L1 to L3](./packages/l1-l3-teleport/) diff --git a/packages/delayedInbox-l2msg/README.md b/packages/delayedInbox-l2msg/README.md index ac8bf29..1096193 100644 --- a/packages/delayedInbox-l2msg/README.md +++ b/packages/delayedInbox-l2msg/README.md @@ -1,8 +1,8 @@ -# Tutorial: send a message from the parent chain +# Tutorial: send a signed transaction from the parent chain -`delayedInbox-l2msg` shows how to send a message to your chain (also referred to as an L2Message) only using an RPC of the parent chain. This demo has 2 parts: +`delayedInbox-l2msg` shows how to send a signed transaction to your chain (also referred to as an L2Message) only using an RPC of the parent chain. This demo has 2 parts: -1. how to send a normal transaction using the delayed inbox ([./scripts/normalTx.js](./scripts/normalTx.js)) +1. how to send a normal signed transaction using the delayed inbox ([./scripts/normalTx.js](./scripts/normalTx.js)) 2. how to withdraw your funds back without sending a transaction directly to the sequencer ([./scripts/withdrawFunds.js](./scripts/withdrawFunds.js)) ## Bypassing the sequencer diff --git a/packages/eth-deposit-to-different-address/scripts/exec.js b/packages/eth-deposit-to-different-address/scripts/exec.js index 06da7fd..30789fc 100644 --- a/packages/eth-deposit-to-different-address/scripts/exec.js +++ b/packages/eth-deposit-to-different-address/scripts/exec.js @@ -55,6 +55,7 @@ const main = async () => { /** * Transfer ether from parent chain to a different address on child chain * This convenience method automatically queries for the retryable's max submission cost and forwards the appropriate amount to the specified address on the child chain + * by using a retryable ticket instead of a regular deposit. * Arguments required are: * (1) amount: The amount of ETH to be transferred * (2) parentSigner: The address on the parent chain of the account transferring ETH to the child chain From 250f5fc6373695c78bbdd7f3efd6b4e3beb5f8d7 Mon Sep 17 00:00:00 2001 From: TucksonDev Date: Wed, 6 Nov 2024 12:42:17 +0000 Subject: [PATCH 3/3] Mention native gas tokens for Orbit chains --- README.md | 6 +++--- .../README.md | 10 +++++----- .../scripts/exec.js | 19 ++++++++++--------- packages/eth-deposit/README.md | 8 ++++---- packages/eth-deposit/scripts/exec.js | 16 ++++++++-------- packages/eth-withdraw/README.md | 10 +++++----- packages/eth-withdraw/scripts/exec.js | 14 +++++--------- 7 files changed, 40 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index c1ca8da..f577266 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,9 @@ yarn install #### :white_check_mark: Moving stuff around -- ⤴️ 🔹 [Deposit Ether](./packages/eth-deposit/) -- ⤴️ 🔹 [Deposit Ether to a different address](./packages/eth-deposit-to-different-address/) -- ⤵️ 🔹 [Withdraw Ether](./packages/eth-withdraw/) +- ⤴️ 🔹 [Deposit Ether or native token](./packages/eth-deposit/) +- ⤴️ 🔹 [Deposit Ether or native token to a different address](./packages/eth-deposit-to-different-address/) +- ⤵️ 🔹 [Withdraw Ether or native token](./packages/eth-withdraw/) - ⤴️ 💸 [Deposit Token](./packages/token-deposit/) - ⤵️ 💸 [Withdraw token](./packages/token-withdraw/) - ⤴️ 🔹 [Contract alias control in the child chain, and fund-transfer guide](./packages/contract-deposit/) diff --git a/packages/eth-deposit-to-different-address/README.md b/packages/eth-deposit-to-different-address/README.md index 68869b5..dfcc2c0 100644 --- a/packages/eth-deposit-to-different-address/README.md +++ b/packages/eth-deposit-to-different-address/README.md @@ -1,16 +1,16 @@ -# eth-deposit-to-different-address tutorial +# Tutorial: deposit Ether or native token to a different address -`eth-deposit-to-different-address` shows how to move Ether from the parent chain into an Arbitrum or Orbit chain, to an address different than the depositor. +`eth-deposit-to-different-address` shows how to move Ether (or your chain's native token if you're using a custom gas token) from the parent chain into an Arbitrum or Orbit chain, to an address different than the depositor. ## How it works (under the hood) -For the common case of depositing ETH to the same account on the child chain, use the tutorial [eth-deposit](../eth-deposit/README.md). +For the common case of depositing Ether (or your chain's native token) to the same account on the child chain, use the tutorial [eth-deposit](../eth-deposit/README.md). -In this specific case, we will use a retryable ticket (Arbitrum's canonical method for creating cross-chain messages) to deposit ETH into a different address. We will use the parameter `l2CallValue` of the retryable ticket to specify the amount of ETH to deposit, and `callValueRefundAddress` to specify the destination address. For more info on retryable tickets, see [this page of the Arbitrum documentation](https://docs.arbitrum.io/how-arbitrum-works/arbos/l1-l2-messaging#eth-deposits). +In this specific case, we will use a retryable ticket (Arbitrum's canonical method for creating cross-chain messages) to deposit the chain's native token (e.g. Ether) into a different address. We will use the parameter `l2CallValue` of the retryable ticket to specify the amount of assets to deposit, and `callValueRefundAddress` to specify the destination address. For more info on retryable tickets, see [this page of the Arbitrum documentation](https://docs.arbitrum.io/how-arbitrum-works/arbos/l1-l2-messaging#eth-deposits). ## Using the Arbitrum SDK -Our [Arbitrum SDK](https://github.com/OffchainLabs/arbitrum-sdk) provides a simply convenience method for depositing Ether, abstracting away the need for the client to connect to any contracts manually. +Our [Arbitrum SDK](https://github.com/OffchainLabs/arbitrum-sdk) provides a simply convenience method for depositing Ether (or your chain's native token), abstracting away the need for the client to connect to any contracts manually. See [./exec.js](./scripts/exec.js) for inline explanation. diff --git a/packages/eth-deposit-to-different-address/scripts/exec.js b/packages/eth-deposit-to-different-address/scripts/exec.js index 30789fc..db210b3 100644 --- a/packages/eth-deposit-to-different-address/scripts/exec.js +++ b/packages/eth-deposit-to-different-address/scripts/exec.js @@ -23,7 +23,6 @@ const parentChainProvider = new providers.JsonRpcProvider( const childChainProvider = new providers.JsonRpcProvider(process.env.CHAIN_RPC) const parentChainWallet = new Wallet(walletPrivateKey, parentChainProvider) -const childChainWallet = new Wallet(walletPrivateKey, childChainProvider) /** * Set the destination address and amount to be deposited in the child chain (in wei) @@ -32,7 +31,9 @@ const destAddress = '0x2D98cBc6f944c4bD36EdfE9f98cd7CB57faEC8d6' const depositAmount = utils.parseEther('0.0001') const main = async () => { - await arbLog('Deposit Eth via Arbitrum SDK on a different address') + await arbLog( + 'Deposit native token (e.g. Ether) via Arbitrum SDK to a different address' + ) /** * Add the custom network configuration to the SDK if present @@ -41,24 +42,24 @@ const main = async () => { /** * Use childChainNetwork to create an Arbitrum SDK EthBridger instance - * We'll use EthBridger for its convenience methods around transferring ETH to the child chain + * We'll use EthBridger for its convenience methods around transferring the native asset to the child chain */ const childChainNetwork = await getArbitrumNetwork(childChainProvider) const ethBridger = new EthBridger(childChainNetwork) /** - * First, let's check the ETH balance of the destination address + * First, let's check the balance of the destination address */ const destinationAddressInitialEthBalance = await childChainProvider.getBalance(destAddress) /** - * Transfer ether from parent chain to a different address on child chain + * Transfer ether (or native token) from parent chain to a different address on child chain * This convenience method automatically queries for the retryable's max submission cost and forwards the appropriate amount to the specified address on the child chain * by using a retryable ticket instead of a regular deposit. * Arguments required are: - * (1) amount: The amount of ETH to be transferred - * (2) parentSigner: The address on the parent chain of the account transferring ETH to the child chain + * (1) amount: The amount of ETH (or native token) to be transferred + * (2) parentSigner: The address on the parent chain of the account transferring ETH (or native token) to the child chain * (3) childProvider: A provider of the child chain * (4) destinationAddress: The address where the ETH will be sent to */ @@ -102,12 +103,12 @@ const main = async () => { ) /** - * Our destination address ETH balance should be updated now + * Our destination address balance should be updated now */ const destinationAddressUpdatedEthBalance = await childChainProvider.getBalance(destAddress) console.log( - `ETH balance of the destination address has been updated from ${destinationAddressInitialEthBalance.toString()} to ${destinationAddressUpdatedEthBalance.toString()}` + `Balance of the destination address has been updated from ${destinationAddressInitialEthBalance.toString()} to ${destinationAddressUpdatedEthBalance.toString()}` ) } main() diff --git a/packages/eth-deposit/README.md b/packages/eth-deposit/README.md index 69b486f..5300d67 100644 --- a/packages/eth-deposit/README.md +++ b/packages/eth-deposit/README.md @@ -1,14 +1,14 @@ -# eth-deposit Tutorial +# Tutorial: deposit Ether or native token -`eth-deposit` shows how to move Ether from the parent chain into an Arbitrum or Orbit chain. +`eth-deposit` shows how to move Ether (or your chain's native token if you're using a custom gas token) from the parent chain into an Arbitrum or Orbit chain. ## How it works (under the hood) -A user deposits Ether onto an Arbitrum chain using Arbitrum's general Parent-to-child message passing system, and simply passing the desired Ether as callvalue and no additional data. For more info, see [this page of the Arbitrum documentation](https://docs.arbitrum.io/how-arbitrum-works/arbos/l1-l2-messaging#eth-deposits). +A user deposits the chain's native token (e.g. Ether) onto an Arbitrum chain using Arbitrum's general Parent-to-child message passing system, and simply passing the desired Ether as callvalue and no additional data. For more info, see [this page of the Arbitrum documentation](https://docs.arbitrum.io/how-arbitrum-works/arbos/l1-l2-messaging#eth-deposits). ## Using the Arbitrum SDK -Our [Arbitrum SDK](https://github.com/OffchainLabs/arbitrum-sdk) provides a simply convenience method for depositing Ether, abstracting away the need for the client to connect to any contracts manually. +Our [Arbitrum SDK](https://github.com/OffchainLabs/arbitrum-sdk) provides a simply convenience method for depositing Ether (or your chain's native token), abstracting away the need for the client to connect to any contracts manually. See [./exec.js](./scripts/exec.js) for inline explanation. diff --git a/packages/eth-deposit/scripts/exec.js b/packages/eth-deposit/scripts/exec.js index ad372a0..f39d13b 100644 --- a/packages/eth-deposit/scripts/exec.js +++ b/packages/eth-deposit/scripts/exec.js @@ -31,7 +31,7 @@ const childChainWallet = new Wallet(walletPrivateKey, childChainProvider) const depositAmount = utils.parseEther('0.0001') const main = async () => { - await arbLog('Deposit Eth via Arbitrum SDK') + await arbLog('Deposit native token (e.g. Ether) via Arbitrum SDK') /** * Add the custom network configuration to the SDK if present @@ -40,22 +40,22 @@ const main = async () => { /** * Use childChainNetwork to create an Arbitrum SDK EthBridger instance - * We'll use EthBridger for its convenience methods around transferring ETH to the child chain + * We'll use EthBridger for its convenience methods around transferring the native asset to the child chain */ const childChainNetwork = await getArbitrumNetwork(childChainProvider) const ethBridger = new EthBridger(childChainNetwork) /** - * First, let's check the wallet's initial ETH balance in the child chain + * First, let's check the wallet's initial balance in the child chain */ const initialEthBalance = await childChainWallet.getBalance() /** - * Transfer ether from parent to child chain + * Transfer ether (or native token) from parent to child chain * This convenience method automatically queries for the retryable's max submission cost and forwards the appropriate amount to the child chain * Arguments required are: - * (1) amount: The amount of ETH to be transferred - * (2) parentSigner: The address on the parent chain of the account transferring ETH to the child chain + * (1) amount: The amount of ETH (or native token) to be transferred + * (2) parentSigner: The address on the parent chain of the account transferring ETH (or native token) to the child chain * (3) childProvider: A provider of the child chain */ const depositTransaction = await ethBridger.deposit({ @@ -98,11 +98,11 @@ const main = async () => { ) /** - * Our wallet's ETH balance on the child chain should be updated now + * Our wallet's balance on the child chain should be updated now */ const updatedEthBalance = await childChainWallet.getBalance() console.log( - `Your ETH balance in the child chain is updated from ${initialEthBalance.toString()} to ${updatedEthBalance.toString()}` + `Your balance in the child chain is updated from ${initialEthBalance.toString()} to ${updatedEthBalance.toString()}` ) } main() diff --git a/packages/eth-withdraw/README.md b/packages/eth-withdraw/README.md index 88d6b5e..a334743 100644 --- a/packages/eth-withdraw/README.md +++ b/packages/eth-withdraw/README.md @@ -1,16 +1,16 @@ -# eth-withdraw tutorial +# Tutorial: withdraw Ether or native token -`eth-withdraw` shows how to move Ether from an Arbitrum or Orbit chain into its parent chain. +`eth-withdraw` shows how to move Ether (or your chain's native token if you're using a custom gas token) from an Arbitrum or Orbit chain into its parent chain. -Note that this repo covers initiating an Ether withdrawal. For a demo on releasing the funds from the Outbox, see [outbox-execute](../outbox-execute/README.md) +Note that this repo covers initiating a withdrawal. For a demo on releasing the funds from the Outbox, see [outbox-execute](../outbox-execute/README.md) ## How it works (under the hood) -To withdraw Ether from an Arbitrum chain, a client creates an outgoing / child to parent message using the `ArbSys` precompile that later lets them release Ether from its escrow in the parent chain's Bridge contract. For more info, see [this page of the Arbitrum documentation](https://docs.arbitrum.io/how-arbitrum-works/arbos/l2-l1-messaging). +To withdraw Ether (or your chain's native token) from an Arbitrum chain, a client creates an outgoing / child to parent message using the `ArbSys` precompile that later lets them release the asset from its escrow in the parent chain's Bridge contract. For more info, see [this page of the Arbitrum documentation](https://docs.arbitrum.io/how-arbitrum-works/arbos/l2-l1-messaging). ## Using the Arbitrum SDK -Our [Arbitrum SDK](https://github.com/OffchainLabs/arbitrum-sdk) provides a simply convenience method for withdrawing Ether, abstracting away the need for the client to connect to any contracts manually. +Our [Arbitrum SDK](https://github.com/OffchainLabs/arbitrum-sdk) provides a simply convenience method for withdrawing Ether (or your chain's native token), abstracting away the need for the client to connect to any contracts manually. See [./exec.js](./scripts/exec.js) for inline explanation. diff --git a/packages/eth-withdraw/scripts/exec.js b/packages/eth-withdraw/scripts/exec.js index b10b1c3..2529438 100644 --- a/packages/eth-withdraw/scripts/exec.js +++ b/packages/eth-withdraw/scripts/exec.js @@ -1,9 +1,5 @@ const { utils, providers, Wallet } = require('ethers') -const { - getArbitrumNetwork, - EthBridger, - EthDepositMessageStatus, -} = require('@arbitrum/sdk') +const { getArbitrumNetwork, EthBridger } = require('@arbitrum/sdk') const { arbLog, requireEnvVariables, @@ -34,26 +30,26 @@ const main = async () => { /** * Use childChainNetwork to create an Arbitrum SDK EthBridger instance - * We'll use EthBridger for its convenience methods around transferring ETH to the parent chain + * We'll use EthBridger for its convenience methods around transferring the native asset to the parent chain */ const childChainNetwork = await getArbitrumNetwork(childChainProvider) const ethBridger = new EthBridger(childChainNetwork) /** - * First, let's check our wallet's initial ETH balance in the child chain and ensure there's some ETH to withdraw + * First, let's check our wallet's initial balance in the child chain and ensure there's some native asset to withdraw */ const initialEthBalance = await childChainWallet.getBalance() if (initialEthBalance.lt(withdrawAmount)) { console.log( - `Oops - not enough ether; fund your wallet on the child chain ${childChainWallet.address} with at least 0.000001 ether` + `Oops - not enough balance; fund your wallet on the child chain ${childChainWallet.address} with at least 0.000001 ether (or your chain's gas token)` ) process.exit(1) } console.log('Wallet properly funded: initiating withdrawal now') /** - * We're ready to withdraw ETH using the ethBridger instance from Arbitrum SDK + * We're ready to withdraw the native asset using the ethBridger instance from Arbitrum SDK * It will use our current wallet's address as the default destination */ const withdrawTransaction = await ethBridger.withdraw({