|
1 | 1 | --- |
2 | | -title: Transferring a SuperchainERC20 |
| 2 | +title: Transferring SuperchainERC20 tokens |
3 | 3 | lang: en-US |
4 | 4 | description: Learn how to transfer a SuperchainERC20 between chains using L2ToL2CrossDomainMessenger. |
5 | 5 | --- |
6 | 6 |
|
7 | 7 | import { Callout, Steps } from 'nextra/components' |
| 8 | +import { AutorelayCallout } from '@/components/AutorelayCallout' |
8 | 9 |
|
9 | 10 | <Callout> |
10 | | -The SuperchainERC20 standard is ready for production use with active Mainnet deployments. |
11 | | -Please note that the OP Stack interoperability upgrade, required for crosschain messaging, is currently still in active development. |
| 11 | + The SuperchainERC20 standard is ready for production deployments. |
| 12 | + Please note that the OP Stack interoperability upgrade, required for crosschain messaging, is currently still in active development. |
12 | 13 | </Callout> |
13 | 14 |
|
14 | | -# Transferring a SuperchainERC20 |
| 15 | +# Transferring SuperchainERC20 tokens |
15 | 16 |
|
16 | | -This guide provides an overview of transferring `SuperchainERC20` tokens between chains. |
| 17 | +This guide shows how to transfer `SuperchainERC20` tokens between chains programmatically. |
17 | 18 |
|
18 | | -## Overview |
| 19 | +Note that this tutorial provides step-by-step instructions for transferring `SuperchainERC20` tokens using code. |
19 | 20 |
|
20 | | -Transferring SuperchainERC20 tokens between chains involves two main phases: |
| 21 | +* For a detailed behind-the-scenes explanation, [see the explainer](/stack/interop/superchain-erc20#how-it-works). |
| 22 | +* For a sample UI that bridges a `SuperchainERC20` token, [see here](https://interop-alpha-app.superchain.tools/). |
21 | 23 |
|
22 | | -1. **Source Chain Operations** |
23 | | - * Mint tokens if needed |
24 | | - * Initiate the transfer using the bridge |
25 | | -2. **Destination Chain Operations** |
26 | | - * Relay the transfer message |
27 | | - * Verify the transfer completion |
| 24 | +## Overview |
28 | 25 |
|
29 | 26 | <Callout type="warning"> |
30 | | - Always verify your addresses and amounts before sending transactions. Cross-chain transfers cannot be reversed. |
| 27 | + Always verify your addresses and amounts before sending transactions. |
| 28 | + Cross-chain transfers cannot be reversed. |
31 | 29 | </Callout> |
32 | 30 |
|
33 | | -## How it works |
34 | | - |
35 | | -This diagram illustrates the process of a SuperchainERC20 token transfer between chains. |
36 | | -Through the `L2ToL2CrossDomainMessenger` contract, tokens are burned on the source chain and a transfer message is emitted. |
37 | | -This message must then be relayed to the destination chain, where an equivalent amount of tokens will be minted to the specified recipient address - ensuring secure cross-chain transfers while maintaining the total token supply across all chains. |
38 | | - |
39 | | -```mermaid |
40 | | -sequenceDiagram |
41 | | - actor User |
42 | | - participant SourceChain |
43 | | - participant Bridge as L2ToL2CrossDomainMessenger |
44 | | - participant DestChain |
45 | | - |
46 | | - Note over User,DestChain: Step 1: Prepare Tokens |
47 | | - User->>SourceChain: Check token balance |
48 | | - alt |
49 | | - User->>SourceChain: Mint or acquire tokens |
50 | | - end |
51 | | - |
52 | | - Note over User,DestChain: Step 2: Initiate Transfer |
53 | | - User->>SourceChain: Approve bridge contract |
54 | | - User->>Bridge: Call sendERC20 |
55 | | - Bridge->>SourceChain: Burn tokens |
56 | | - Bridge-->>Bridge: Emit transfer message |
57 | | - |
58 | | - Note over User,DestChain: Step 3: Complete Transfer |
59 | | - User->>Bridge: Get message details |
60 | | - User->>Bridge: Relay message on destination |
61 | | - Bridge->>DestChain: Mint tokens to recipient |
62 | | - |
63 | | - Note over User,DestChain: Step 4: Verify |
64 | | - User->>DestChain: Check token balance |
65 | | -``` |
| 31 | +### What you'll build |
| 32 | + |
| 33 | +* A TypeScript application to transfer `SuperchainERC20` tokens between chains |
| 34 | + |
| 35 | +### What you'll learn |
| 36 | + |
| 37 | +* How to send `SuperchainERC20` tokens on the blockchain and between blockchains |
| 38 | +* How to relay messages between chains |
| 39 | + |
| 40 | +## Prerequisites |
| 41 | + |
| 42 | +Before starting this tutorial, ensure your development environment meets the following requirements: |
| 43 | + |
| 44 | +### Technical knowledge |
| 45 | + |
| 46 | +* Intermediate TypeScript knowledge |
| 47 | +* Understanding of smart contract development |
| 48 | +* Familiarity with blockchain concepts |
| 49 | + |
| 50 | +### Development environment |
| 51 | + |
| 52 | +* Unix-like operating system (Linux, macOS, or WSL for Windows) |
| 53 | +* Node.js version 16 or higher |
| 54 | +* Git for version control |
| 55 | + |
| 56 | +### Required tools |
| 57 | + |
| 58 | +The tutorial uses these primary tools: |
| 59 | + |
| 60 | +* Foundry: For issuing transactions |
| 61 | +* TypeScript: For implementation |
| 62 | +* Node: For running TypeScript code from the command line |
| 63 | +* Viem: For blockchain interaction |
| 64 | + |
| 65 | +## Directions |
66 | 66 |
|
67 | 67 | <Steps> |
68 | | - ### Prepare your tokens |
| 68 | + ### Preparation |
69 | 69 |
|
70 | | - Ensure you have tokens on the source chain using one of these methods: |
| 70 | + You need onchain `SuperchainERC20` tokens. |
| 71 | + You can [deploy your own token](./deploy-superchain-erc20), but in this tutorial we will use [`CustomSuperchainToken`](https://sid.testnet.routescan.io/address/0xF3Ce0794cB4Ef75A902e07e5D2b75E4D71495ee8), existing `SuperchainERC20` token on the [Interop devnet](/stack/interop/tools/devnet). |
71 | 72 |
|
72 | | - * Use existing tokens you already own |
73 | | - * Mint new tokens using the [SuperchainERC20 contract](https://github.com/ethereum-optimism/supersim/blob/main/contracts/src/L2NativeSuperchainERC20.sol) if you have minting permissions |
74 | | - * Acquire tokens through a supported exchange or transfer |
| 73 | + 1. Create environment variables for the RPC endpoints for the blockchains and the token address. |
75 | 74 |
|
76 | | - ### Initiate the transfer |
| 75 | + ```sh |
| 76 | + RPC_DEV0=https://interop-alpha-0.optimism.io |
| 77 | + RPC_DEV1=https://interop-alpha-1.optimism.io |
| 78 | + TOKEN_ADDRESS=0xF3Ce0794cB4Ef75A902e07e5D2b75E4D71495ee8 |
| 79 | + ``` |
77 | 80 |
|
78 | | - To start the transfer: |
| 81 | + 2. Set `PRIVATE_KEY` to the private key of an address that has [Sepolia ETH](https://cloud.google.com/application/web3/faucet/ethereum/sepolia). |
79 | 82 |
|
80 | | - 1. Choose the destination chain where you want to receive the tokens |
81 | | - 2. Specify the recipient address and the amount to transfer |
82 | | - 3. Call the bridge contract, which will: |
83 | | - * Lock or burn your tokens on the source chain |
84 | | - * Emit a message that will be used to mint tokens on the destination chain |
| 83 | + ```sh |
| 84 | + export PRIVATE_KEY=0x<private key here> |
| 85 | + MY_ADDRESS=`cast wallet address $PRIVATE_KEY` |
| 86 | + ``` |
85 | 87 |
|
86 | | - ### Complete the transfer |
| 88 | + 3. Send ETH to the two L2 blockchains. |
87 | 89 |
|
88 | | - To finalize the transfer on the destination chain: |
| 90 | + ```sh |
| 91 | + cast send --rpc-url https://endpoints.omniatech.io/v1/eth/sepolia/public --private-key $PRIVATE_KEY --value 0.02ether 0x7385d89d38ab79984e7c84fab9ce5e6f4815468a |
| 92 | + cast send --rpc-url https://endpoints.omniatech.io/v1/eth/sepolia/public --private-key $PRIVATE_KEY --value 0.02ether 0x55f5c4653dbcde7d1254f9c690a5d761b315500c |
| 93 | + ``` |
89 | 94 |
|
90 | | - 1. Get the message details from the source chain event |
91 | | - 2. Use the `L2ToL2CrossDomainMessenger` contract to relay the message |
92 | | - 3. The message relay will trigger the minting of tokens on the destination chain |
| 95 | + 4. Wait a few minutes until you can see the ETH [on the block explorer](https://sid.testnet.routescan.io/) for your address. |
93 | 96 |
|
94 | | - <Callout type="info"> |
95 | | - The transfer isn't complete until the message is successfully relayed on the destination chain. See the [technical reference guide](/stack/interop/tutorials/relay-messages-viem) for specific relay instructions. |
96 | | - </Callout> |
| 97 | + <details> |
| 98 | + <summary>Sanity check</summary> |
97 | 99 |
|
98 | | - ### Verify completion |
| 100 | + Check the ETH balance of your address on both blockchains. |
99 | 101 |
|
100 | | - After relaying the message: |
| 102 | + ```sh |
| 103 | + cast balance --ether $MY_ADDRESS --rpc-url $RPC_DEV0 |
| 104 | + cast balance --ether $MY_ADDRESS --rpc-url $RPC_DEV1 |
| 105 | + ``` |
| 106 | + </details> |
101 | 107 |
|
102 | | - 1. Check your token balance on the destination chain |
103 | | - 2. Confirm the transferred amount matches what you sent |
104 | | - 3. The tokens should now be available for use on the destination chain |
105 | | -</Steps> |
| 108 | + 5. Obtain tokens on Interop devnet 0. |
| 109 | + When using `CustomSuperchainToken`, there are two ways to do this: |
| 110 | + |
| 111 | + * Use the [block explorer](https://sid.testnet.routescan.io/address/0xF3Ce0794cB4Ef75A902e07e5D2b75E4D71495ee8/contract/420120000/writeContract?chainid=420120000) and a browser wallet to run the [faucet](https://sid.testnet.routescan.io/address/0xF3Ce0794cB4Ef75A902e07e5D2b75E4D71495ee8/contract/420120000/writeContract?chainid=420120000#F6) function. |
| 112 | + |
| 113 | + * Use `cast` to call the `faucet` function. |
| 114 | + |
| 115 | + ```sh |
| 116 | + cast send --rpc-url $RPC_DEV0 --private-key $PRIVATE_KEY $TOKEN_ADDRESS "faucet()" |
| 117 | + ``` |
| 118 | + |
| 119 | + <details> |
| 120 | + <summary>Sanity check</summary> |
106 | 121 |
|
107 | | -For detailed technical instructions including contract addresses, specific commands, and message relaying details, refer to our [technical reference guide](/stack/interop/tutorials/relay-messages-viem). |
| 122 | + Run this command to check your token balance. |
108 | 123 |
|
109 | | -## Alternative methods |
| 124 | + ```sh |
| 125 | + cast call --rpc-url $RPC_DEV0 $TOKEN_ADDRESS "balanceOf(address)" $MY_ADDRESS | cast --from-wei |
| 126 | + ``` |
| 127 | + </details> |
110 | 128 |
|
111 | | -You can also use: |
| 129 | + ### Transfer tokens using TypeScript |
112 | 130 |
|
113 | | -* [viem bindings/actions](/stack/interop/tutorials/relay-messages-viem) for TypeScript integration |
| 131 | + We are going to use a [Node](https://nodejs.org/en) project, to be able to use [`@eth-optimism/viem`](https://www.npmjs.com/package/@eth-optimism/viem) to send the executing message. |
| 132 | + We use [TypeScript](https://www.typescriptlang.org/) to have [type safety](https://en.wikipedia.org/wiki/Type_safety) combined with JavaScript functionality. |
| 133 | + |
| 134 | + 1. Initialize a new Node project. |
| 135 | + |
| 136 | + ```sh |
| 137 | + mkdir xfer-erc20 |
| 138 | + cd xfer-erc20 |
| 139 | + npm init -y |
| 140 | + npm install --save-dev -y viem tsx @types/node @eth-optimism/viem |
| 141 | + mkdir src |
| 142 | + ``` |
| 143 | + |
| 144 | + 2. Edit `package.json` to add the `start` script. |
| 145 | + |
| 146 | + ```json |
| 147 | + { |
| 148 | + "name": "xfer-erc20", |
| 149 | + "version": "1.0.0", |
| 150 | + "main": "index.js", |
| 151 | + "scripts": { |
| 152 | + "test": "echo \"Error: no test specified\" && exit 1", |
| 153 | + "start": "tsx src/xfer-erc20.mts" |
| 154 | + }, |
| 155 | + "keywords": [], |
| 156 | + "author": "", |
| 157 | + "license": "ISC", |
| 158 | + "type": "module", |
| 159 | + "description": "", |
| 160 | + "devDependencies": { |
| 161 | + "@eth-optimism/viem": "^0.3.2", |
| 162 | + "@types/node": "^22.13.4", |
| 163 | + "tsx": "^4.19.3", |
| 164 | + "viem": "^2.23.3" |
| 165 | + } |
| 166 | + } |
| 167 | + ``` |
| 168 | + |
| 169 | + 3. Create `src/xfer-erc20.mts`: |
| 170 | + |
| 171 | + ```typescript file=<rootDir>/public/tutorials/xfer-erc20.mts hash=19a948eeb482046afb1a55ccc5019599 |
| 172 | + ``` |
| 173 | + |
| 174 | + <details> |
| 175 | + <summary>Explanation of `xfer-erc20.mts`</summary> |
| 176 | + |
| 177 | + ```typescript file=<rootDir>/public/tutorials/xfer-erc20.mts#L79-L84 hash=85f317d0cbe2b59e303e36a3e6154c62 |
| 178 | + ``` |
| 179 | + |
| 180 | + Use `@eth-optimism/viem`'s `walletActionsL2().sendSuperchainERC20` to send the `SuperchainERC20` tokens. |
| 181 | + Internally, this function calls [`SuperchainTokenBridge.sendERC20`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/SuperchainTokenBridge.sol#L52-L78) to send the tokens. |
| 182 | + |
| 183 | + <AutorelayCallout /> |
| 184 | + |
| 185 | + ```typescript file=<rootDir>/public/tutorials/xfer-erc20.mts#L88-L90 hash=cab6e961b558f4f5a7b877062b1cfa45 |
| 186 | + ``` |
| 187 | + |
| 188 | + To relay a message, we need the information in the receipt. |
| 189 | + Also, we need to wait until the transaction with the relayed message is actually part of a block. |
| 190 | + |
| 191 | + ```typescript file=<rootDir>/public/tutorials/xfer-erc20.mts#L92-L94 hash=1da0981adb2fbd38cccf1b0602158418 |
| 192 | + ``` |
| 193 | + |
| 194 | + A single transaction can send multiple messages. |
| 195 | + But here we know we sent just one, so we look for the first one in the list. |
| 196 | + |
| 197 | + ```typescript file=<rootDir>/public/tutorials/xfer-erc20.mts#L96-L99 hash=b5ad9f0c44aee84742cd20c348fdb156 |
| 198 | + ``` |
| 199 | + |
| 200 | + This is how you use `@eth-optimism/viem` to create an executing message. |
| 201 | + </details> |
| 202 | + |
| 203 | + 4. Run the TypeScript program, and see the change in your `CustomSuperchainToken` balances. |
| 204 | + |
| 205 | + ```sh |
| 206 | + npm start |
| 207 | + ``` |
| 208 | +</Steps> |
114 | 209 |
|
115 | 210 | ## Next steps |
116 | 211 |
|
117 | 212 | * Read the [Superchain Interop Explainer](/stack/interop/explainer#faqs) or check out this [Superchain interop design video walk-thru](https://www.youtube.com/watch?v=FKc5RgjtGes). |
| 213 | +* Learn [how this works](/stack/interop/superchain-erc20). |
118 | 214 | * Use [Supersim](/app-developers/tools/supersim), a local dev environment that simulates Superchain interop for testing applications against a local version of the Superchain. |
0 commit comments