diff --git a/pages/app-developers/tutorials/bridging/cross-dom-bridge-erc20.mdx b/pages/app-developers/tutorials/bridging/cross-dom-bridge-erc20.mdx index cf7f98399..4a6932a25 100644 --- a/pages/app-developers/tutorials/bridging/cross-dom-bridge-erc20.mdx +++ b/pages/app-developers/tutorials/bridging/cross-dom-bridge-erc20.mdx @@ -1,11 +1,11 @@ --- -title: Bridging ERC-20 tokens to OP Mainnet with the Optimism SDK +title: Bridging ERC-20 tokens to OP Mainnet description: >- - Learn how to use the Optimism SDK to transfer ERC-20 tokens between Layer 1 + Learn how to use the @eth-optimism/viem package to transfer ERC-20 tokens between Layer 1 (Ethereum or Sepolia) and Layer 2 (OP Mainnet or OP Sepolia). lang: en-US content_type: tutorial -topic: bridging-erc-20-tokens-to-op-mainnet-with-the-optimism-sdk +topic: bridging-erc-20-tokens-to-op-mainnet personas: - app-developer categories: @@ -18,19 +18,14 @@ is_imported_content: 'false' --- import { Callout, Steps } from 'nextra/components' -import { WipCallout } from '@/components/WipCallout' - +# Bridging ERC-20 tokens to OP Mainnet -# Bridging ERC-20 tokens to OP Mainnet with the Optimism SDK - - - -This tutorial explains how you can use the [Optimism SDK](https://sdk.optimism.io) to bridge ERC-20 tokens from L1 (Ethereum or Sepolia) to L2 (OP Mainnet or OP Sepolia). -The Optimism SDK is an easy way to add bridging functionality to your javascript-based application. +This tutorial explains how you can use [@eth-optimism/viem](https://www.npmjs.com/package/@eth-optimism/viem) to bridge ERC-20 tokens from L1 (Ethereum or Sepolia) to L2 (OP Mainnet or OP Sepolia). +The `@eth-optimism/viem` package is an easy way to add bridging functionality to your javascript-based application. It also provides some safety rails to prevent common mistakes that could cause tokens to be made inaccessible. -Behind the scenes, the Optimism SDK uses the [Standard Bridge](/app-developers/bridging/standard-bridge) contracts to transfer tokens. +Behind the scenes, `@eth-optimism/viem` package uses the [Standard Bridge](/app-developers/bridging/standard-bridge) contracts to transfer tokens. Make sure to check out the [Standard Bridge guide](/app-developers/bridging/standard-bridge) if you want to learn more about how the bridge works under the hood. @@ -42,9 +37,8 @@ Make sure to check out the [Standard Bridge guide](/app-developers/bridging/stan ## Supported networks -The Optimism SDK supports any of the [Superchain networks](/superchain/networks). -[Some Superchain networks](https://sdk.optimism.io/enums/l2chainid) are already included in the SDK by default. -If you want to use a network that isn't included by default, you can simply [instantiate the SDK with the appropriate contract addresses](/app-developers/get-started). +The `@eth-optimism/viem` package supports any of the [Superchain networks](/superchain/networks). +If you want to use a network that isn't included by default, you can simply [instantiate the package with the appropriate contract addresses](/app-developers/get-started). ## Dependencies @@ -53,15 +47,15 @@ If you want to use a network that isn't included by default, you can simply [ins ## Create a demo project -You're going to use the Optimism SDK for this tutorial. -Since the Optimism SDK is a [Node.js](https://nodejs.org/en/) library, you'll need to create a Node.js project to use it. +You're going to use the `@eth-optimism/viem` package for this tutorial. +Since the `@eth-optimism/viem` package is a [Node.js](https://nodejs.org/en/) library, you'll need to create a Node.js project to use it. {

Make a Project Folder

} ```bash - mkdir op-sample-project - cd op-sample-project + mkdir bridging-erc20-tokens + cd bridging-erc20-tokens ``` {

Initialize the Project

} @@ -70,16 +64,16 @@ Since the Optimism SDK is a [Node.js](https://nodejs.org/en/) library, you'll ne pnpm init ``` - {

Install the Optimism SDK

} + {

Install the `@eth-optimism/viem`

} ```bash - pnpm add @eth-optimism/sdk + pnpm add @eth-optimism/viem ``` - {

Install ethers.js

} + {

Install viem

} ```bash - pnpm add ethers@^5 + pnpm add viem ```
@@ -114,7 +108,7 @@ export TUTORIAL_PRIVATE_KEY=0x... ## Start the Node REPL -You're going to use the Node REPL to interact with the Optimism SDK. +You're going to use the Node REPL to interact with the `@eth-optimism/viem`. To start the Node REPL, run the following command in your terminal: ```bash @@ -126,16 +120,13 @@ This will bring up a Node REPL prompt that allows you to run javascript code. ## Import dependencies You need to import some dependencies into your Node REPL session. +The `@eth-optimism/viem` package uses ESM modules, and to use in the Node.js REPL, you need to use dynamic imports with await. +Here's how to do it: - {

Import the Optimism SDK

} - - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L3 hash=26b2fdb17dd6c8326a54ec51f0769528 - ``` - - {

Import ethers.js

} + {

Import the @eth-optimism/viem package

} - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L4 hash=69a65ef97862612e4978b8563e6dbe3a + ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L2-L10 hash=5e88e02086fb2f4cf2e1e99a4cd30b04 ```
@@ -147,20 +138,39 @@ Let's set those up now. {

