Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 67 additions & 53 deletions pages/stack/interop/tutorials/message-passing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,24 @@ For development purposes, we'll first use autorelay mode to handle message execu
<Steps>
### Setting up test networks


<Callout type="warning" emoji="⚠️">
If you attempt to run these steps with the [devnet](../tools/devnet), you *must* Send the executing message yourself, as explained [here](#implement-manual-message-relaying).
</Callout>

1. In the directory where Supersim is installed, start it with autorelay.

```sh
supersim
./supersim --interop.autorelay
```

Supersim creates three `anvil` blockchains:

\| Role | ChainID | RPC URL |
\| -------\* | ------: | ---------------------------------------------\* |
\| L1 | 900 | [http://127.0.0.1:8545](http://127.0.0.1:8545) |
\| OPChainA | 901 | [http://127.0.0.1:9545](http://127.0.0.1:9545) |
\| OPChainB | 902 | [http://127.0.0.1:9546](http://127.0.0.1:9546) |
| Role | ChainID | RPC URL |
| -------- | ------: | --------------------------------------------- |
| L1 | 900 | [http://127.0.0.1:8545](http://127.0.0.1:8545) |
| OPChainA | 901 | [http://127.0.0.1:9545](http://127.0.0.1:9545) |
| OPChainB | 902 | [http://127.0.0.1:9546](http://127.0.0.1:9546) |

2. In a separate shell, store the configuration in environment variables.

Expand Down Expand Up @@ -141,8 +146,8 @@ For development purposes, we'll first use autorelay mode to handle message execu
2. In `src/Greeter.sol` put this file.
This is a variation on [Hardhat's Greeter contract](https://github.com/matter-labs/hardhat-zksync/blob/main/examples/upgradable-example/contracts/Greeter.sol).

```solidity file=<rootDir>/public/tutorials/Greeter.sol#L1-L20 hash=b3c5550bcc2cc4272125388ef23a67e7
```
```solidity file=<rootDir>/public/tutorials/Greeter.sol#L1-L20 hash=b3c5550bcc2cc4272125388ef23a67e7
```

3. Deploy the `Greeter` contract to Chain B and store the resulting contract address in the `GREETER_B_ADDR` environment variable.

Expand Down Expand Up @@ -441,10 +446,10 @@ In production we will not have this, we need to create our own executing message

2. Create or replace `src/app.mts` with this code.

```solidity file=<rootDir>/public/tutorials/app.mts#L1-L51 hash=8f6f776884b8e37ae613f7aea8cd6a3b
```
```typescript file=<rootDir>/public/tutorials/app.mts#L1-L51 hash=8f6f776884b8e37ae613f7aea8cd6a3b
```

3. Run the program, see that a greeting from chain A is related to chain B.
3. Run the program, see that a greeting from chain A is relayed to chain B.

```sh
npm start
Expand Down Expand Up @@ -490,50 +495,50 @@ In production we will not have this, we need to create our own executing message

1. Replace `src/app.mts` with:

```js file=<rootDir>/public/tutorials/app.mts#L1-L51 hash=8f6f776884b8e37ae613f7aea8cd6a3b
```
```typescript file=<rootDir>/public/tutorials/app_v2.mts hash=a7b0f60aa6f1e48fc9994178ed3d5498
```

<details>
<summary>Explanation</summary>
<details>
<summary>Explanation</summary>

1. **Import Required Libraries**
1. **Import Required Libraries**

* Imports functions from `viem` for wallet creation, HTTP transport, and contract interactions.
* Imports `@eth-optimism/viem` utilities for handling OP-Stack-specific actions and interoperability.
* Loads ABI definitions from `Greeter.json` and `GreetingSender.json` for contract interactions.
* Imports functions from `viem` for wallet creation, HTTP transport, and contract interactions.
* Imports `@eth-optimism/viem` utilities for handling OP-Stack-specific actions and interoperability.
* Loads ABI definitions from `Greeter.json` and `GreetingSender.json` for contract interactions.

2. **Initialize Wallet Clients**
2. **Initialize Wallet Clients**

* Uses `privateKeyToAccount` to generate an account from an environment variable.
* Creates `walletA` for chain `supersimL2A` and `walletB` for chain `supersimL2B`, extending them with Viem's public and OP-Stack-specific actions.
* Uses `privateKeyToAccount` to generate an account from an environment variable.
* Creates `walletA` for chain `supersimL2A` and `walletB` for chain `supersimL2B`, extending them with Viem's public and OP-Stack-specific actions.

3. **Get Contract Instances**
3. **Get Contract Instances**

* Retrieves contract instances for `greeter` on `walletB` and `greetingSender` on `walletA` using `getContract`.
* The addresses are taken from environment variables, and the clients are set to the respective wallets.
* Retrieves contract instances for `greeter` on `walletB` and `greetingSender` on `walletA` using `getContract`.
* The addresses are taken from environment variables, and the clients are set to the respective wallets.

4. **Direct Greeting on Chain B**
4. **Direct Greeting on Chain B**

* Calls `setGreeting` on `greeter` to store a greeting directly on chain B.
* Waits for the transaction to be confirmed using `waitForTransactionReceipt`.
* Reads and logs the greeting stored on chain B.
* Calls `setGreeting` on `greeter` to store a greeting directly on chain B.
* Waits for the transaction to be confirmed using `waitForTransactionReceipt`.
* Reads and logs the greeting stored on chain B.

5. **Cross-Chain Greeting via Chain A**
5. **Cross-Chain Greeting via Chain A**

* Calls `setGreeting` on `greetingSender` to send a greeting through chain A.
* Waits for the transaction receipt on chain A.
* Calls `setGreeting` on `greetingSender` to send a greeting through chain A.
* Waits for the transaction receipt on chain A.

6. **Retrieve and Relay the Cross-Chain Message**
6. **Retrieve and Relay the Cross-Chain Message**

* Extracts the message from the transaction receipt using `createInteropSentL2ToL2Messages`.
* Relays the message to chain B using `walletB.interop.relayMessage`.
* Waits for confirmation of the relay transaction.
* Extracts the message from the transaction receipt using `createInteropSentL2ToL2Messages`.
* Relays the message to chain B using `walletB.interop.relayMessage`.
* Waits for confirmation of the relay transaction.

7. **Verify the Updated Greeting on Chain B**
7. **Verify the Updated Greeting on Chain B**

* Reads the greeting from `greeter` after the relay process.
* Logs the updated greeting, showing that it was successfully relayed from chain A to chain B.
</details>
* Reads the greeting from `greeter` after the relay process.
* Logs the updated greeting, showing that it was successfully relayed from chain A to chain B.
</details>

2. Rerun the JavaScript program, and see that the message is relayed.

Expand All @@ -546,29 +551,38 @@ In production we will not have this, we need to create our own executing message
The same contracts are deployed on [the devnet](../tools/devnet).
You can relay messages in exactly the same way you'd do it on Supersim.

\| Contract | Network | Address |
\| ---------------\* | -------------------------------------------\* | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\* |
\| `Greeter` | [Devnet 1](../tools/devnet#interop-devnet-1) | [`0x1A183FCf61053B7dcd2322BbE766f7E1946d3718`](https://sid.testnet.routescan.io/address/0x1A183FCf61053B7dcd2322BbE766f7E1946d3718) |
\| `GreetingSender` | [Devnet 0](../tools/devnet#interop-devnet-1) | [`0x9De9f84a4EB3616B44CF1d68cD1A9098Df6cB25f`](https://sid.testnet.routescan.io/address/0x9De9f84a4EB3616B44CF1d68cD1A9098Df6cB25f/contract/420120000/readContract?chainid=420120000) |
| Contract | Network | Address |
| --------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Greeter` | [Devnet 1](../tools/devnet#interop-devnet-1) | [`0x1A183FCf61053B7dcd2322BbE766f7E1946d3718`](https://sid.testnet.routescan.io/address/0x1A183FCf61053B7dcd2322BbE766f7E1946d3718) |
| `GreetingSender` | [Devnet 0](../tools/devnet#interop-devnet-1) | [`0x9De9f84a4EB3616B44CF1d68cD1A9098Df6cB25f`](https://sid.testnet.routescan.io/address/0x9De9f84a4EB3616B44CF1d68cD1A9098Df6cB25f/contract/420120000/readContract?chainid=420120000) |

To modify the program to relay messagez on devnet, follow these steps:
To modify the program to relay messages on devnet, follow these steps:

1. In `src/app.mts`, replace these lines to update the chains and contract addresses.

\| Line number | New content |
\| ----------: | -------------------------------------------------------------------------\* |
\| 10 | `import { interopAlpha0, interopAlpha1 } from '@eth-optimism/viem/chains'` |
\| 24 | ` chain: interopAlpha0,` |
\| 32 | ` chain: interopAlpha1,` |
\| 40 | ` address: "0x1A183FCf61053B7dcd2322BbE766f7E1946d3718",` |
\| 46 | ` address: "0x9De9f84a4EB3616B44CF1d68cD1A9098Df6cB25f",` |
| Line number | New content |
| ----------: | ------------------------------------------------------------------------- |
| 9 | `import { interopAlpha0, interopAlpha1 } from '@eth-optimism/viem/chains'` |
| 23 | ` chain: interopAlpha0,` |
| 31 | ` chain: interopAlpha1,` |
| 39 | ` address: "0x1A183FCf61053B7dcd2322BbE766f7E1946d3718",` |
| 45 | ` address: "0x9De9f84a4EB3616B44CF1d68cD1A9098Df6cB25f",` |

2. Set `PRIV_KEY` to the private key of an address that has Sepolia ETH on the two chains.
2. Set `PRIV_KEY` to the private key of an address that has [Sepolia ETH](https://cloud.google.com/application/web3/faucet/ethereum/sepolia).

```sh
export PRIV_KEY=0x<private key here>
```

3. Send ETH to the two L2 blockchains.

```sh
cast send --rpc-url https://endpoints.omniatech.io/v1/eth/sepolia/public --private-key $PRIV_KEY --value 0.001ether 0x7385d89d38ab79984e7c84fab9ce5e6f4815468a
cast send --rpc-url https://endpoints.omniatech.io/v1/eth/sepolia/public --private-key $PRIV_KEY --value 0.001ether 0x7385d89d38ab79984e7c84fab9ce5e6f4815468a
```

Wait a few minutes until you can see the ETH [on your explorer](https://sid.testnet.routescan.io/).

3. Rerun the test.

```sh
Expand Down
74 changes: 74 additions & 0 deletions public/tutorials/app_v2.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import {
createWalletClient,
http,
publicActions,
getContract,
Address,
} from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { supersimL2A, supersimL2B } from '@eth-optimism/viem/chains'

import {
walletActionsL2,
publicActionsL2,
createInteropSentL2ToL2Messages,
} from '@eth-optimism/viem'

import greeterData from './Greeter.json'
import greetingSenderData from './GreetingSender.json'

const account = privateKeyToAccount(process.env.PRIV_KEY as `0x${string}`)

const walletA = createWalletClient({
chain: supersimL2A,
transport: http(),
account
}).extend(publicActions)
.extend(publicActionsL2())
.extend(walletActionsL2())

const walletB = createWalletClient({
chain: supersimL2B,
transport: http(),
account
}).extend(publicActions)
.extend(publicActionsL2())
.extend(walletActionsL2())

const greeter = getContract({
address: process.env.GREETER_B_ADDR as Address,
abi: greeterData.abi,
client: walletB
})

const greetingSender = getContract({
address: process.env.GREETER_A_ADDR as Address,
abi: greetingSenderData.abi,
client: walletA
})

const txnBHash = await greeter.write.setGreeting(
["Greeting directly to chain B"])
await walletB.waitForTransactionReceipt({hash: txnBHash})

const greeting1 = await greeter.read.greet()
console.log(`Chain B Greeting: ${greeting1}`)

const txnAHash = await greetingSender.write.setGreeting(
["Greeting through chain A"])
const receiptA = await walletA.waitForTransactionReceipt({hash: txnAHash})

const sentMessage =
(await createInteropSentL2ToL2Messages(walletA, { receipt: receiptA }))
.sentMessages[0]
const relayMsgTxnHash = await walletB.interop.relayMessage({
sentMessageId: sentMessage.id,
sentMessagePayload: sentMessage.payload,
})

const receiptRelay = await walletB.waitForTransactionReceipt(
{hash: relayMsgTxnHash})

const greeting2 = await greeter.read.greet()
console.log(`Chain A Greeting: ${greeting2}`)