From 215f2c099f9d56a5a31246949552dfe6e172b51d Mon Sep 17 00:00:00 2001 From: Hamdi Allam Date: Wed, 9 Oct 2024 17:28:50 -0400 Subject: [PATCH] updated docs (#197) --- docs/src/SUMMARY.md | 2 +- ...manually-relaying-interop-messages-cast.md | 155 +++++-------- docs/src/guides/interop/relay-using-viem.md | 206 +++++++----------- 3 files changed, 137 insertions(+), 226 deletions(-) diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 6d97cb7ff..4f5e77bbe 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -23,8 +23,8 @@ - [Sending deposit transactions](./guides/deposit-transactions.md) - [Interoperability](./guides/interop/README.md) + - [Viem to send and relay interop messages](./guides/interop/relay-using-viem.md) - [Manually relaying interop messages with cast](./guides/interop/manually-relaying-interop-messages-cast.md) - - [Using viem to relay interop messages (TypeScript)](./guides/interop/relay-using-viem.md) - [Writing cross-chain contract using `L2ToL2CrossDomainMessenger`](./guides/interop/writing-contract-using-l2cdm.md) - [Calling a contract on destination chain]() - [Bridging SuperchainWETH]() diff --git a/docs/src/guides/interop/manually-relaying-interop-messages-cast.md b/docs/src/guides/interop/manually-relaying-interop-messages-cast.md index 1be9b6787..b336ad7d5 100644 --- a/docs/src/guides/interop/manually-relaying-interop-messages-cast.md +++ b/docs/src/guides/interop/manually-relaying-interop-messages-cast.md @@ -1,7 +1,7 @@ # Manually relaying interop messages with `cast` and L2ToL2CrossDomainMessenger -This guide describes how to form a [message identifier](https://specs.optimism.io/interop/messaging.html#message-identifier) to execute a message on a destination chain. +This guide describes how to form a [message identifier](https://specs.optimism.io/interop/messaging.html#message-identifier) to relay a [L2ToL2CrossDomainMessenger](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol) cross chain call. We'll perform the SuperchainERC20 interop transfer in [First steps](../../getting-started/first-steps.md#send-an-interoperable-superchainerc20-token-from-chain-901-to-902-l2-to-l2-message-passing) again, this time manually relaying the message without the autorelayer. @@ -20,38 +20,33 @@ We'll perform the SuperchainERC20 interop transfer in [First steps](../../gettin - [8. Check the balance on chain 902](#8-check-the-balance-on-chain-902) - [Alternatives](#alternatives) - - ## Overview ### Contracts used - [L2NativeSuperchainERC20](https://github.com/ethereum-optimism/supersim/blob/main/contracts/src/L2NativeSuperchainERC20.sol) - `0x420beeF000000000000000000000000000000001` -- [CrossL2Inbox](https://github.com/ethereum-optimism/optimism/blob/92ed64e171c6eb9c6a080c626640e8836f0653cc/packages/contracts-bedrock/src/L2/CrossL2Inbox.sol) - - `0x4200000000000000000000000000000000000022` - [L2ToL2CrossDomainMessenger](https://github.com/ethereum-optimism/optimism/blob/92ed64e171c6eb9c6a080c626640e8836f0653cc/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol) - `0x4200000000000000000000000000000000000023` - ### High level steps Sending an interop message using the `L2ToL2CrossDomainMessenger`: -**on source chain** (OPChainA 901) +**On source chain** (OPChainA 901) -1. call the `L2ToL2CrossChainMessenger.sendMessage` - - the `L2NativeSuperchainERC20.sendERC20` contract will call this under the hood -2. get the log identifier and the message payload +1. Invoke `L2NativeSuperchainERC20.sentERC20` to bridge funds + - this leverages `L2ToL2CrossDomainMessenger.sendMessage` to make the cross chain call +2. Retrieve the log identifier and the message payload for the `SentMessage` event. -**on destination chain** (OPChainB 902) +**On destination chain** (OPChainB 902) -3. call `L2ToL2CrossDomainMessenger.relayMessage` - - this calls `L2NativeSuperchainERC20.relayERC20` +3. Relay the message with `L2ToL2CrossDomainMessenger.relayMessage` + - which then calls `L2NativeSuperchainERC20.relayERC20` ### Message identifier A message identifier uniquely identifies a log emitted on a chain. -The sequencer and smart contracts (CrossL2Inbox) use the identifier to perform [invariant checks](https://specs.optimism.io/interop/messaging.html#messaging-invariants) to confirm that the source message is valid. +The sequencer and smart contracts (CrossL2Inbox) use the identifier to perform [invariant checks](https://specs.optimism.io/interop/messaging.html#messaging-invariants) to confirm that the message is valid. ```solidity struct Identifier { @@ -89,104 +84,68 @@ cast send 0x420beeF000000000000000000000000000000001 "sendERC20(address _to, uin ### 4. Get the log emitted by the `L2ToL2CrossDomainMessenger` -The token contract calls the [L2ToL2CrossDomainMessenger](https://github.com/ethereum-optimism/optimism/blob/92ed64e171c6eb9c6a080c626640e8836f0653cc/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol), which emits a message (log) that can be executed on the destination chain. - -```sh -cast logs --address 0x4200000000000000000000000000000000000023 --rpc-url http://127.0.0.1:9545 -``` - -**example result:** +The token contract calls the [L2ToL2CrossDomainMessenger](https://github.com/ethereum-optimism/optimism/blob/92ed64e171c6eb9c6a080c626640e8836f0653cc/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol), which emits a message (log) that can be relayed on the destination chain. ```sh -- address: 0x4200000000000000000000000000000000000023 - blockHash: 0x644e640094d96e379fec06f3dfbb3b03ee54cde15450543a847f61a063977e90 - blockNumber: 10 - data: 0x000000000000000000000000420beef00000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000064d9f50046000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb9226600000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000 - logIndex: 1 - removed: false - topics: [ - 0x382409ac69001e11931a28435afef442cbfd20d9891907e8fa373ba7d351f320 - 0x0000000000000000000000000000000000000000000000000000000000000386 - 0x000000000000000000000000420beef000000000000000000000000000000001 - 0x0000000000000000000000000000000000000000000000000000000000000000 - ] - transactionHash: 0xf6fcec6ae3941e33223cd6a63d0ffaeac1795b65c144db17e6ae7c8d3e2250dc - transactionIndex: 0 -``` - -### 5. Get the block timestamp the log was emitted in - -Since the message identifier requires the block timestamp, fetch the block info to get the timestamp. - -```sh -cast block 0xREPLACE_WITH_CORRECT_BLOCKHASH --rpc-url http://127.0.0.1:9545 -``` - -**example result:** - -```sh -baseFeePerGas 301131671 -difficulty 0 -extraData 0x -gasLimit 30000000 -gasUsed 63173 -hash 0x644e640094d96e379fec06f3dfbb3b03ee54cde15450543a847f61a063977e90 -logsBloom 0x20000000000000020000000000000000000000080000000000000010000000000000000000000000000000000000000010000000000000000008000000000000000000000000000002000008000000000000000000000100000020000000000000000000020000000040000100000800000000000008000000000010000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000010000000000000000000000000040000002000000200000000000000000000000102000000800000000000020000000000000000000000000000000000000000000000000000000001400000000 -miner 0x4200000000000000000000000000000000000011 -mixHash 0x0000000000000000000000000000000000000000000000000000000000000000 -nonce 0x0000000000000000 -number 10 -parentHash 0xac9dc75fdf4ab41e5b90eefb103745eade25c4b98b48dff784df7d6d45c6144a -parentBeaconRoot -transactionsRoot 0x15e50417f6fa12895cb81dcf9db89f486d3a5760db538ebca97337d28c90f12a -receiptsRoot 0x1a3a7571e087a8200fba03d0c19d433c8293d99d7faa55d953c19006333fe75a -sha3Uncles 0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347 -size 731 -stateRoot 0xb436dee5ab769a104f36e4c1ae3d09c79ec07a8741f0b724c06f0ab8264f1cd1 -timestamp 1728428155 (Tue, 8 Oct 2024 22:55:55 +0000) -withdrawalsRoot -totalDifficulty 0 -transactions: [ - 0xf6fcec6ae3941e33223cd6a63d0ffaeac1795b65c144db17e6ae7c8d3e2250dc +$ cast logs --address 0x4200000000000000000000000000000000000023 --rpc-url http://127.0.0.1:9545 + +address: 0x4200000000000000000000000000000000000023 +blockHash: 0x3905831f1b109ce787d180c1ed977ebf0ff1a6334424a0ae8f3731b035e3f708 +blockNumber: 4 +data: 0x000000000000000000000000420beef00000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000064d9f50046000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb9226600000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000 +logIndex: 1 +topics: [ + 0x382409ac69001e11931a28435afef442cbfd20d9891907e8fa373ba7d351f320 + 0x0000000000000000000000000000000000000000000000000000000000000386 + 0x000000000000000000000000420beef000000000000000000000000000000001 + 0x0000000000000000000000000000000000000000000000000000000000000000 ] +... ``` -### 6. Construct message payload +### 5. Retrive the block timestamp the log was emitted in -To construct the message payload we need to concatenate all the log topics and log data. These need to be concatenated as all the topics first in order and then the data: +Since the message identifier requires the block timestamp, fetch the block info to get the timestamp. ```sh -# 0x + topics[0] + topics[1] + topics[2] + topics[3] + data -0x + 382409ac69001e11931a28435afef442cbfd20d9891907e8fa373ba7d351f320 + 0000000000000000000000000000000000000000000000000000000000000386 + 000000000000000000000000420beef000000000000000000000000000000001 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000420beef00000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000064d9f50046000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb9226600000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000 +$ cast block 0xREPLACE_WITH_CORRECT_BLOCKHASH --rpc-url http://127.0.0.1:9545 +... +timestamp 1728507703 +... ``` -### 7. Prepare the identifier +### 6. Prepare the message identifier & payload Now we have all the information needed for the message (log) identifier. | **Parameter** | **Value** | **Note** | |---------------|--------------------------------------------|----------------------------| | origin | 0x4200000000000000000000000000000000000023 | L2ToL2CrossDomainMessenger | -| blocknumber | 10 | from step 4 | +| blocknumber | 4 | from step 4 | | logIndex | 1 | from step 4 | -| timestamp | 1728428155 | from step 5 | +| timestamp | 1728507703 | from step 5 | | chainid | 901 | OPChainA chainID | -### 8. Send the relayMessage transaction +The message payload is the concatenation of the [...topics, data] in order. + +``` +0x + 382409ac69001e11931a28435afef442cbfd20d9891907e8fa373ba7d351f320 + + 0000000000000000000000000000000000000000000000000000000000000386 + + 000000000000000000000000420beef000000000000000000000000000000001 + + 0000000000000000000000000000000000000000000000000000000000000000 + + 000000000000000000000000420beef00000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000064d9f50046000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb9226600000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000 +``` + +Payload: `0x382409ac69001e11931a28435afef442cbfd20d9891907e8fa373ba7d351f3200000000000000000000000000000000000000000000000000000000000000386000000000000000000000000420beef0000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000420beef00000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000064d9f50046000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb9226600000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000` + +### 7. Send the relayMessage transaction -Call `relayMessage` on [L2ToL2CrossDomainMessenger](https://github.com/ethereum-optimism/optimism/blob/a05feb362b5209ab6a200874e9d45244f12240d1/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L149) +Call `relayMessage` on the [L2ToL2CrossDomainMessenger](https://github.com/ethereum-optimism/optimism/blob/92ed64e171c6eb9c6a080c626640e8836f0653cc/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L126) ```solidity // L2ToL2CrossDomainMessenger.sol (truncated for brevity) -interface ICrossL2Inbox { - struct Identifier { - address origin; - uint256 blockNumber; - uint256 logIndex; - uint256 timestamp; - uint256 chainId; - } +contract L2ToL2CrossDomainMessenger { // ... @@ -202,20 +161,18 @@ interface ICrossL2Inbox { **`relayMessage` parameters** -- `ICrossL2Inbox.Identifier calldata _id`: identifier pointing to the log on the source chain - - same as the identifier in step 7. -- `bytes calldata _sentMessage`: calldata to call the contract on the destination chain with. - - message payload from step 6. +- `ICrossL2Inbox.Identifier calldata _id`: identifier pointing to the `SentMessage` log on the source chain +- `bytes memory _sentMessage`: encoding of the log topics & data Below is an example call, but make sure to replace them with the correct values you received in previous steps. ```sh -cast send 0x4200000000000000000000000000000000000023 \ -"relayMessage((address, uint256, uint256, uint256, uint256), bytes)" \ -"(0x4200000000000000000000000000000000000023, 10, 1, 1728428155, 901)" \ -0x382409ac69001e11931a28435afef442cbfd20d9891907e8fa373ba7d351f3200000000000000000000000000000000000000000000000000000000000000386000000000000000000000000420beef0000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000420beef00000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000064d9f50046000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb9226600000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000 \ ---rpc-url http://127.0.0.1:9546 \ ---private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 +$ cast send 0x4200000000000000000000000000000000000023 \ + "relayMessage((address, uint256, uint256, uint256, uint256), bytes)" \ + "(0x4200000000000000000000000000000000000023, 4, 1, 1728507703, 901)" \ + 0x382409ac69001e11931a28435afef442cbfd20d9891907e8fa373ba7d351f3200000000000000000000000000000000000000000000000000000000000000386000000000000000000000000420beef0000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000420beef00000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000064d9f50046000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb9226600000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000 \ + --rpc-url http://127.0.0.1:9546 \ + --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 ``` ### 9. Check the balance on chain 902 @@ -231,4 +188,4 @@ cast balance --erc20 0x420beeF000000000000000000000000000000001 0xf39Fd6e51aad88 This is obviously very tedious to do by hand 😅. Here are some alternatives - use `supersim --interop.autorelay` - this only works on supersim, but relayers for the testnet/prod environment will be available soon! -- [use `viem` bindings/actions](relay-using-viem.md) - if you're using typescript, we have bindings available to make fetching identifiers and relaying messages easier +- [use `viem` bindings/actions](relay-using-viem.md) - if you're using typescript, we have bindings available to make fetching identifiers and relaying messages easy diff --git a/docs/src/guides/interop/relay-using-viem.md b/docs/src/guides/interop/relay-using-viem.md index 6357e9d3d..1c5f8a3ec 100644 --- a/docs/src/guides/interop/relay-using-viem.md +++ b/docs/src/guides/interop/relay-using-viem.md @@ -29,8 +29,7 @@ supersim npm i viem @eth-optimism/viem ``` -### 3. Define chains and constants - +### 3. Imports & Setup ```ts import { http, @@ -42,75 +41,49 @@ import { } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { + contracts, publicActionsL2, walletActionsL2, - extractMessageIdentifierFromLogs, + supersimL2A, + supersimL2B, + createInteropSentL2ToL2Messages, + decodeRelayedL2ToL2Messages, } from "@eth-optimism/viem"; -import { anvil } from "viem/chains"; -// Define constants - L2NativeSuperchainERC20 contract address is the same on every chain -const L2_NATIVE_SUPERCHAINERC20_ADDRESS = - "0x420beeF000000000000000000000000000000001"; +// SuperERC20 is in development so we manually define the address here +const L2_NATIVE_SUPERCHAINERC20_ADDRESS = "0x420beeF000000000000000000000000000000001"; -const L2_TO_L2_CROSS_DOMAIN_MESSENGER_ADDRESS = - "0x4200000000000000000000000000000000000023"; - -// account for 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 -const account = privateKeyToAccount( - "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", -); +// Account for 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 +const account = privateKeyToAccount("0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"); // Define chains -const opChainA = defineChain({ - ...anvil, - id: 901, - name: "OPChainA", - rpcUrls: { - default: { - http: ["http://127.0.0.1:9545"], - }, - }, -}); - -const opChainB = defineChain({ - ...anvil, - id: 902, - name: "OPChainB", - rpcUrls: { - default: { - http: ["http://127.0.0.1:9546"], - }, - }, -}); +// ... left out as we'll use the supersim chain definitions -// Configure op clients +// Configure clients with optimism extension const opChainAClient = createWalletClient({ transport: http(), - chain: opChainA, + chain: supersimL2A, account, -}) - .extend(walletActionsL2()) +}).extend(walletActionsL2()) .extend(publicActionsL2()) .extend(publicActions); const opChainBClient = createWalletClient({ transport: http(), - chain: opChainB, + chain: superismL2B, account, -}) - .extend(walletActionsL2()) +}).extend(walletActionsL2()) .extend(publicActionsL2()) .extend(publicActions); ``` -### 4. Mint and send `L2NativeSuperchainERC20` on source chain - +### 4. Mint and Bridge `L2NativeSuperchainERC20` from source chain ```ts // ####### // OP Chain A // ####### -// 1. Mint 1000 `L2NativeSuperchainERC20` token +// 1. Mint 1000 `L2NativeSuperchainERC20` token on chain A const mintTxHash = await opChainAClient.writeContract({ address: L2_NATIVE_SUPERCHAINERC20_ADDRESS, @@ -121,50 +94,51 @@ const mintTxHash = await opChainAClient.writeContract({ await opChainAClient.waitForTransactionReceipt({ hash: mintTxHash }); -// 2. Initiate sendERC20 tx -console.log("Initiating sendERC20 on OPChainA..."); +// 2. Initiate sendERC20 tx to bridge funds to chain B + +console.log("Initiating sendERC20 on OPChainA to OPChainB..."); const sendERC20TxHash = await opChainAClient.writeContract({ address: L2_NATIVE_SUPERCHAINERC20_ADDRESS, abi: parseAbi([ "function sendERC20(address _to, uint256 _amount, uint256 _chainId)", ]), functionName: "sendERC20", - args: [account.address, 1000n, BigInt(opChainB.id)], + args: [account.address, 1000n, BigInt(supersimL2B.id)], }); -const sendERC20TxReceipt = await opChainAClient.waitForTransactionReceipt({ - hash: sendERC20TxHash, -}); +const sendERC20Receipt = await opChainAClient.waitForTransactionReceipt({ hash: sendERC20TxHash }); -// 3. Grab the message identifier from the logs -const { id: messageIdentifier, payload: l2ToL2CrossDomainMessengerCalldata } = - await extractMessageIdentifierFromLogs(opChainAClient, { - receipt: sendERC20TxReceipt, - }); +// 3. Construct the interoperable log data from the sent message +const { sentMessages } = await createInteropSentL2ToL2Messages(opChainAClient, { receipt: sendERC20Receipt }) +const sentMessage = sentMessages[0] // We only sent 1 message ``` -### 5. Relay the message on the destination chain - +### 5. Relay the sent message on the destination chain ```ts // ########## // OP Chain B // ########## -// 4. Execute the relayERC20 function on OPChainB -console.log("Executing L2 to L2 message on OPChainB..."); -const executeTxHash = await opChainBClient.executeL2ToL2Message({ - id: messageIdentifier, - target: L2_TO_L2_CROSS_DOMAIN_MESSENGER_ADDRESS, - message: l2ToL2CrossDomainMessengerCalldata, -}); +// 4. Relay the sent message -await opChainBClient.waitForTransactionReceipt({ - hash: executeTxHash, +console.log("Relaying message on OPChainB..."); +const relayTxHash = await opChainBClient.relayL2ToL2Message({ + sentMessageId: sentMessage.id, + sentMessagePayload: sentMessage.payload, }); -// 5. Check balance on OPChainB +const relayReceipt = await opChainBClient.waitForTransactionReceipt({ hash: relayTxHash }); + +// 5. Ensure the message was relayed successfully + +const { successfulMessages, failedMessages } = decodeRelayedL2ToL2Messages({ receipt: relayReceipt }); +if (successfulMessages.length != 1) { + throw new Error("failed to relay message!") +} + +// 6. Check balance on OPChainB const balance = await opChainBClient.readContract({ address: L2_NATIVE_SUPERCHAINERC20_ADDRESS, abi: parseAbi(["function balanceOf(address) view returns (uint256)"]), @@ -194,69 +168,46 @@ import { } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { + contracts, publicActionsL2, walletActionsL2, - extractMessageIdentifierFromLogs, + supersimL2A, + supersimL2B, + createInteropSentL2ToL2Messages, + decodeRelayedL2ToL2Messages, } from "@eth-optimism/viem"; -import { anvil } from "viem/chains"; -// Define constants - L2NativeSuperchainERC20 contract address is the same on every chain +// SuperERC20 is in development so we manually define the address here const L2_NATIVE_SUPERCHAINERC20_ADDRESS = "0x420beeF000000000000000000000000000000001"; -const L2_TO_L2_CROSS_DOMAIN_MESSENGER_ADDRESS = - "0x4200000000000000000000000000000000000023"; - // account for 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 -const account = privateKeyToAccount( - "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", -); +const account = privateKeyToAccount("0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"); // Define chains -const opChainA = defineChain({ - ...anvil, - id: 901, - name: "OPChainA", - rpcUrls: { - default: { - http: ["http://127.0.0.1:9545"], - }, - }, -}); - -const opChainB = defineChain({ - ...anvil, - id: 902, - name: "OPChainB", - rpcUrls: { - default: { - http: ["http://127.0.0.1:9546"], - }, - }, -}); +// ... left out as we'll use the supersim chain definitions // Configure op clients const opChainAClient = createWalletClient({ transport: http(), - chain: opChainA, + chain: supersimL2A, account, -}) - .extend(walletActionsL2()) +}).extend(walletActionsL2()) .extend(publicActionsL2()) .extend(publicActions); const opChainBClient = createWalletClient({ transport: http(), - chain: opChainB, + chain: supersimL2B, account, -}) - .extend(walletActionsL2()) +}).extend(walletActionsL2()) .extend(publicActionsL2()) .extend(publicActions); // ####### // OP Chain A // ####### + // 1. Mint 1000 `L2NativeSuperchainERC20` token const mintTxHash = await opChainAClient.writeContract({ @@ -268,7 +219,8 @@ const mintTxHash = await opChainAClient.writeContract({ await opChainAClient.waitForTransactionReceipt({ hash: mintTxHash }); -// 2. Initiate sendERC20 tx +// 2. Initiate sendERC20 tx to bridge funds to chain B + console.log("Initiating sendERC20 on OPChainA..."); const sendERC20TxHash = await opChainAClient.writeContract({ address: L2_NATIVE_SUPERCHAINERC20_ADDRESS, @@ -276,35 +228,38 @@ const sendERC20TxHash = await opChainAClient.writeContract({ "function sendERC20(address _to, uint256 _amount, uint256 _chainId)", ]), functionName: "sendERC20", - args: [account.address, 1000n, BigInt(opChainB.id)], + args: [account.address, 1000n, BigInt(supersimL2B.id)], }); -const sendERC20TxReceipt = await opChainAClient.waitForTransactionReceipt({ - hash: sendERC20TxHash, -}); +const sendERC20Receipt = await opChainAClient.waitForTransactionReceipt({ hash: sendERC20TxHash }); -// 3. Grab the message identifier from the logs -const { id: messageIdentifier, payload: l2ToL2CrossDomainMessengerCalldata } = - await extractMessageIdentifierFromLogs(opChainAClient, { - receipt: sendERC20TxReceipt, - }); +// 3. Construct the interoperable log data from the sent message + +const { sentMessages } = await createInteropSentL2ToL2Messages(opChainAClient, { receipt: sendERC20Receipt }) +const sentMessage = sentMessages[0] // We only sent 1 message // ########## // OP Chain B // ########## -// 4. Execute the relayERC20 function on OPChainB -console.log("Executing L2 to L2 message on OPChainB..."); -const executeTxHash = await opChainBClient.executeL2ToL2Message({ - id: messageIdentifier, - target: L2_TO_L2_CROSS_DOMAIN_MESSENGER_ADDRESS, - message: l2ToL2CrossDomainMessengerCalldata, -}); -await opChainBClient.waitForTransactionReceipt({ - hash: executeTxHash, +// 4. Relay the sent message + +console.log("Relaying message on OPChainB..."); +const relayTxHash = await opChainBClient.relayL2ToL2Message({ + sentMessageId: sentMessage.id, + sentMessagePayload: sentMessage.payload, }); -// 5. Check balance on OPChainB +const relayReceipt = await opChainBClient.waitForTransactionReceipt({ hash: relayTxHash }); + +// 5. Ensure the message was relayed successfully + +const { successfulMessages, failedMessages } = decodeRelayedL2ToL2Messages({ receipt: relayReceipt }); +if (successfulMessages.length != 1) { + throw new Error("failed to relay message!") +} + +// 6. Check balance on OPChainB const balance = await opChainBClient.readContract({ address: L2_NATIVE_SUPERCHAINERC20_ADDRESS, abi: parseAbi(["function balanceOf(address) view returns (uint256)"]), @@ -313,5 +268,4 @@ const balance = await opChainBClient.readContract({ }); console.log(`Balance on OPChainB: ${balance}`); - -``` \ No newline at end of file +```