Load your private key

} - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L6 hash=755b77a7ffc7dfdc186f36c37d3d847a + This step retrieves your private key from the environment variable you set earlier and converts it into an account object that Viem can use for transaction signing. + + The private key is essential for authorizing transactions on both L1 and L2 networks. + For security reasons, we access it from an environment variable rather than hardcoding it. + + ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L16-L17 hash=6a160f7ff083969091e72c90e1138563 ``` {

Create the RPC providers and wallets

} - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L8-L11 hash=9afdce50665ae93bce602068071ffaa1 + Here we establish the connections to both networks by creating four different clients: + + 1. L1 Public Client: For reading data from the Sepolia network + 2. L1 Wallet Client: For signing and sending transactions on Sepolia + 3. L2 Public Client: For reading data from OP Sepolia + 4. L2 Wallet Client: For signing and sending transactions on OP Sepolia + + Each client is configured with the appropriate chain information and RPC endpoint. + This dual-network setup allows us to seamlessly interact with both layers using the same account. + Replace `` with your API key from a RPC provider. + + ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L19-L42 hash=7f6a923f34ed2b0babdf44f57f88f8c1 ``` {

Set the L1 and L2 ERC-20 addresses

} - This tutorial uses existing ERC-20 tokens that have been deployed on Sepolia and OP Sepolia. - These tokens are designed for testing the bridging process. + We define the addresses of the ERC-20 tokens on both networks. + These are specially deployed test tokens with corresponding implementations on both L1 (Sepolia) and L2 (OP Sepolia). + + The L2 token is configured to recognize deposits from its L1 counterpart. + We also define a constant `oneToken` representing the full unit (10^18 wei) to simplify our deposit and withdrawal operations. - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L13-L14 hash=d8f0d4c8124782a6cd36097ff31010e5 + ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L12-L13 hash=d4da7ec838773c9f0e4ca38f4ba70242 ``` @@ -180,22 +190,38 @@ The L1 testing token located at [`0x5589BB8228C07c4e15558875fAf2B859f678d129`](h {

Set the ERC20 ABI

} - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L16 hash=d1caeba8dc014637e2b0b72f5cd076d0 - ``` + The Application Binary Interface (ABI) defines how to interact with the smart contract functions. This ERC-20 ABI includes several critical functions: + + * `balanceOf`: Allows us to check token balances for any address + * `faucet`: A special function in this test token that mints new tokens to the caller + * `approve`: Required to grant the bridge permission to transfer tokens on our behalf + * `allowance`: To check how many tokens we've approved for the bridge + * `decimals` and `symbol`: Provide token metadata - {

Create a Contract instance for the L1 token

} + This comprehensive ABI gives us everything we need to manage our tokens across both L1 and L2. - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L18 hash=9f9d7e38319ff5263e0e99d80d495554 + ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L44-L95 hash=7967d72de2b91fb16ba2b4723995e307 ``` {

Request some tokens

} - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L21-L22 hash=3533ec5426e8845fdb9af1e9e8d3de4c + Now we'll call the `faucet` function on the L1 test token contract to receive free tokens for testing. + This transaction will mint new tokens directly to our wallet address. + + The function doesn't require any parameters - it simply credits a predetermined amount to whoever calls it. + We store the transaction hash for later reference and wait for the transaction to be confirmed. + + ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L97-L104 hash=90511372fb9f975abfa8ec68659eb4a0 ``` {

Check your token balance

} - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L25 hash=d7a60aa394d1055555c2aeab2a2e111d + After using the faucet, we verify our token balance by calling the `balanceOf` function on the L1 token contract. + + This step confirms that we've successfully received tokens before proceeding with the bridging process. + The balance is returned in the smallest unit (wei), but we format it into a more readable form using the `formatEther` utility function from `viem`, since this token uses 18 decimal places. + + ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L109-L115 hash=63fcd2ca7e6fe0466340d615950e9658 ```
@@ -207,68 +233,92 @@ You'll then receive the same number of tokens on L2 in return. {

