Skip to content

Commit c81b7e0

Browse files
committed
updated tutorial
1 parent 936450d commit c81b7e0

File tree

5 files changed

+178
-137
lines changed

5 files changed

+178
-137
lines changed

pages/stack/interop/tutorials.mdx

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import { Card, Cards } from 'nextra/components'
1111
Documentation covering Interop related tutorials.
1212

1313
<Cards>
14+
<Card title="Interop message passing tutorial" href="/stack/interop/tutorials/message-passing" icon={<img src="/img/icons/shapes.svg" />} />
15+
1416
<Card title="Issuing new assets with SuperchainERC20" href="/stack/interop/tutorials/deploy-superchain-erc20" icon={<img src="/img/icons/shapes.svg" />} />
1517

1618
<Card title="Transferring a SuperchainERC20" href="/stack/interop/tutorials/transfer-superchainERC20" icon={<img src="/img/icons/shapes.svg" />} />

pages/stack/interop/tutorials/message-passing.mdx

+77-137
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: Interop message passing tutorial
33
lang: en-US
4-
description: Learn how to pass messages between chains in the Superchain using the L2ToL2CrossDomainMessenger contract.
4+
description: Learn to implement cross-chain communication in the Superchain by building a message passing system using the L2ToL2CrossDomainMessenger contract.
55
---
66

77
import { Callout } from 'nextra/components'
@@ -12,34 +12,82 @@ import { InteropCallout } from '@/components/WipCallout'
1212

1313
# Interop message passing tutorial
1414

15-
<Callout>
16-
This is a step-by-step tutorial.
17-
You can find an explanation of how this works [here](../message-passing).
15+
## Overview
16+
17+
This tutorial demonstrates how to implement cross-chain communication within the Superchain ecosystem. You'll build a complete
18+
message passing system that enables different chains to interact with each other using the `L2ToL2CrossDomainMessenger` contract.
19+
20+
### What You'll Build
21+
* A Greeter contract that stores and updates messages
22+
* A GreetingSender contract that sends cross-chain messages
23+
* A TypeScript application to relay messages between chains
24+
25+
### What you'll learn
1826

