diff --git a/pages/interop/tutorials/_meta.json b/pages/interop/tutorials/_meta.json
index a5567d2fa..1b6e893cf 100644
--- a/pages/interop/tutorials/_meta.json
+++ b/pages/interop/tutorials/_meta.json
@@ -4,8 +4,6 @@
"transfer-superchainERC20": "Transferring a SuperchainERC20",
"custom-superchain-erc20": "Custom SuperchainERC20 tokens",
"bridge-crosschain-eth": "Bridging native cross-chain ETH transfers",
- "relay-messages-cast": "Relaying interop messages using `cast`",
- "relay-messages-viem": "Relaying interop messages using `viem`",
"contract-calls": "Making crosschain contract calls (ping pong)",
"event-reads": "Making crosschain event reads (tic-tac-toe)",
"event-contests": "Deploying crosschain event composability (contests)",
diff --git a/pages/interop/tutorials/message-passing.mdx b/pages/interop/tutorials/message-passing.mdx
index 5214c4597..128cdfeb9 100644
--- a/pages/interop/tutorials/message-passing.mdx
+++ b/pages/interop/tutorials/message-passing.mdx
@@ -22,10 +22,8 @@ categories:
is_imported_content: 'false'
---
-import { Callout } from 'nextra/components'
-import { Steps } from 'nextra/components'
+import { Callout, Steps, Tabs } from 'nextra/components'
import { InteropCallout } from '@/components/WipCallout'
-import { AutorelayCallout } from '@/components/AutorelayCallout'
@@ -36,66 +34,66 @@ import { AutorelayCallout } from '@/components/AutorelayCallout'
This tutorial demonstrates how to implement cross-chain communication within the Superchain ecosystem. You'll build a complete
message passing system that enables different chains to interact with each other using the `L2ToL2CrossDomainMessenger` contract.
-### What You'll Build
-
-* A Greeter contract that stores and updates messages
-* A GreetingSender contract that sends cross-chain messages
-* A TypeScript application to relay messages between chains
+
+ About this tutorial
-### What you'll learn
+ **Prerequisite technical knowledge**
-* How to deploy contracts across different chains
-* How to implement cross-chain message passing
-* How to handle sender verification across chains
-* How to relay messages manually between chains
+ * Intermediate Solidity programming
+ * Basic TypeScript knowledge
+ * Understanding of smart contract development
+ * Familiarity with blockchain concepts
-
- This tutorial provides step-by-step instructions for implementing cross-chain messaging.
- For a conceptual overview,
- see the [message passing explainer](/interop/message-passing).
-
+ **What you'll learn**
-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.
+ * How to deploy contracts across different chains
+ * How to implement cross-chain message passing
+ * How to handle sender verification across chains
+ * How to relay messages manually between chains
-## Prerequisites
+ **Development environment**
-Before starting this tutorial, ensure your development environment meets the following requirements:
+ * Unix-like operating system (Linux, macOS, or WSL for Windows)
+ * Node.js version 16 or higher
+ * Git for version control
-### Technical knowledge
+ **Required tools**
-* Intermediate Solidity programming
-* Basic TypeScript knowledge
-* Understanding of smart contract development
-* Familiarity with blockchain concepts
+ The tutorial uses these primary tools:
-### Development environment
+ * Foundry: For smart contract development
+ * Supersim: For local blockchain simulation (optional)
+ * TypeScript: For offchain code (for relaying messages manually)
+ * Viem: For interactions with the chain from the offchain app
+
-* Unix-like operating system (Linux, macOS, or WSL for Windows)
-* Node.js version 16 or higher
-* Git for version control
+### What You'll Build
-### Required tools
+* A `Greeter` contract that stores and updates a greeting
+* A `GreetingSender` contract that sends cross-chain messages to update the greeting
+* A TypeScript application to relay messages between chains
-The tutorial uses these primary tools:
+
+ This tutorial provides step-by-step instructions for implementing cross-chain messaging.
+ For a conceptual overview,
+ see the [Message Passing Explainer](/interop/message-passing).
+
-* Foundry: For smart contract development
-* Supersim: For local blockchain simulation
-* TypeScript: For implementation
-* Viem: For blockchain interaction
+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.
## Setting up your development environment
### Follow the [Installation Guide](/app-developers/tutorials/supersim/getting-started/installation) to install:
- * Foundry for smart contract development
- * Supersim for local blockchain simulation
+ * Foundry for smart contract development (required in all cases)
+ * Supersim for local blockchain simulation (optional)
### Verify your installation:
```sh
forge --version
- supersim --version
+ ./supersim --version
```
@@ -105,50 +103,75 @@ The implementation consists of three main components:
1. **Greeter Contract**: Deployed on `Chain B`, receives and stores messages.
2. **GreetingSender Contract**: Deployed on `Chain A`, initiates cross-chain messages.
-3. **Message relay system**: Ensures message delivery between chains.
-
-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.
### Setting up test networks
-
- If you attempt to run these steps with the [devnet](/interop/tools/devnet), you *must* Send the executing message yourself, as explained [here](#implement-manual-message-relaying).
-
-
- 1. In the directory where Supersim is installed, start it with autorelay.
+ 1. If you are using [Supersim](/interop/tools/supersim), go to the directory where Supersim is installed and start it with autorelay.
```sh
./supersim --interop.autorelay
```
- Supersim creates three `anvil` blockchains:
+ If you are using [the devnets](/interop/tools/devnet), just skip this step.
+
+
+
+ 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) |
+
+
+
+ These are the three networks involved in the devnet:
- | 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 (Sepolia) | 11155111 | [https://eth-sepolia.public.blastapi.io](https://eth-sepolia.public.blastapi.io) |
+ | ChainA | 420120000 | [https://interop-alpha-0.optimism.io](https://interop-alpha-0.optimism.io) |
+ | ChainB | 420120001 | [https://interop-alpha-1.optimism.io](https://interop-alpha-1.optimism.io) |
+
+
2. In a separate shell, store the configuration in environment variables.
- ```sh
- USER_ADDR=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
- PRIV_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
- RPC_L1=http://localhost:8545
- RPC_A=http://localhost:9545
- RPC_B=http://localhost:9546
- ```
+
+
+ Set these parameters for Supersim.
+
+ ```sh
+ PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
+ USER_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
+ URL_CHAIN_A=http://127.0.0.1:9545
+ URL_CHAIN_B=http://127.0.0.1:9546
+ INTEROP_BRIDGE=0x4200000000000000000000000000000000000028
+ ```
+
+
+
+ For Devnet, specify in `PRIVATE_KEY` the private key you used for the setup script and then these parameters.
+
+ ```sh
+ USER_ADDRESS=`cast wallet address --private-key $PRIVATE_KEY`
+ URL_CHAIN_A=https://interop-alpha-0.optimism.io
+ URL_CHAIN_B=https://interop-alpha-1.optimism.io
+ INTEROP_BRIDGE=0x4200000000000000000000000000000000000028
+ ```
+
+
Sanity check
- To verify that the chains are running, check the balance of `$USER_ADDR`.
+ To verify that the chains are running, check the balance of `$USER_ADDRESS`.
```sh
- cast balance --ether $USER_ADDR --rpc-url $RPC_L1
- cast balance --ether $USER_ADDR --rpc-url $RPC_A
- cast balance --ether $USER_ADDR --rpc-url $RPC_B
+ cast balance --ether $USER_ADDRESS --rpc-url $URL_CHAIN_A
+ cast balance --ether $USER_ADDRESS --rpc-url $URL_CHAIN_B
```
@@ -168,42 +191,42 @@ For development purposes, we'll first use autorelay mode to handle message execu
```solidity file=/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.
+ 3. Deploy the `Greeter` contract to Chain B and store the resulting contract address in the `GREETER_B_ADDRESS` environment variable.
```sh
- GREETER_B_ADDR=`forge create --rpc-url $RPC_B --private-key $PRIV_KEY Greeter --broadcast | awk '/Deployed to:/ {print $3}'`
+ GREETER_B_ADDRESS=`forge create --rpc-url $URL_CHAIN_B --private-key $PRIVATE_KEY Greeter --broadcast | awk '/Deployed to:/ {print $3}'`
```
-
- Explanation
+
+ Explanation
- The command that deploys the contract is:
+ The command that deploys the contract is:
- ```sh
- forge create --rpc-url $RPC_B --private-key $PRIV_KEY Greeter --broadcast
- ```
+ ```sh
+ forge create --rpc-url $URL_CHAIN_B --private-key $PRIVATE_KEY Greeter --broadcast
+ ```
- The command output gives us the deployer address, the address of the new contract, and the transaction hash:
+ The command output gives us the deployer address, the address of the new contract, and the transaction hash:
- ```
- Deployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
- Deployed to: 0x5FC8d32690cc91D4c39d9d3abcBD16989F875707
- Transaction hash: 0xf155d360ec70ee10fe0e02d99c16fa5d6dc2a0e79b005fec6cbf7925ff547dbf
- ```
+ ```
+ Deployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
+ Deployed to: 0x5FC8d32690cc91D4c39d9d3abcBD16989F875707
+ Transaction hash: 0xf155d360ec70ee10fe0e02d99c16fa5d6dc2a0e79b005fec6cbf7925ff547dbf
+ ```
- The [`awk`](https://www.tutorialspoint.com/awk/index.htm) command looks for the line that has `Deployed to:` and writes the third word in that line, which is the address.
+ The [`awk`](https://www.tutorialspoint.com/awk/index.htm) command looks for the line that has `Deployed to:` and writes the third word in that line, which is the address.
- ```sh
- awk '/Deployed to:/ {print $3}'
- ```
+ ```sh
+ awk '/Deployed to:/ {print $3}'
+ ```
- Finally, in UNIX (including Linux and macOS) the when the command line includes backticks (\`\`\`), the shell executes the code between the backticks and puts the output, in this case the contract address, in the command.
- So we get.
+ Finally, in UNIX (including Linux and macOS) the when the command line includes backticks (\`\`\`), the shell executes the code between the backticks and puts the output, in this case the contract address, in the command.
+ So we get.
- ```sh
- GREETER_B_ADDR=
- ```
-
+ ```sh
+ GREETER_B_ADDRESS=
+ ```
+
Sanity check
@@ -212,9 +235,9 @@ For development purposes, we'll first use autorelay mode to handle message execu
The first and third commands retrieve the current greeting, while the second command updates it.
```sh
- cast call --rpc-url $RPC_B $GREETER_B_ADDR "greet()" | cast --to-ascii
- cast send --private-key $PRIV_KEY --rpc-url $RPC_B $GREETER_B_ADDR "setGreeting(string)" Hello
- cast call --rpc-url $RPC_B $GREETER_B_ADDR "greet()" | cast --to-ascii
+ cast call --rpc-url $URL_CHAIN_B $GREETER_B_ADDRESS "greet()" | cast --to-ascii
+ cast send --private-key $PRIVATE_KEY --rpc-url $URL_CHAIN_B $GREETER_B_ADDRESS "setGreeting(string)" Hello$$
+ cast call --rpc-url $URL_CHAIN_B $GREETER_B_ADDRESS "greet()" | cast --to-ascii
```
@@ -227,37 +250,29 @@ For development purposes, we'll first use autorelay mode to handle message execu
echo @eth-optimism/=lib/node_modules/@eth-optimism/ >> remappings.txt
```
- 5. The [`@eth-optimism/contracts-bedrock`](https://www.npmjs.com/package/@eth-optimism/contracts-bedrock) library does not have the Interop Solidity code yet.
- Run these commands to add it.
-
- ```sh
- mkdir -p lib/node_modules/@eth-optimism/contracts-bedrock/interfaces/L2
- wget https://raw.githubusercontent.com/ethereum-optimism/optimism/refs/heads/develop/packages/contracts-bedrock/interfaces/L2/IL2ToL2CrossDomainMessenger.sol
- mv IL2ToL2CrossDomainMessenger.sol lib/node_modules/@eth-optimism/contracts-bedrock/interfaces/L2
- ```
-
- 6. Create `src/GreetingSender.sol`.
+ 5. Create `src/GreetingSender.sol`.
- ```solidity file=/public/tutorials/GreetingSender.sol#L1-L28 hash=9ed77001810caf52bbaa94da8b0dc5c6
+ ```solidity file=/public/tutorials/GreetingSender.sol hash=bc4d79b54b5d6a007264f9972818f56a
```
-
- Explanation
+
+ Explanation
- ```solidity file=/public/tutorials/GreetingSender.sol#L21-L27 hash=6c27ebcf4916e5aa2325d30f99c65436
- ```
+ ```solidity file=/public/tutorials/GreetingSender.sol#L21-L27 hash=6c27ebcf4916e5aa2325d30f99c65436
+ ```
- This function encodes a call to `setGreeting` and sends it to a contract on another chain.
- `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.
- The encoded message is then passed to `messenger.sendMessage`, which forwards it to the destination contract (`greeterAddress`) on the specified chain (`greeterChainId`).
+ This function encodes a call to `setGreeting` and sends it to a contract on another chain.
+ `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.
+ The encoded message is then passed to `messenger.sendMessage`, which forwards it to the destination contract (`greeterAddress`) on the specified chain (`greeterChainId`).
- This ensures that `setGreeting` is executed remotely with the provided `greeting` value (as long as there is an executing message to relay it).
-
+ This ensures that `setGreeting` is executed remotely with the provided `greeting` value (as long as there is an executing message to relay it).
+
7. Deploy `GreetingSender` to chain A.
```sh
- GREETER_A_ADDR=`forge create --rpc-url $RPC_A --private-key $PRIV_KEY --broadcast GreetingSender --constructor-args $GREETER_B_ADDR 902 | awk '/Deployed to:/ {print $3}'`
+ CHAIN_ID_B=`cast chain-id --rpc-url $URL_CHAIN_B`
+ GREETER_A_ADDRESS=`forge create --rpc-url $URL_CHAIN_A --private-key $PRIVATE_KEY --broadcast GreetingSender --constructor-args $GREETER_B_ADDRESS $CHAIN_ID_B | awk '/Deployed to:/ {print $3}'`
```
### Send a message
@@ -265,13 +280,13 @@ For development purposes, we'll first use autorelay mode to handle message execu
Send a greeting from chain A to chain B.
```sh
- cast call --rpc-url $RPC_B $GREETER_B_ADDR "greet()" | cast --to-ascii
- cast send --private-key $PRIV_KEY --rpc-url $RPC_A $GREETER_A_ADDR "setGreeting(string)" "Hello from chain A"
- sleep 2
- cast call --rpc-url $RPC_B $GREETER_B_ADDR "greet()" | cast --to-ascii
+ cast call --rpc-url $URL_CHAIN_B $GREETER_B_ADDRESS "greet()" | cast --to-ascii
+ cast send --private-key $PRIVATE_KEY --rpc-url $URL_CHAIN_A $GREETER_A_ADDRESS "setGreeting(string)" "Hello from chain A"
+ sleep 4
+ cast call --rpc-url $URL_CHAIN_B $GREETER_B_ADDRESS "greet()" | cast --to-ascii
```
- The `sleep` call is because the message is not relayed until the next chain B block, which can take up to two seconds.
+ The `sleep` call is because it can take up to two seconds until the transaction is included in chain A, and then up to two seconds until the relay transaction is included in chain B.
## Sender information
@@ -279,7 +294,7 @@ For development purposes, we'll first use autorelay mode to handle message execu
Run this command to view the events to see who called `setGreeting`.
```sh
-cast logs --rpc-url $RPC_B 'SetGreeting(address,string)'
+cast logs --rpc-url $URL_CHAIN_B 'SetGreeting(address,string)'
```
The sender information is stored in the second event topic.
@@ -297,7 +312,10 @@ In this section we change `Greeter.sol` to emit a separate event in it receives
pragma solidity ^0.8.0;
import { Predeploys } from "@eth-optimism/contracts-bedrock/src/libraries/Predeploys.sol";
- import { IL2ToL2CrossDomainMessenger } from "@eth-optimism/contracts-bedrock/interfaces/L2/IL2ToL2CrossDomainMessenger.sol";
+
+ interface IL2ToL2CrossDomainMessenger {
+ function crossDomainMessageContext() external view returns (address sender_, uint256 source_);
+ }
contract Greeter {
@@ -334,26 +352,34 @@ In this section we change `Greeter.sol` to emit a separate event in it receives
}
```
-
- Explanation
-
- ```solidity
- if (msg.sender == Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER) {
- (address sender, uint256 chainId) =
- messenger.crossDomainMessageContext();
- emit CrossDomainSetGreeting(sender, chainId, _greeting);
- }
- ```
+
+ Explanation
- If we see that we got a message from `L2ToL2CrossDomainMessenger`, we call [`L2ToL2CrossDomainMessenger.crossDomainMessageContext`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L118-L126).
-
+ ```solidity
+ interface IL2ToL2CrossDomainMessenger {
+ function crossDomainMessageContext() external view returns (address sender_, uint256 source_);
+ }
+ ```
+
+ This definition isn't part of the [npmjs package](https://www.npmjs.com/package/@eth-optimism/contracts-bedrock) at writing, so we just add it here.
+
+ ```solidity
+ if (msg.sender == Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER) {
+ (address sender, uint256 chainId) =
+ messenger.crossDomainMessageContext();
+ emit CrossDomainSetGreeting(sender, chainId, _greeting);
+ }
+ ```
+
+ If we see that we got a message from `L2ToL2CrossDomainMessenger`, we call [`L2ToL2CrossDomainMessenger.crossDomainMessageContext`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L118-L126).
+
2. Redeploy the contracts.
Because the address of `Greeter` is immutable in `GreetingSender`, we need to redeploy both contracts.
```sh
- GREETER_B_ADDR=`forge create --rpc-url $RPC_B --private-key $PRIV_KEY Greeter --broadcast | awk '/Deployed to:/ {print $3}'`
- GREETER_A_ADDR=`forge create --rpc-url $RPC_A --private-key $PRIV_KEY --broadcast GreetingSender --constructor-args $GREETER_B_ADDR 902 | awk '/Deployed to:/ {print $3}'`
+ GREETER_B_ADDRESS=`forge create --rpc-url $URL_CHAIN_B --private-key $PRIVATE_KEY Greeter --broadcast | awk '/Deployed to:/ {print $3}'`
+ GREETER_A_ADDRESS=`forge create --rpc-url $URL_CHAIN_A --private-key $PRIVATE_KEY --broadcast GreetingSender --constructor-args $GREETER_B_ADDRESS $CHAIN_ID_B | awk '/Deployed to:/ {print $3}'`
```
### Verify you can see cross chain sender information
@@ -361,259 +387,25 @@ In this section we change `Greeter.sol` to emit a separate event in it receives
1. Set the greeting through `GreetingSender`.
```sh
- cast call --rpc-url $RPC_B $GREETER_B_ADDR "greet()" | cast --to-ascii
- cast send --private-key $PRIV_KEY --rpc-url $RPC_A $GREETER_A_ADDR "setGreeting(string)" "Hello from chain A, with a CrossDomainSetGreeting event"
- sleep 2
- cast call --rpc-url $RPC_B $GREETER_B_ADDR "greet()" | cast --to-ascii
+ cast call --rpc-url $URL_CHAIN_B $GREETER_B_ADDRESS "greet()" | cast --to-ascii
+ cast send --private-key $PRIVATE_KEY --rpc-url $URL_CHAIN_A $GREETER_A_ADDRESS "setGreeting(string)" "Hello from chain A, with a CrossDomainSetGreeting event"
+ sleep 4
+ cast call --rpc-url $URL_CHAIN_B $GREETER_B_ADDRESS "greet()" | cast --to-ascii
```
2. Read the log entries.
```sh
- cast logs --rpc-url $RPC_B 'CrossDomainSetGreeting(address,uint256,string)'
- echo $GREETER_A_ADDR
- echo 0x385 | cast --to-dec
+ cast logs --rpc-url $URL_CHAIN_B 'CrossDomainSetGreeting(address,uint256,string)'
+ echo $GREETER_A_ADDRESS
+ echo 0x385=`echo 0x385 | cast --to-dec`
+ echo 0x190a85c0=`echo 0x190a85c0 | cast --to-dec`
```
- See that the second topic (the first indexed log parameter) is the same as `$GREETER_A_ADDR`.
- The third topic is `0x385=901`, which is the chain ID for chain A.
+ See that the second topic (the first indexed log parameter) is the same as `$GREETER_A_ADDRESS`.
+ The third topic can be either `0x385=901`, which is the chain ID for supersim chain A, or `0x190a85c0=420120000`, which is the chain ID for devnet alpha 0.
-## Implement manual message relaying
-
-
-
-
- ### Set up
-
- We are going to use a [Node](https://nodejs.org/en) project, to be able to get executing messages from the command line.
- We use [TypeScript](https://www.typescriptlang.org/) to have type safety combined with JavaScript functionality.
-
- 1. Initialize a new Node project.
-
- ```sh
- mkdir ../offchain-code
- cd ../offchain-code
- npm init -y
- npm install --save-dev -y viem tsx @types/node @eth-optimism/viem
- mkdir src
- ```
-
- 2. Edit `package.json` to add the `start` script.
-
- ```json
- {
- "name": "offchain-code",
- "version": "1.0.0",
- "main": "index.js",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1",
- "start": "tsx src/app.mts"
- },
- "keywords": [],
- "author": "",
- "license": "ISC",
- "type": "commonjs",
- "description": "",
- "devDependencies": {
- "@eth-optimism/viem": "^0.3.2",
- "@types/node": "^22.13.1",
- "tsx": "^4.19.2",
- "viem": "^2.22.23"
- }
- }
- ```
-
- 3. Export environment variables.
- This is necessary because those variables are currently limited to the shell process.
- We need them in the Node process that the shell creates.
-
- ```sh
- export GREETER_A_ADDR GREETER_B_ADDR PRIV_KEY
- ```
-
-
- Sanity check
-
- 1. Create a simple `src/app.mts` file.
-
- ```typescript
- console.log(`Greeter A ${process.env.GREETER_A_ADDR}`)
- console.log(`Greeter B ${process.env.GREETER_B_ADDR}`)
- ```
-
- 2. Run the program.
-
- ```sh
- npm run start
- ```
-
-
- ### Send a greeting
-
- 1. Link the compiled versions of the onchain code, which include the ABI, to the source code.
-
- ```sh
- cd src
- ln -s ../../onchain-code/out/Greeter.sol/Greeter.json .
- ln -s ../../onchain-code/out/GreetingSender.sol/GreetingSender.json .
- cd ..
- ```
-
- 2. Create or replace `src/app.mts` with this code.
-
- ```typescript file=/public/tutorials/app.mts#L1-L51 hash=8f6f776884b8e37ae613f7aea8cd6a3b
- ```
-
- 3. Run the program, see that a greeting from chain A is relayed to chain B.
-
- ```sh
- npm start
- ```
-
- ### Rerun supersim
-
- Now we need to rerun Supersim *without* autorelay.
-
- 1. In the window that runs Supersim, stop it and restart with this command:
-
- ```sh
- ./supersim
- ```
-
- 2. In the window you used for your earlier tests, redeploy the contracts.
- Export the addresses so we'll have them in JavaScript
-
- ```sh
- cd ../onchain-code
- export GREETER_B_ADDR=`forge create --rpc-url $RPC_B --private-key $PRIV_KEY Greeter --broadcast | awk '/Deployed to:/ {print $3}'`
- export GREETER_A_ADDR=`forge create --rpc-url $RPC_A --private-key $PRIV_KEY --broadcast GreetingSender --constructor-args $GREETER_B_ADDR 902 | awk '/Deployed to:/ {print $3}'`
- cd ../offchain-code
- ```
-
- 3. Rerun the JavaScript program.
-
- ```sh
- npm start
- ```
-
- See that the transaction to chain B changes the greeting, but the transaction to chain A does not.
-
- ```
- > offchain-code@1.0.0 start
- > tsx src/app.mts
-
- Chain B Greeting: Greeting directly to chain B
- Chain A Greeting: Greeting directly to chain B
- ```
-
- ### Add manual relaying logic
-
- 1. Replace `src/app.mts` with:
-
- ```typescript file=/public/tutorials/app_v2.mts hash=f0aef31ef2ce29590a37f18ca07e52a9
- ```
-
-
- Explanation
-
- ```typescript file=/public/tutorials/app_v2.mts#L11-L15 hash=84fb4799b2fdd18785f691d602567145
- ```
-
- Import from the [`@eth-optimism/viem`](https://www.npmjs.com/package/@eth-optimism/viem) package.
-
- ```typescript file=/public/tutorials/app_v2.mts#L22-L28 hash=28c42407a1a01774f25ca78535d93c6e
- ```
-
- In addition to extending the wallets with [Viem public actions](https://viem.sh/docs/accounts/local#5-optional-extend-with-public-actions), extend with the OP-Stack actions, both the public ones and the ones that require an account.
-
- ```typescript file=/public/tutorials/app_v2.mts#L59 hash=fc1aae397872717a3ed364930cdab9fc
- ```
-
- To relay a message we need the information in the receipt.
- Also, we need to wait until the transaction with the relayed message is actually part of a block.
-
- ```typescript file=/public/tutorials/app_v2.mts#L61-L63 hash=d45ebbc0d53dfbecbd8d357eb83e1b68
- ```
-
- A single transaction can send multiple messages.
- But here we know we sent just one, so we look for the first one in the list.
-
- ```typescript file=/public/tutorials/app_v2.mts#L64-L70 hash=079ffd3e6fdf4eff3653ee7a74078183
- ```
-
- Here we first send the relay message on chain B, and then wait for the receipt for it.
-
-
- 2. Rerun the JavaScript program, and see that the message is relayed.
-
- ```sh
- npm start
- ```
-
- ### Using devnet
-
- The same contracts are deployed on [the devnet](/interop/tools/devnet).
- You can relay messages in exactly the same way you'd do it on Supersim.
-
- | Contract | Network | Address |
- | ---------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
- | `Greeter` | [Devnet 1](/interop/tools/devnet#interop-devnet-1) | [`0x1A183FCf61053B7dcd2322BbE766f7E1946d3718`](https://sid.testnet.routescan.io/address/0x1A183FCf61053B7dcd2322BbE766f7E1946d3718) |
- | `GreetingSender` | [Devnet 0](/interop/tools/devnet#interop-devnet-1) | [`0x9De9f84a4EB3616B44CF1d68cD1A9098Df6cB25f`](https://sid.testnet.routescan.io/address/0x9De9f84a4EB3616B44CF1d68cD1A9098Df6cB25f/contract/420120000/readContract?chainid=420120000) |
-
- 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 |
- | ----------: | -------------------------------------------------------------------------- |
- | 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](https://cloud.google.com/application/web3/faucet/ethereum/sepolia).
-
- ```sh
- export PRIV_KEY=0x
- ```
-
- 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 0x55f5c4653dbcde7d1254f9c690a5d761b315500c
- ```
-
- Wait a few minutes until you can see the ETH [on your explorer](https://sid.testnet.routescan.io/).
-
- 4. Rerun the test.
-
- ```sh
- npm start
- ```
-
- 5. You can see the transactions in a block explorer.
-
- * The first transaction, which sets the greeting directly, [on the `Greeter` contract on interop1](https://sid.testnet.routescan.io/address/0x1A183FCf61053B7dcd2322BbE766f7E1946d3718).
- * The second transaction, the initiation message for the cross chain greeting change, [on the `GreetingSender` contract on interop0](https://sid.testnet.routescan.io/address/0x9De9f84a4EB3616B44CF1d68cD1A9098Df6cB25f).
- * The third transaction, the executing message for the cross chain greeting change, [on the `Greeter` contract on interop1 as an internal transaction](https://sid.testnet.routescan.io/address/0x1A183FCf61053B7dcd2322BbE766f7E1946d3718/internalTx).
-
- ### Debugging
-
- To see what messages were relayed by a specific transaction you can use this code:
-
- ```typescript
- import { decodeRelayedL2ToL2Messages } from '@eth-optimism/viem'
-
- const decodedRelays = decodeRelayedL2ToL2Messages(
- {receipt: receiptRelay})
-
- console.log(decodedRelays)
- console.log(decodedRelays.successfulMessages[0].log)
- ```
-
## Next steps
diff --git a/pages/interop/tutorials/message-passing/_meta.json b/pages/interop/tutorials/message-passing/_meta.json
index 3ed7579dd..7401d0da8 100644
--- a/pages/interop/tutorials/message-passing/_meta.json
+++ b/pages/interop/tutorials/message-passing/_meta.json
@@ -1,3 +1,3 @@
{
- "relay-with-cast": "Relay transactions manually"
+ "manual-relay": "Relay transactions manually"
}
diff --git a/pages/interop/tutorials/message-passing/manual-relay.mdx b/pages/interop/tutorials/message-passing/manual-relay.mdx
new file mode 100644
index 000000000..09e8735ce
--- /dev/null
+++ b/pages/interop/tutorials/message-passing/manual-relay.mdx
@@ -0,0 +1,353 @@
+---
+title: Relay transactions manually
+description: >-
+ Learn to relay transactions directly by sending the correct transaction.
+lang: en-US
+content_type: tutorial
+topic: interop-cast-manual-relay-tutorial
+personas:
+ - protocol-developer
+ - chain-operator
+ - app-developer
+categories:
+ - protocol
+ - interoperability
+ - cross-chain-messaging
+ - message-relaying
+ - cross-domain-messenger
+ - smart-contracts
+ - testnet
+ - superchain
+is_imported_content: 'false'
+---
+
+import { Callout, Steps } from 'nextra/components'
+import { InteropCallout } from '@/components/WipCallout'
+import { AutorelayCallout } from '@/components/AutorelayCallout'
+
+# Relay transactions manually
+
+
+
+
+
+## Overview
+
+Learn to relay transactions directly by sending the correct transaction.
+
+
+ About this tutorial
+
+ **Prerequisite technical knowledge**
+
+ * Familiarity with blockchain concepts
+ * Familiarity with [Foundry](https://book.getfoundry.sh/getting-started/installation), especially `cast`
+
+ **What you'll learn**
+
+ * How to use `cast` to relay transactions when autorelay does not work
+ * How to relay transactions using JavaScript
+
+ **Development environment requirements**
+
+ * Unix-like operating system (Linux, macOS, or WSL for Windows)
+ * Node.js version 16 or higher
+ * Git for version control
+ * Supersim environment configured and running
+ * Foundry tools installed (forge, cast, anvil)
+
+
+### What you'll build
+
+* A program to relay messages using [the JavaScript library](https://www.npmjs.com/package/@eth-optimism/viem)
+* A shell script to relay messages using [`cast`](https://book.getfoundry.sh/cast/)
+
+## Setup
+
+These steps are necessary to run the tutorial, regardless of whether you are using `cast` or the JavaScript API.
+
+
+ ### Run Supersim
+
+ This exercise needs to be done on Supersim.
+ You cannot use the devnets because you cannot disable autorelay on them.
+
+ 1. Follow the [installation guide](/app-developers/tutorials/supersim/getting-started/installation).
+
+ 2. Run Supersim *without* `--interop.relay`.
+
+ ```sh
+ ./supersim
+ ```
+
+ ### Create the state for relaying messages
+
+ The results of this step are similar to what the [message passing tutorial](/interop/tutorials/message-passing) would produce if you did not have autorelay on.
+
+ Execute this script.
+
+ ```sh file=/public/tutorials/setup-for-manual-relay.sh hash=eea0a71ff6b4c27b91225a715eb2718e
+ ```
+
+ This script installs `Greeter.sol` on chain B and `GreetingSender.sol` on chain A.
+ These smart contracts let us send a message from chain A that needs to be relayed to chain B.
+
+ Then, the script creates `./manual-relay/sendAndRelay.sh` to manually relay a message from chain A to chain B.
+ That script is [explained below](#manual-relay-using-cast).
+
+ Finally, this script writes out some parameter setting lines that should be executed on the main shell before you continue.
+ With a fresh Supersim running, these should be:
+
+ ```sh
+ GREETER_A_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3
+ GREETER_B_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3
+ PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
+ ```
+
+
+
+## Manual relay using the API
+
+
+ ### Setup
+
+ Use a [Node](https://nodejs.org/en) project.
+
+ 1. Initialize a new Node project.
+
+ ```sh
+ mkdir -p manual-relay/offchain
+ cd manual-relay/offchain
+ npm init -y
+ npm install --save-dev viem @eth-optimism/viem
+ mkdir src
+ ```
+
+ 2. Export environment variables.
+ This is necessary because those variables are currently limited to the shell process.
+ We need them in the Node process that the shell creates.
+
+ ```sh
+ export GREETER_A_ADDRESS GREETER_B_ADDRESS PRIVATE_KEY
+ ```
+
+ ### Manual relaying app
+
+ 1. Create a file `manual-relay.mjs` with:
+
+ ```javascript file=/public/tutorials/manual-relay.mjs hash=b0c44b327af300437f3d71ff049842f9
+ ```
+
+
+ Explanation
+
+ ```javascript file=/public/tutorials/manual-relay.mjs#L8-L9 hash=2d062eb374989a8a40199a4d7dc8be6e
+ ```
+
+ Import from the [`@eth-optimism/viem`](https://www.npmjs.com/package/@eth-optimism/viem) package.
+
+ ```javascript file=/public/tutorials/manual-relay.mjs#L18-L32 hash=cf5ce47bcbcd80327230a6da689688f8
+ ```
+
+ In addition to extending the wallets with [Viem public actions](https://viem.sh/docs/accounts/local#5-optional-extend-with-public-actions), extend with the OP-Stack actions.
+ On wallet A we need the public actions, those that only read information.
+ On wallet B we need the wallet actions, the ones that require an account.
+
+ ```javascript file=/public/tutorials/manual-relay.mjs#L55 hash=23aa6f24baeb5757130361f30c1b0e9c
+ ```
+
+ To relay a message we need the information in the receipt.
+ Also, we need to wait until the transaction with the relayed message is actually part of a block.
+
+ ```javascript file=/public/tutorials/manual-relay.mjs#L57-L58 hash=c0d3d8a60143c30b93db256518e8b583
+ ```
+
+ Show the user that until the relay transaction happens on chain B, the greeting is unchanged.
+
+ ```javascript file=/public/tutorials/manual-relay.mjs#L60-L63 hash=8cc99e67ee36474c81183108531cb295
+ ```
+
+ A single transaction can send multiple messages.
+ But here we know we sent just one, so we look for the first one in the list.
+
+ ```javascript file=/public/tutorials/manual-relay.mjs#L64-L71 hash=b7ed7d70ba5ec84322beee5369c5bee5
+ ```
+
+ Here we first send the relay message on chain B, and then wait for the receipt for it.
+
+
+ 2. Run JavaScript program, and see that the message is relayed.
+
+ ```sh
+ node manual-relay.mjs
+ ```
+
+ ### Debugging
+
+ To see what messages were relayed by a specific transaction you can use this code:
+
+ ```javascript
+ import { decodeRelayedL2ToL2Messages } from '@eth-optimism/viem'
+
+ const decodedRelays = decodeRelayedL2ToL2Messages(
+ {receipt: receiptRelay})
+
+ console.log(decodedRelays)
+ console.log(decodedRelays.successfulMessages[0].log)
+ ```
+
+
+## Manual relay using `cast`
+
+You can see an example of how to manually relay using `cast` in `manual-relay/sendAndRelay.sh`.
+It is somewhat complicated, so the setup creates one that is tailored to your environment.
+
+You can run the script using this command:
+
+```sh
+./manual-relay/sendAndRelay.sh
+```
+
+Here is the detailed explanation:
+
+1. Configuration parameters
+
+ ```sh
+ #! /bin/sh
+ PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
+ USER_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
+ URL_CHAIN_A=http://localhost:9545
+ URL_CHAIN_B=http://localhost:9546
+ GREETER_A_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3
+ GREETER_B_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3
+ CHAIN_ID_B=902
+ ```
+
+ This is the configuration.
+ The greeter addresses are identical because the nonce for the user address has an identical nonce on both chains.
+
+2. Send a message that needs to be relayed
+
+ ```sh
+ cast send -q --private-key $PRIVATE_KEY --rpc-url $URL_CHAIN_A $GREETER_A_ADDRESS "setGreeting(string)" "Hello from chain A $$"
+ ```
+
+ Send a message from chain A to chain B. The `$$` is the process ID, so if you rerun the script you'll see that the information changes.
+
+3. Find the log entry to relay
+
+ ```sh
+ cast logs "SentMessage(uint256,address,uint256,address,bytes)" --rpc-url $URL_CHAIN_A | tail -14 > log-entry
+ ```
+
+ Whenever `L2ToL2CrossDomainMessenger` sends a message to a different blockchain, it emits a [`SendMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L83-L91) event.
+ Extract only the latest `SendMessage` event from the logs.
+
+
+ Example `log-entry`
+
+ ```yaml
+ - address: 0x4200000000000000000000000000000000000023
+ blockHash: 0xcd0be97ffb41694faf3a172ac612a23f224afc1bfecd7cb737a7a464cf5d133e
+ blockNumber: 426
+ data: 0x0000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000064a41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001948656c6c6f2066726f6d20636861696e2041203131333030370000000000000000000000000000000000000000000000000000000000000000000000
+ logIndex: 0
+ removed: false
+ topics: [
+ 0x382409ac69001e11931a28435afef442cbfd20d9891907e8fa373ba7d351f320
+ 0x0000000000000000000000000000000000000000000000000000000000000386
+ 0x0000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa3
+ 0x0000000000000000000000000000000000000000000000000000000000000000
+ ]
+ transactionHash: 0x1d6f2e5e2c8f3eb055e95741380ca36492f784b9782848b66b66c65c5937ff3a
+ transactionIndex: 0
+ ```
+
+
+4. Manipulate the log entry to obtain information
+
+ ```sh
+ TOPICS=`cat log-entry | grep -A4 topics | awk '{print $1}' | tail -4 | sed 's/0x//'`
+ TOPICS=`echo $TOPICS | sed 's/ //g'`
+ ```
+
+ Consolidate the log topics into a single hex string.
+
+ ```sh
+ ORIGIN=0x4200000000000000000000000000000000000023
+ BLOCK_NUMBER=`cat log-entry | awk '/blockNumber/ {print $2}'`
+ LOG_INDEX=`cat log-entry | awk '/logIndex/ {print $2}'`
+ TIMESTAMP=`cast block $BLOCK_NUMBER --rpc-url $URL_CHAIN_A | awk '/timestamp/ {print $2}'`
+ CHAIN_ID_A=`cast chain-id --rpc-url $URL_CHAIN_A`
+ SENT_MESSAGE=`cat log-entry | awk '/data/ {print $2}'`
+ ```
+
+ Read additional fields from the log entry.
+
+ ```sh
+ LOG_ENTRY=0x`echo $TOPICS$SENT_MESSAGE | sed 's/0x//'`
+ ```
+
+ Consolidate the entire log entry.
+
+5. Create the access list for the executing message
+
+ ```sh
+ RPC_PARAMS=$(cat <-
- Learn to relay transactions directly by sending the correct transaction.
-lang: en-US
-content_type: tutorial
-topic: interop-cast-manual-relay-tutorial
-personas:
- - protocol-developer
- - chain-operator
- - app-developer
-categories:
- - protocol
- - interoperability
- - cross-chain-messaging
- - message-relaying
- - cross-domain-messenger
- - smart-contracts
- - testnet
- - superchain
-is_imported_content: 'false'
----
-
-import { Callout } from 'nextra/components'
-import { Steps } from 'nextra/components'
-import { InteropCallout } from '@/components/WipCallout'
-import { AutorelayCallout } from '@/components/AutorelayCallout'
-
-# Relay transactions manually
-
-
-
-
-
-## Overview
-
-Learn to relay transactions directly by sending the correct transaction.
-
-
- About this tutorial
-
- **Prerequisite technical knowledge**
-
- * Familiarity with blockchain concepts
- * Familiarity with [Foundry](https://book.getfoundry.sh/getting-started/installation), especially `cast`
-
- **What you'll learn**
-
- * How to use `cast` to relay transactions when autorelay does not work
-
- **Development environment requirements**
-
- * Unix-like operating system (Linux, macOS, or WSL for Windows)
- * Node.js version 16 or higher
- * Git for version control
- * Supersim environment configured and running
- * Foundry tools installed (forge, cast, anvil)
-
-
-### What you'll build
-
-* A script to relay messages without using [the JavaScript library](https://www.npmjs.com/package/@eth-optimism/viem)
-
-## Setup
-
-
- ### Run Supersim
-
- This exercise needs to be done on Supersim.
- You cannot use the devnets because you cannot disable autorelay on them.
-
- 1. Follow the [installation guide](/app-developers/tutorials/supersim/getting-started/installation).
-
- 2. Run Supersim *without* `--interop.relay`.
-
- ```sh
- ./supersim
- ```
-
- ### Create the state for relaying messages
-
- The results of this step are similar to what the [message passing tutorial](/interop/tutorials/message-passing) would produce if you did not have autorelay on.
-
- Execute this script.
-
- ```sh file=/public/tutorials/setup-for-manual-relay.sh#L1-L147 hash=a63d72f58a06ca7ca78fd1592efcf4a3
- ```
-
-
-## Manually relay a message using `cast`
-
-Run this script:
-
-```sh
-./manual-relay/sendAndRelay.sh
-```
-
-### Explanation
-
-```sh
-#! /bin/sh
-PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
-USER_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
-URL_CHAIN_A=http://localhost:9545
-URL_CHAIN_B=http://localhost:9546
-GREETER_A_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3
-GREETER_B_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3
-CHAIN_ID_B=902
-```
-
-This is the configuration.
-The greeter addresses are identical because the nonce for the user address has the same nonce on both chains.
-
-```sh
-cast send -q --private-key $PRIVATE_KEY --rpc-url $URL_CHAIN_A $GREETER_A_ADDRESS "setGreeting(string)" "Hello from chain A $$"
-```
-
-Send a message from chain A to chain B. The `$$` is the process ID, so if you rerun the script you'll see that the information changes.
-
-```sh
-cast logs "SentMessage(uint256,address,uint256,address,bytes)" --rpc-url $URL_CHAIN_A | tail -14 > log-entry
-```
-
-Whenever `L2ToL2CrossDomainMessenger` sends a message to a different blockchain, it emits a [`SendMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L83-L91) event.
-Extract only the latest `SendMessage` event from the logs.
-
-
- Example `log-entry`
-
- ```yaml
- - address: 0x4200000000000000000000000000000000000023
- blockHash: 0xcd0be97ffb41694faf3a172ac612a23f224afc1bfecd7cb737a7a464cf5d133e
- blockNumber: 426
- data: 0x0000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000064a41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001948656c6c6f2066726f6d20636861696e2041203131333030370000000000000000000000000000000000000000000000000000000000000000000000
- logIndex: 0
- removed: false
- topics: [
- 0x382409ac69001e11931a28435afef442cbfd20d9891907e8fa373ba7d351f320
- 0x0000000000000000000000000000000000000000000000000000000000000386
- 0x0000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa3
- 0x0000000000000000000000000000000000000000000000000000000000000000
- ]
- transactionHash: 0x1d6f2e5e2c8f3eb055e95741380ca36492f784b9782848b66b66c65c5937ff3a
- transactionIndex: 0
- ```
-
-
-```sh
-TOPICS=`cat log-entry | grep -A4 topics | awk '{print $1}' | tail -4 | sed 's/0x//'`
-TOPICS=`echo $TOPICS | sed 's/ //g'`
-```
-
-Consolidate the log topics into a single hex string.
-
-```sh
-ORIGIN=0x4200000000000000000000000000000000000023
-BLOCK_NUMBER=`cat log-entry | awk '/blockNumber/ {print $2}'`
-LOG_INDEX=`cat log-entry | awk '/logIndex/ {print $2}'`
-TIMESTAMP=`cast block $BLOCK_NUMBER --rpc-url $URL_CHAIN_A | awk '/timestamp/ {print $2}'`
-CHAIN_ID_A=`cast chain-id --rpc-url $URL_CHAIN_A`
-SENT_MESSAGE=`cat log-entry | awk '/data/ {print $2}'`
-```
-
-Read additional fields from the log entry.
-
-```sh
-LOG_ENTRY=0x`echo $TOPICS$SENT_MESSAGE | sed 's/0x//'`
-```
-
-Consolidate the entire log entry.
-
-```sh
-RPC_PARAMS=$(cat <> remappings.txt
+
cat > src/Greeter.sol < src/GreetingSender.sol <> remappings.txt
-mkdir -p lib/node_modules/@eth-optimism/contracts-bedrock/interfaces/L2
-wget https://raw.githubusercontent.com/ethereum-optimism/optimism/refs/heads/develop/packages/contracts-bedrock/interfaces/L2/IL2ToL2CrossDomainMessenger.sol
-mv IL2ToL2CrossDomainMessenger.sol lib/node_modules/@eth-optimism/contracts-bedrock/interfaces/L2
CHAIN_ID_B=`cast chain-id --rpc-url $URL_CHAIN_B`
GREETER_B_ADDRESS=`forge create --rpc-url $URL_CHAIN_B --private-key $PRIVATE_KEY Greeter --broadcast | awk '/Deployed to:/ {print $3}'`
GREETER_A_ADDRESS=`forge create --rpc-url $URL_CHAIN_A --private-key $PRIVATE_KEY --broadcast GreetingSender --constructor-args $GREETER_B_ADDRESS $CHAIN_ID_B | awk '/Deployed to:/ {print $3}'`
echo Setup done
+cd ..
+
cat > sendAndRelay.sh <