Define the amount to deposit

} - The testing token has 18 decimal places, so you'll want to define a variable that represents one token. + We define a variable `oneToken` that represents 1 full token in its base units (wei). + ERC-20 tokens typically use 18 decimal places, so 1 token equals 10^18 wei. + + This constant helps us work with precise token amounts in our transactions, avoiding rounding errors and ensuring exact value transfers. + We'll use this value for both deposits and withdrawals - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L27 hash=9349517ae6165a8798e49750da8faeee + ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L14 hash=1940b943a802d51e41572bc7d6bc4515 ``` - {

Create a CrossChainMessenger instance

} - - The Optimism SDK exports a `CrossChainMessenger` class that makes it easy to interact with the `L1StandardBridge` contract. + {

Allow the Standard Bridge to access your tokens

} - Create an instance of the `CrossChainMessenger` class: + ERC-20 tokens require a two-step process for transferring tokens on behalf of a user. + First, we must grant permission to the bridge contract to spend our tokens by calling the `approve` function on the token contract. + + We specify the bridge address from the chain configuration and the exact amount we want to bridge. + This approval transaction must be confirmed before the bridge can move our tokens. - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L29-L34 hash=997b9c4cdd5fb1f9d4e0882a683ae016 + ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L118-L125 hash=58cf2e8e55c1466e3ddaa1c030a5266b ``` - {

Allow the Standard Bridge to access your tokens

} + {

Wait for approval

} - Before you can deposit your tokens, you'll need to give the Standard Bridge contract an allowance of tokens on L1. - This will allow the Standard Bridge to pull these tokens out of your address and escrow inside the bridge. + After submitting the approval transaction, we need to wait for it to be confirmed on L1. + We use the `waitForTransactionReceipt` function to monitor the transaction until it's included in a block. + + The receipt provides confirmation details, including which block includes our transaction. + This step ensures our approval is finalized before attempting to bridge tokens. - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L37-L38 hash=3d9347e57540e808d71230c1bbe49db5 + ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L128 hash=cfbada5a799bb17450ce56580bc31e11 ``` {

Deposit your tokens

} - Now you can deposit your tokens into the Standard Bridge contract. + Now we can execute the actual bridging operation using the `depositERC20` function from the `@eth-optimism/viem` package. + + This function handles all the complex interactions with the `L1StandardBridge` contract for us. + We provide: + + * The addresses of both the L1 and L2 tokens + * The amount to bridge + * The target chain (OP Sepolia) + * Our wallet address as the recipient on L2 + * A minimum gas limit for the L2 transaction - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L41-L42 hash=0dc6191c87c0a371d7a469ed98190e57 + This streamlined process ensures our tokens are safely transferred to L2. + + ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L130-L139 hash=5084d848deaf4b798706446a24e54a18 ``` Using a smart contract wallet? As a safety measure, `depositERC20` will fail if you try to deposit ETH from a smart contract wallet without specifying a `recipient`. Add the `recipient` option to the `depositERC20` call to fix - this. Check out the [Optimism SDK - docs](https://sdk.optimism.io/classes/crosschainmessenger#depositERC20-2) for + this. Check out the [@eth-optimism/viem + docs](https://github.com/ethereum-optimism/ecosystem/tree/main/packages/viem) for more info on the options you can pass to `depositERC20`. {

Wait for the deposit to be relayed

} - You can use the `waitForMessageStatus` function to wait for the deposit to be relayed to L2. + After initiating the deposit, we need to wait for the L1 transaction to be confirmed. + This function tracks the transaction until it's included in an L1 block. + + Note that while this confirms the deposit was accepted on L1, there will still be a short delay (typically a few minutes) before the tokens appear on L2, as the transaction needs to be processed by the Optimism sequencer. - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L45 hash=659971675ab8d53bc2bd5196f72c873b + ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L141-L142 hash=886c0a2fe4aa92dc67288d02bb654c3e ``` {

Check your token balance on L1

} - You should now have one less token on L1. + After the deposit transaction is confirmed, we check our token balance on L1 again to verify that the tokens have been deducted. + + This balance should be lower by the amount we bridged, as those tokens are now escrowed in the `L1StandardBridge` contract. + This step helps confirm that the first part of the bridging process completed successfully: - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L48 hash=d7a60aa394d1055555c2aeab2a2e111d - ``` - - {

Create a Contract instance for the L2 token

} - - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L50 hash=d7ab5afad79dafcb7be976c3d0d3df84 + ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L148-L154 hash=9985ca726c10c42d96ea508c247a878c ``` {

Check your token balance on L2

} - You should now have one more token on L2. + After allowing some time for the L2 transaction to be processed, we check our token balance on L2 to verify that we've received the bridged tokens. + + The newly minted L2 tokens should appear in our wallet at the same address we used on L1. + This step confirms the complete success of the bridge operation from L1 to L2. - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L53 hash=b332b68817359e4c6e991ed83de6e490 + ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L177-L183 hash=bf12c15e0ea43846a09176d351bf4f33 ```
@@ -279,26 +329,31 @@ Nice! Now you're going to repeat the process in reverse to bridge some tokens from L2 to L1. - {

Start your withdrawal on L2

} - - The first step to withdrawing tokens from L2 to L1 is to start the withdrawal on L2. + {

Initiate the withdrawal

} - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L56-L57 hash=b97f906085a2c350d9113488ea9b1d45 - ``` + To move tokens back to L1, we use the `withdrawOptimismERC20` function from the `@eth-optimism/viem` package. + This function interacts with the `L2StandardBridge` contract to initialize the withdrawal process. + We specify: - {

Check your token balance on L2

} + * The L2 token address + * The amount to withdraw (we're using half of a token in this tutorial) + * Our address as the recipient on L1 + * A minimum gas limit for the transaction - You should now have one less token on L2, but your token balance on L1 will not have changed yet. + Unlike deposits, withdrawals from L2 to L1 are not immediate and require a multi-step process including a 7-day challenge period for security reasons. - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L60 hash=b332b68817359e4c6e991ed83de6e490 + ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L164-L171 hash=9ee233eaa1711443ff15e0d28d2da190 ``` - {

Wait until the withdrawal is ready to prove

} + {

Wait for the transaction receipt

} - The second step to withdrawing tokens from L2 to L1 is to prove to the bridge on L1 that the withdrawal happened on L2. - You first need to wait until the withdrawal is ready to prove. + Similar to deposits, we wait for the withdrawal transaction to be confirmed on L2. + This receipt provides confirmation that the withdrawal has been initiated. + + The transaction logs contain critical information that will be used later in the withdrawal verification process. + This is only the first step in the withdrawal - the tokens are now locked on L2, but not yet available on L1. - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L63 hash=e8b55ec0f16f90ba4d4197cf47ff8e6d + ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L173-L174 hash=f1359ec27815a9fcf4964a877280da59 ``` @@ -306,52 +361,20 @@ Now you're going to repeat the process in reverse to bridge some tokens from L2 wait. - {

Prove the withdrawal on L1

} - - Once the withdrawal is ready to be proven, you'll send an L1 transaction to prove that the withdrawal happened on L2. - - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L66 hash=fee5f5e924472ee9daceb681ccae1cb9 - ``` - - {

Wait until the withdrawal is ready for relay

} - - The final step to withdrawing tokens from L2 to L1 is to relay the withdrawal on L1. - This can only happen after the fault proof period has elapsed. - On OP Mainnet, this takes 7 days. - - - We're currently testing fault proofs on OP Sepolia, so withdrawal times - reflect Mainnet times. - - - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L69 hash=55a41ac5586b8a688ffd6dfbb20f2d15 - ``` - - {