19-
[See here](#use-the-eth-optimismviem-library-to-relay-the-message), if you want a working code example.
27+
* How to deploy contracts across different chains
28+
* How to implement cross-chain message passing
29+
* How to handle sender verification across chains
30+
* How to relay messages manually between chains
31+
32+
<Callout>
33+
This tutorial provides step-by-step instructions for implementing cross-chain messaging.
34+
For a conceptual overview,
35+
see the [message passing explainer](../message-passing).
2036
</Callout>
2137

2238
In this tutorial, you will learn how to use the [`L2ToL2CrossDomainMessenger`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol) contract to pass messages between interoperable blockchains.
2339

2440
## Prerequisites
2541

26-
Before starting this tutorial, ensure you have:
42+
Before starting this tutorial, ensure your development environment meets the following requirements:
2743

28-
* Basic knowledge of Solidity and TypeScript
29-
* Experience with smart contract development
44+
### Technical knowledge
45+
46+
* Intermediate Solidity programming
47+
* Basic TypeScript knowledge
48+
* Understanding of smart contract development
3049
* Familiarity with blockchain concepts
31-
* A Unix-like environment (Linux, macOS, or WSL for Windows)
3250

51+
### Development environment
52+
53+
* Unix-like operating system (Linux, macOS, or WSL for Windows)
54+
* Node.js version 16 or higher
55+
* Git for version control
56+
57+
### Required tools
58+
59+
The tutorial uses these primary tools:
60+
* Foundry: For smart contract development
61+
* Supersim: For local blockchain simulation
62+
* TypeScript: For implementation
63+
* Viem: For blockchain interaction
64+
65+
66+
## Setting up your development environment
67+
68+
<Steps>
69+
70+
### Follow the [Installation Guide](/app-developers/tutorials/supersim/getting-started/installation) to install:
71+
* Foundry for smart contract development
72+
* Supersim for local blockchain simulation
3373

34-
## Installing required tools
74+
### Verify your installation:
75+
```sh
76+
forge --version
77+
supersim --version
78+
```
3579

36-
Before starting this tutorial, refer to the [Installation Guide](/app-developers/tutorials/supersim/getting-started/installation) to set up **Foundry** and **Supersim** on your system.
80+
</Steps>
3781

3882
## Implementing onchain message passing (in Solidity)
3983

40-
This section demonstrates how to deploy smart contracts for cross-chain messaging and send messages between them.
41-
For now, we will ignore the need for executing messages by turning on autorelay.
42-
Read more on [how to relay your own messages](#javascript-message-relaying).
84+
The implementation consists of three main components:
85+
86+
1. **Greeter Contract**: Deployed on `Chain B`, receives and stores messages.
87+
2. **GreetingSender Contract**: Deployed on `Chain A`, initiates cross-chain messages.
88+
3. **Message relay system**: Ensures message delivery between chains.
89+
90+
For development purposes, we'll first use autorelay mode to handle message execution automatically. Later sections cover [manual message relaying](#javascript-message-relaying) for production environments.
4391

4492
<Steps>
4593

@@ -48,7 +96,7 @@ Read more on [how to relay your own messages](#javascript-message-relaying).
4896
1. In the directory where Supersim is installed, start it with autorelay.
4997

5098
```sh
51-
./supersim --interop.autorelay
99+
supersim
52100
```
53101

54102
Supersim creates three `anvil` blockchains:
@@ -90,34 +138,13 @@ To verify that the chains are running, check the balance of `$USER_ADDR`.
90138
```sh
91139
mkdir onchain-code
92140
cd onchain-code
93-
forge init
141+
forge init
94142
```
95-
96143
2. In `src/Greeter.sol` put this file.
97144
This is a variation on [Hardhat's Greeter contract](https://github.com/matter-labs/hardhat-zksync/blob/main/examples/upgradable-example/contracts/Greeter.sol).
98145

99-
```solidity
100-
//SPDX-License-Identifier: MIT
101-
pragma solidity ^0.8.0;
102-
103-
contract Greeter {
104-
string greeting;
105-
106-
event SetGreeting(
107-
address indexed sender, // msg.sender
108-
string greeting
109-
);
110-
111-
function greet() public view returns (string memory) {
112-
return greeting;
113-
}
114-
115-
function setGreeting(string memory _greeting) public {
116-
greeting = _greeting;
117-
emit SetGreeting(msg.sender, _greeting);
118-
}
119-
}
120-
```
146+
```solidity file=<rootDir>/public/tutorials/Greeter.sol#L1-L20 hash=b3c5550bcc2cc4272125388ef23a67e7
147+
```
121148

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

@@ -193,60 +220,23 @@ To verify that the chains are running, check the balance of `$USER_ADDR`.
193220

194221
1. Create `src/GreetingSender.sol`.
195222

196-
```solidity
197-
//SPDX-License-Identifier: MIT
198-
pragma solidity ^0.8.0;
199-
200-
import { Predeploys } from "@eth-optimism/contracts-bedrock/src/libraries/Predeploys.sol";
201-
import { IL2ToL2CrossDomainMessenger } from "@eth-optimism/contracts-bedrock/interfaces/L2/IL2ToL2CrossDomainMessenger.sol";
202-
203-
import { Greeter } from "src/Greeter.sol";
204-
205-
contract GreetingSender {
206-
IL2ToL2CrossDomainMessenger public immutable messenger =
207-
IL2ToL2CrossDomainMessenger(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER);
208-
209-
address immutable greeterAddress;
210-
uint256 immutable greeterChainId;
211-
212-
constructor(address _greeterAddress, uint256 _greeterChainId) {
213-
greeterAddress = _greeterAddress;
214-
greeterChainId = _greeterChainId;
215-
}
216-
217-
function setGreeting(string calldata greeting) public {
218-
bytes memory message = abi.encodeCall(
219-
Greeter.setGreeting,
220-
(greeting)
221-
);
222-
messenger.sendMessage(greeterChainId, greeterAddress, message);
223-
}
224-
}
223+
```solidity file=<rootDir>/public/tutorials/GreetingSender.sol#L1-L28 hash=75d197d1e1da112421785c2160f6a55a
225224
```
226225

227226
<details>
228227

229228
<summary>Explanation</summary>
230229

231-
```solidity
232-
function setGreeting(string calldata greeting) public {
233-
bytes memory message = abi.encodeCall(
234-
Greeter.setGreeting,
235-
(greeting)
236-
);
230+
```solidity file=<rootDir>/public/tutorials/GreetingSender.sol#L21-L27 hash=6c27ebcf4916e5aa2325d30f99c65436
237231
```
238232

239-
The message is the [calldata](https://docs.soliditylang.org/en/latest/internals/layout_in_calldata.html) sent to the destination contract.
240-
The easiest way to calldata is the use [`abi.encodeCall`](https://docs.soliditylang.org/en/latest/units-and-global-variables.html#abi-encoding-and-decoding-functions).
241-
242-
243-
```solidity
244-
messenger.sendMessage(greeterChainId, greeterAddress, message);
245-
}
246-
```
233+
This function encodes a call to `setGreeting` and sends it to a contract on another chain.
247234

248-
Actually send the message using [`L2ToL2CrossDomainMessenger.sendMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L128-L154).
235+
* `abi.encodeCall(Greeter.setGreeting, (greeting))` constructs the [calldata](https://docs.soliditylang.org/en/latest/internals/layout_in_calldata.html) by encoding the function selector and parameters.
236+
* The encoded message is then passed to `messenger.sendMessage`, which forwards it to the destination contract (`greeterAddress`) on the specified chain (`greeterChainId`).
237+
This ensures that `setGreeting` is executed remotely with the provided `greeting` value.
249238

239+
250240
</details>
251241

252242
1. Deploy `GreetingSender` to chain A.
@@ -379,7 +369,7 @@ In this section we change `Greeter.sol` to emit a separate event in it receives
379369

380370
</Steps>
381371

382-
## Javascript message relaying
372+
## Implement manual message relaying
383373

384374
So far we relied on `--interop.autorelay` to send the executing messages to chain B.
385375
But we only have it because we're using a development system.
@@ -468,59 +458,9 @@ We use [TypeScript](https://www.typescriptlang.org/) to have type safety combine
468458

469459
1. Create or replace `src/app.mts` with this code.
470460

471-
```typescript
472-
import {
473-
createWalletClient,
474-
http,
475-
defineChain,
476-
publicActions,
477-
getContract,
478-
Address,
479-
} from 'viem'
480-
import { privateKeyToAccount } from 'viem/accounts'
481-
import { supersimL2A, supersimL2B } from '@eth-optimism/viem/chains'
482-
483-
484-
import greeterData from './Greeter.json'
485-
import greetingSenderData from './GreetingSender.json'
486-
487-
const account = privateKeyToAccount(process.env.PRIV_KEY as `0x${string}`)
488-
489-
const walletA = createWalletClient({
490-
chain: supersimL2A,
491-
transport: http(),
492-
account
493-
}).extend(publicActions)
494-
495-
const walletB = createWalletClient({
496-
chain: supersimL2B,
497-
transport: http(),
498-
account
499-
}).extend(publicActions)
500-
501-
const greeter = getContract({
502-
address: process.env.GREETER_B_ADDR as Address,
503-
abi: greeterData.abi,
504-
client: walletB
505-
})
506-
507-
const greetingSender = getContract({
508-
address: process.env.GREETER_A_ADDR as Address,
509-
abi: greetingSenderData.abi,
510-
client: walletA
511-
})
512-
const txnBHash = await greeter.write.setGreeting(["Greeting directly to chain B"])
513-
await walletB.waitForTransactionReceipt({hash: txnBHash})
514-
515-
const greeting1 = await greeter.read.greet()
516-
console.log(`Chain B Greeting: ${greeting1}`)
517-
518-
const txnAHash = await greetingSender.write.setGreeting(["Greeting through chain A"])
519-
await walletA.waitForTransactionReceipt({hash: txnAHash})
461+
```solidity file=<rootDir>/public/tutorials/app.mts#L1-L51 hash=8f6f776884b8e37ae613f7aea8cd6a3b
462+
```
520463

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

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

@@ -564,7 +504,7 @@ Now we need to rerun Supersim *without* autorelay.
564504
Chain A Greeting: Greeting directly to chain B
565505
```
566506

567-
### Use the `@eth-optimism/viem` library to relay the message
507+
### Add manual relaying logic
568508

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

public/tutorials/Greeter.sol

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
contract Greeter {
5+
string greeting;
6+
7+
event SetGreeting(
8+
address indexed sender, // msg.sender
9+
string greeting
10+
);
11+
12+
function greet() public view returns (string memory) {
13+
return greeting;
14+
}
15+
16+
function setGreeting(string memory _greeting) public {
17+
greeting = _greeting;
18+
emit SetGreeting(msg.sender, _greeting);
19+
}
20+
}

public/tutorials/GreetingSender.sol

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
import { Predeploys } from "@eth-optimism/contracts-bedrock/src/libraries/Predeploys.sol";
5+
import { IL2ToL2CrossDomainMessenger } from "@eth-optimism/contracts-bedrock/interfaces/L2/IL2ToL2CrossDomainMessenger.sol";
6+
7+
import { Greeter } from "src/Greeter.sol";
8+
9+
contract GreetingSender {
10+
IL2ToL2CrossDomainMessenger public immutable messenger =
11+
IL2ToL2CrossDomainMessenger(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER);
12+
13+
address immutable greeterAddress;
14+
uint256 immutable greeterChainId;
15+
16+
constructor(address _greeterAddress, uint256 _greeterChainId) {
17+
greeterAddress = _greeterAddress;
18+
greeterChainId = _greeterChainId;
19+
}
20+
21+
function setGreeting(string calldata greeting) public {
22+
bytes memory message = abi.encodeCall(
23+
Greeter.setGreeting,
24+
(greeting)
25+
);
26+
messenger.sendMessage(greeterChainId, greeterAddress, message);
27+
}
28+
}

0 commit comments

Comments
 (0)