Relay the withdrawal on L1

} - - Once the withdrawal is ready to be relayed, you can finally complete the withdrawal process. - - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L85 hash=f8d30944dad1664d82b9fdf14da59f9e - ``` - - {

Wait until the withdrawal is relayed

} - - Now you simply wait until the message is relayed. - - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L88 hash=c2c14a739c44011a058e9848a0019f15 - ``` - - {

Check your token balance on L1

} + {

Check your token balance on L2

} - You should now have one more token on L1. + After the withdrawal transaction is confirmed, we check our token balance on L2 again to verify that the tokens have been deducted. + Our L2 balance should now be lower by the amount we initiated for withdrawal. + + At this point, the withdrawal process has begun, but the tokens are not yet available on L1 - they will become accessible after the 7-day challenge period and after completing the "prove" and "finalize" withdrawal steps. - ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L91 hash=d7a60aa394d1055555c2aeab2a2e111d + ```js file=/public/tutorials/cross-dom-bridge-erc20.js#L177-L183 hash=bf12c15e0ea43846a09176d351bf4f33 ```
## Next steps Congrats! -You've just deposited and withdrawn tokens using the Optimism SDK. -You should now be able to write applications that use the Optimism SDK to transfer ERC-20 tokens between L1 and L2. +You've just deposited and withdrawn tokens using `@eth-optimism/viem` package. +You should now be able to write applications that use the `@eth-optimism/viem` package to transfer ERC-20 tokens between L1 and L2. Although this tutorial used Sepolia and OP Sepolia, the same process works for Ethereum and OP Mainnet. diff --git a/pages/notices/_meta.json b/pages/notices/_meta.json index fb1599c69..bda2e2e29 100644 --- a/pages/notices/_meta.json +++ b/pages/notices/_meta.json @@ -7,6 +7,5 @@ "upgrade-14": "Upgrade 14: MT-Cannon and Isthmus L1 Contracts", "upgrade-13": "Upgrade 13: OPCM and incident response improvements", "blob-fee-bug": "Superchain testnets' blob fee bug", - "custom-gas-tokens-deprecation": "Preparing for Custom Gas Tokens deprecation", - "sdk-deprecation": "Preparing for Optimism SDK deprecation" + "custom-gas-tokens-deprecation": "Preparing for Custom Gas Tokens deprecation" } diff --git a/pages/notices/sdk-deprecation.mdx b/pages/notices/sdk-deprecation.mdx deleted file mode 100644 index f64f6e724..000000000 --- a/pages/notices/sdk-deprecation.mdx +++ /dev/null @@ -1,83 +0,0 @@ ---- -title: Preparing for Optimism SDK deprecation -description: >- - This page outlines the details of the Optimism SDK deprecation and guides - developers to migrate to using `viem` library. -lang: en-US -content_type: guide -topic: sdk-deprecation -personas: - - app-developer -categories: - - protocol - - ethers - - viem -is_imported_content: 'false' ---- - -## Preparing for Optimism SDK deprecation - -The Optimism SDK will officially be deprecated in Q1 2025. The project is shifting to the `viem` library for a more modern, efficient, and flexible development experience. This change affects all tutorials and resources that previously relied on the Optimism SDK, and relevant documentation has been updated accordingly. - -### Breaking changes to expect - -The migration from the Optimism SDK to [viem](https://viem.sh/op-stack) library brings several breaking changes: - -* **Transaction estimation**: Methods for estimating gas fees will now leverage `viem` APIs. -* **Bridging**: All token bridging actions must be updated to use the `viem` library bridging methods. -* **Cross-chain communication**: `viem` library simplifies the cross-domain messaging functionality. -* **SDK method removal**: All deprecated SDK methods will be unavailable after Q1 2025. - -Developers and users are strongly encouraged to transition to `viem` before the deprecation date to avoid disruptions. - -### Updated tutorials - -We are updating our tutorials to use the `viem` library. - -### For app developers - -If your application currently depends on the Optimism SDK, you will need to migrate to using the `viem` library. -The tutorials have been updated to reflect these changes, and it is critical to update your applications before the deprecation date to maintain compatibility. - -Here are some key points to consider: - -Install new dependencies: Replace the Optimism SDK with `viem` in your project. - -```bash - pnpm remove @eth-optimism/sdk - pnpm add viem -``` - -* Update imports: Replace Optimism SDK imports with `viem` imports. -* Migrate SDK methods: Refactor your code to use equivalent `viem` methods. Refer to the viem documentation and opstack documentation for guidance. -* Test thoroughly: After migration, extensively test your application to ensure all functionality works as expected. - -### For chain operators - -Chain operators utilizing the SDK for cross-chain operations, bridging, or other functions should switch to the `viem` library. -The `viem` library offers more efficient methods to handle these operations. - -Chain operators should be aware of the following: - -* SDK removal: Remove any dependencies on the Optimism SDK in your infrastructure. -* Update tooling: Ensure all tools and scripts are updated to use `viem`. -* Monitor performance: After migration, closely monitor your chain's performance to ensure smooth operation. - -### For node operators - -Node operators will need to ensure that any scripts or services relying on the Optimism SDK are updated to use `viem` library. -These updates will help align with future improvements and scalability efforts across the OP Stack. - -Node operators should take the following steps: - -* Update node software: Ensure your node software is compatible with the latest `viem` libraries. -* Review configuration: Check and update any configuration files that may reference the Optimism SDK. -* Test thoroughly: Perform comprehensive testing in a staging environment before updating production nodes. - -### Need help? - -For further assistance or questions about this migration, feel free to reach through the following channels: - -* Connect with us on [Discord](https://discord.gg/optimism) for community support -* Join us on our [developer forum](https://github.com/ethereum-optimism/developers/discussions) for discussions, questions, and general support. -* Open an [issue on our GitHub repository](https://github.com/ethereum-optimism/docs/issues) for documentation-related concerns diff --git a/pages/operators/chain-operators/deploy.mdx b/pages/operators/chain-operators/deploy.mdx index 7d4e7b49b..82bfb891b 100644 --- a/pages/operators/chain-operators/deploy.mdx +++ b/pages/operators/chain-operators/deploy.mdx @@ -24,12 +24,12 @@ import { Card, Cards } from 'nextra/components' This section provides information on OP Stack genesis creation, deployment overview, and smart contract deployment. You'll find guides and overviews to help you understand and work with these topics. - + - + - + - + diff --git a/pages/operators/chain-operators/deploy/_meta.json b/pages/operators/chain-operators/deploy/_meta.json new file mode 100644 index 000000000..9921d07e6 --- /dev/null +++ b/pages/operators/chain-operators/deploy/_meta.json @@ -0,0 +1,7 @@ +{ + "overview": "Deployment overview", + "smart-contracts": "Smart contract deployment", + "validate-deployment": "Validate your contract deployment", + "genesis": "Chain artifacts creation" +} + diff --git a/pages/operators/chain-operators/deploy/genesis.mdx b/pages/operators/chain-operators/deploy/genesis.mdx index 1ae29e717..bffa42b8e 100644 --- a/pages/operators/chain-operators/deploy/genesis.mdx +++ b/pages/operators/chain-operators/deploy/genesis.mdx @@ -1,7 +1,7 @@ --- -title: OP Stack genesis creation +title: Chain artifacts creation lang: en-US -description: Learn how to create a genesis file for the OP Stack. +description: Learn how to create genesis and rollup configuration files using op-deployer after L1 contract deployment. content_type: guide topic: genesis-creation personas: @@ -20,78 +20,93 @@ is_imported_content: 'false' import { Callout } from 'nextra/components' -# OP Stack genesis creation +# Overview - - The recommended way to generate genesis and rollup configuration files is using `op-deployer`. - This ensures standardization and compatibility with the Superchain. - +After deploying the L1 system contracts for your OP Stack chain, you need to generate two files to run nodes on the L2 network: + +* **Genesis file** (`genesis.json`): Initializes the execution client (`op-geth`) +* **Rollup configuration file** (`rollup.json`): Configures the consensus client (`op-node`) -The `op-deployer` tool simplifies the creation of genesis and rollup configuration files (`genesis.json` and `rollup.json`). -These files are crucial for initializing the execution client (`op-geth`) and consensus client (`op-node`) for your network. +This guide shows you how to generate these files from your L1 contract deployment data using `op-deployer`. -The recommended flow for creating a genesis file and rollup configuration file on the OP Stack is as follows: +## Prerequisites -1. **Deploy the L1 contracts** using [op-deployer](/operators/chain-operators/tools/op-deployer). -2. **Generate** both the L2 genesis file (`genesis.json`) and the rollup configuration file (`rollup.json`) using op-deployer's `inspect` commands. -3. **Initialize** your off-chain components (e.g., execution client, consensus client). +Before generating genesis and rollup configuration files, ensure you have: -## Recommended method: using op-deployer +1. Deployed the L1 contracts successfully using the [`op-deployer apply`](/operators/chain-operators/tools/op-deployer#apply-deploy-your-chain) command -### Prerequisites +2. Access to your deployment workspace directory (`.deployer` if you've followed the instructions in the L1 deployment contracts guide) -1. You have installed the `op-deployer` binary following the instructions in [deployer docs](/operators/chain-operators/tools/op-deployer#installation). - After installation, extract the `op-deployer` into your `PATH` and `cd op-deployer`. +## Generating genesis and rollup files -2. You have created and customized an intent file in a `.deployer` directory, typically by running: +After your L1 contracts have been deployed, follow these steps to generate the configuration files: - ```bash - ./bin/op-deployer init --l1-chain-id --l2-chain-ids --workdir .deployer - ``` +### Step 1: Locate your deployment state file - Replace `` and `` with their respective values, see a list of [`chainIds`](https://chainid.network/). +The `op-deployer` tool creates a `state.json` file in your workspace directory that contains all the necessary information about your deployed contracts. -3. You have edited that intent file to your liking (roles, addresses, etc.). +Verify that this file exists in your workspace: + +```bash +ls -la .deployer/state.json +``` -### Step 1: Deploy the L1 contracts +### Step 2: Generate the L2 genesis file -To deploy your chain to L1, run: +Use the `inspect genesis` command to retrieve your L2 genesis file: ```bash -./bin/op-deployer apply --workdir .deployer \ - --l1-rpc-url \ - --private-key +op-deployer inspect genesis --workdir .deployer > .deployer/genesis.json ``` -This command: +Replace `` with your L2 network's chain ID. + +### Step 3: Generate the rollup configuration file -* Reads your intent file in `.deployer/.` -* Deploys the OP Stack contracts to the specified L1. -* Updates a local `state.json` file with the results of the deployment. +Use the `inspect rollup` command to retrieve your rollup configuration file: -### Step 2: Generate your L2 genesis file and rollup file +```bash +op-deployer inspect rollup --workdir .deployer > .deployer/rollup.json +``` -After your L1 contracts have been deployed, generate the L2 genesis and rollup configuration files by inspecting the deployer's `state.json` +### Step 4: Verify the generated files + +Examine the generated files to ensure they contain the expected configuration: ```bash -./bin/op-deployer inspect genesis --workdir .deployer > .deployer/genesis.json -./bin/op-deployer inspect rollup --workdir .deployer > .deployer/rollup.json +# View the genesis file structure +jq . .deployer/genesis.json | head -20 + +# View the rollup configuration +jq . .deployer/rollup.json ``` -* genesis.json is the file you will provide to your execution client (e.g. op-geth). -* rollup.json is the file you will provide to your consensus client (e.g. op-node). +The `genesis.json` file contains the initial state of your L2 blockchain, including: + +* Chain configuration parameters +* Initial account states +* Genesis block properties + +The `rollup.json` file contains the rollup protocol parameters, including: -### Step 3: Initialize your off-chain components +* L1 contract addresses +* Sequencing settings +* Protocol upgrade activation times -Once you have `genesis.json` and `rollup.json`: +## Troubleshooting -1. Initialize op-geth using genesis.json. -2. Configure op-node with rollup.json. -3. Set up additional off-chain infrastructure as needed (block explorer, indexers, etc.). For more on architecture, see [Architecture overview](/operators/chain-operators/architecture). +If you encounter issues with the generated files: + +* [Verify](/operators/chain-operators/tools/op-deployer#verify-verify-contract-source-code-on-block-explorers) that your L1 contract deployment was successful +* Check that you're using the correct **L2 chain ID** in the generation commands +* Ensure your `state.json` file is up-to-date with your latest deployment + + + Never manually edit the generated genesis or rollup files unless you fully understand the implications. Incorrect configurations can lead to consensus failures or chain security issues. + ## Next steps -* Learn how to [initialize](/operators/node-operators/configuration/base-config#initialization-via-genesis-file) - `op-geth` with your `genesis.json` file. -* Learn how to [initialize](/operators/node-operators/configuration/base-config#configuring-op-node) `op-node` with your `rollup.json` file. -* Learn more about the off chain [architecture](/operators/chain-operators/architecture). +* Learn how to [initialize](/operators/node-operators/configuration/base-config#initialization-via-genesis-file) `op-geth` with your `genesis.json` file +* Learn how to [configure](/operators/node-operators/configuration/base-config#configuring-op-node) `op-node` with your `rollup.json` file +* Learn more about the off-chain [architecture](/operators/chain-operators/architecture) diff --git a/pages/operators/chain-operators/deploy/overview.mdx b/pages/operators/chain-operators/deploy/overview.mdx index c9f8885b2..3d2692263 100644 --- a/pages/operators/chain-operators/deploy/overview.mdx +++ b/pages/operators/chain-operators/deploy/overview.mdx @@ -1,5 +1,5 @@ --- -title: OP Stack deployment overview +title: Deployment overview lang: en-US description: Learn about the different components of deploying a standard OP Stack chain. content_type: guide @@ -20,7 +20,7 @@ is_imported_content: 'false' import { Callout } from 'nextra/components' -# OP Stack deployment overview +# Deployment overview When deploying a **standard OP Stack chain**, you'll be setting up several key components. It's useful to understand what each of these components does before diff --git a/pages/operators/chain-operators/deploy/smart-contracts.mdx b/pages/operators/chain-operators/deploy/smart-contracts.mdx index e84905a8a..fd85d2456 100644 --- a/pages/operators/chain-operators/deploy/smart-contracts.mdx +++ b/pages/operators/chain-operators/deploy/smart-contracts.mdx @@ -1,5 +1,5 @@ --- -title: OP Stack Smart Contract Deployment +title: Smart contract deployment lang: en-US description: Learn how to deploy the OP Stack L1 smart contracts. content_type: guide @@ -20,12 +20,10 @@ is_imported_content: 'false' import { Callout, Steps } from 'nextra/components' -# OP Stack smart contract deployment +# Overview This guide outlines the process for deploying the OP Stack L1 smart contracts using `op-deployer`. -## Overview - Deploying OP Stack L1 contracts is a critical step in setting up your rollup. diff --git a/pages/operators/chain-operators/deploy/validate-deployment.mdx b/pages/operators/chain-operators/deploy/validate-deployment.mdx index f369ef093..69ba6002b 100644 --- a/pages/operators/chain-operators/deploy/validate-deployment.mdx +++ b/pages/operators/chain-operators/deploy/validate-deployment.mdx @@ -1,5 +1,5 @@ --- -title: Validating your OP Stack deployment +title: Validate your contract deployment lang: en-US description: Learn how to validate your OP Stack deployment using op-validator content_type: guide diff --git a/public/tutorials/cross-dom-bridge-erc20.js b/public/tutorials/cross-dom-bridge-erc20.js index 8244f367e..ea2b5b10e 100644 --- a/public/tutorials/cross-dom-bridge-erc20.js +++ b/public/tutorials/cross-dom-bridge-erc20.js @@ -1,93 +1,185 @@ (async () => { -const optimism = require("@eth-optimism/sdk") -const ethers = require("ethers") - -const privateKey = process.env.TUTORIAL_PRIVATE_KEY - -const l1Provider = new ethers.providers.StaticJsonRpcProvider("https://rpc.ankr.com/eth_sepolia") -const l2Provider = new ethers.providers.StaticJsonRpcProvider("https://sepolia.optimism.io") -const l1Wallet = new ethers.Wallet(privateKey, l1Provider) -const l2Wallet = new ethers.Wallet(privateKey, l2Provider) - -const l1Token = "0x5589BB8228C07c4e15558875fAf2B859f678d129" -const l2Token = "0xD08a2917653d4E460893203471f0000826fb4034" - -const erc20ABI = [{ constant: true, inputs: [{ name: "_owner", type: "address" }], name: "balanceOf", outputs: [{ name: "balance", type: "uint256" }], type: "function" }, { inputs: [], name: "faucet", outputs: [], stateMutability: "nonpayable", type: "function" }] - -const l1ERC20 = new ethers.Contract(l1Token, erc20ABI, l1Wallet) - -console.log('Getting L1 tokens from faucet...') -tx = await l1ERC20.faucet() -await tx.wait() - -console.log('L1 balance:') -console.log((await l1ERC20.balanceOf(l1Wallet.address)).toString()) - -const oneToken = 1000000000000000000n - -const messenger = new optimism.CrossChainMessenger({ - l1ChainId: 11155111, // 11155111 for Sepolia, 1 for Ethereum - l2ChainId: 11155420, // 11155420 for OP Sepolia, 10 for OP Mainnet - l1SignerOrProvider: l1Wallet, - l2SignerOrProvider: l2Wallet, -}) - -console.log('Approving L1 tokens for deposit...') -tx = await messenger.approveERC20(l1Token, l2Token, oneToken) -await tx.wait() - -console.log('Depositing L1 tokens...') -tx = await messenger.depositERC20(l1Token, l2Token, oneToken) -await tx.wait() - -console.log('Waiting for deposit to be relayed...') -await messenger.waitForMessageStatus(tx.hash, optimism.MessageStatus.RELAYED) - -console.log('L1 balance:') -console.log((await l1ERC20.balanceOf(l1Wallet.address)).toString()) - -const l2ERC20 = new ethers.Contract(l2Token, erc20ABI, l2Wallet) - -console.log('L2 balance:') -console.log((await l2ERC20.balanceOf(l2Wallet.address)).toString()) - -console.log('Withdrawing L2 tokens...') -const withdrawal = await messenger.withdrawERC20(l1Token, l2Token, oneToken) -await withdrawal.wait() - -console.log('L2 balance:') -console.log((await l2ERC20.balanceOf(l2Wallet.address)).toString()) - -console.log('Waiting for withdrawal to be provable...') -await messenger.waitForMessageStatus(withdrawal.hash, optimism.MessageStatus.READY_TO_PROVE) - -console.log('Proving withdrawal...') -await messenger.proveMessage(withdrawal.hash) - -console.log('Waiting for withdrawal to be relayable...') -await messenger.waitForMessageStatus(withdrawal.hash, optimism.MessageStatus.READY_FOR_RELAY) - -// Wait for the next block to be produced, only necessary for CI because messenger can return -// READY_FOR_RELAY before the RPC we're using is caught up to the latest block. Waiting for an -// additional block ensures that the RPC is caught up and the message can be relayed. Users -// should not need to do this when running the tutorial. -const maxWaitTime = Date.now() + 120000 // 2 minutes in milliseconds -const currentBlock = await l1Provider.getBlockNumber() -while (await l1Provider.getBlockNumber() < currentBlock + 1) { - if (Date.now() > maxWaitTime) { - throw new Error('Timed out waiting for block to be produced') - } - await new Promise(resolve => setTimeout(resolve, 1000)) -} - -console.log('Relaying withdrawal...') -await messenger.finalizeMessage(withdrawal.hash) - -console.log('Waiting for withdrawal to be relayed...') -await messenger.waitForMessageStatus(withdrawal.hash, optimism.MessageStatus.RELAYED) - -console.log('L1 balance:') -console.log((await l1ERC20.balanceOf(l1Wallet.address)).toString()) - -})() + const viem = await import('viem'); + const { createPublicClient, createWalletClient, http, formatEther } = viem; + const accounts = await import('viem/accounts'); + const { privateKeyToAccount } = accounts; + const viemChains = await import('viem/chains'); + const { optimismSepolia, sepolia } = viemChains; + const opActions = await import('@eth-optimism/viem/actions'); + const { depositERC20, withdrawOptimismERC20 } = opActions; + + const l1Token = "0x5589BB8228C07c4e15558875fAf2B859f678d129"; + const l2Token = "0xD08a2917653d4E460893203471f0000826fb4034"; + const oneToken = 1000000000000000000n + + const PRIVATE_KEY = process.env.TUTORIAL_PRIVATE_KEY || ''; + const account = privateKeyToAccount(PRIVATE_KEY); + + const L1_RPC_URL = 'https://rpc.ankr.com/eth_sepolia/'; + const L2_RPC_URL = 'https://sepolia.optimism.io'; + + const publicClientL1 = createPublicClient({ + chain: sepolia, + transport: http(L1_RPC_URL), + }); + + const walletClientL1 = createWalletClient({ + account, + chain: sepolia, + transport: http(L1_RPC_URL), + }); + + const publicClientL2 = createPublicClient({ + chain: optimismSepolia, + transport: http(L2_RPC_URL), + }); + + const walletClientL2 = createWalletClient({ + account, + chain: optimismSepolia, + transport: http(L2_RPC_URL), + }); + + const erc20ABI = [ + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "balanceOf", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "faucet", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "spender", + type: "address" + }, + { + internalType: "uint256", + name: "value", + type: "uint256" + } + ], + name: "approve", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + ]; + + console.log('Getting tokens from faucet...'); + const tx = await walletClientL1.writeContract({ + address: l1Token, + abi: erc20ABI, + functionName: 'faucet', + account, + }); + console.log('Faucet transaction:', tx); + + // Wait for the transaction to be mined + await publicClientL1.waitForTransactionReceipt({ hash: tx }); + + const l1Balance = await publicClientL1.readContract({ + address: l1Token, + abi: erc20ABI, + functionName: 'balanceOf', + args: [account.address] + }); + console.log(`L1 Balance after receiving faucet: ${formatEther(l1Balance)}`); + + console.log('Approving tokens for bridge...'); + const bridgeAddress = optimismSepolia.contracts.l1StandardBridge[sepolia.id].address; + const approveTx = await walletClientL1.writeContract({ + address: l1Token, + abi: erc20ABI, + functionName: 'approve', + args: [bridgeAddress, oneToken], + }); + console.log('Approval transaction:', approveTx); + + // Wait for approval transaction to be mined + await publicClientL1.waitForTransactionReceipt({ hash: approveTx }); + + console.log('Depositing tokens to L2...'); + const depositTx = await depositERC20(walletClientL1, { + tokenAddress: l1Token, + remoteTokenAddress: l2Token, + amount: oneToken, + targetChain: optimismSepolia, + to: account.address, + minGasLimit: 200000, + }); + console.log(`Deposit transaction hash: ${depositTx}`); + + const depositReceipt = await publicClientL1.waitForTransactionReceipt({ hash: depositTx }); + console.log(`Deposit confirmed in block ${depositReceipt.blockNumber}`); + console.log("Token bridging initiated! The tokens will arrive on L2 in a few minutes."); + + console.log('Waiting for tokens to arrive on L2...'); + + await new Promise(resolve => setTimeout(resolve, 60000)); // 1 minute + const l1BalanceAfterDeposit = await publicClientL1.readContract({ + address: l1Token, + abi: erc20ABI, + functionName: 'balanceOf', + args: [account.address] + }); + console.log(`L1 Balance after deposit: ${formatEther(l1BalanceAfterDeposit)}`); + + const l2BalanceAfterDeposit = await publicClientL2.readContract({ + address: l2Token, + abi: erc20ABI, + functionName: 'balanceOf', + args: [account.address] + }); + console.log(`L2 Balance after deposit: ${formatEther(l2BalanceAfterDeposit)}`); + + console.log('Withdrawing tokens back to L1...'); + const withdrawTx = await withdrawOptimismERC20(walletClientL2, { + tokenAddress: l2Token, + amount: oneToken / 2n, + to: account.address, + minGasLimit: 200000, + }); + console.log(`Withdrawal transaction hash: ${withdrawTx}`); + + const withdrawReceipt = await publicClientL2.waitForTransactionReceipt({ hash: withdrawTx }); + console.log(`Withdrawal initiated in L2 block ${withdrawReceipt.blockNumber}`); + console.log("Withdrawal process initiated! It will take 7 days for the tokens to be available on L1."); + + const l2Balance = await publicClientL2.readContract({ + address: l2Token, + abi: erc20ABI, + functionName: 'balanceOf', + args: [account.address] + }); + console.log(`L2 Balance after withdrawal: ${formatEther(l2Balance)}`); + +})(); diff --git a/styles/global.css b/styles/global.css index d35079960..06a25fa39 100644 --- a/styles/global.css +++ b/styles/global.css @@ -283,4 +283,10 @@ div.footer-columns { align-items: center; gap: 2rem; } + } + + code .line .highlighted { + background-color: transparent !important; + --tw-shadow-color: transparent !important; + box-shadow: none !important; } \ No newline at end of file diff --git a/theme.config.tsx b/theme.config.tsx index 2eb268c6a..143030bac 100644 --- a/theme.config.tsx +++ b/theme.config.tsx @@ -33,15 +33,15 @@ const config: DocsThemeConfig = { ), darkMode: true, - banner: { - key: 'viem/op-stack', - text: ( - - 🎉 We are deprecating the Optimism SDK and migrating all tutorials to use viem/op-stack. - Read more → - - ) - }, + // banner: { + // key: 'viem/op-stack', + // text: ( + // + // 🎉 We are deprecating the Optimism SDK and migrating all tutorials to use viem/op-stack. + // Read more → + // + // ) + // }, search: { component: Search }, diff --git a/words.txt b/words.txt index ead225f77..9d9f365d7 100644 --- a/words.txt +++ b/words.txt @@ -273,7 +273,6 @@ OPCM Openfort oplabs opnode's -opstack outfile Pausability pcscdpath