From d67b1365d477b4b792dc6ae280d06002b13bb9f4 Mon Sep 17 00:00:00 2001 From: Bradley Camacho <42678939+bradleycamacho@users.noreply.github.com> Date: Wed, 19 Feb 2025 11:34:09 -0800 Subject: [PATCH 1/3] Fix broken lint --- pages/app-developers/tools/build/faucets.mdx | 26 ++++++------- .../transactions/parameters.mdx | 32 ++++++++-------- .../interop/tutorials/message-passing.mdx | 37 +++++++++---------- 3 files changed, 46 insertions(+), 49 deletions(-) diff --git a/pages/app-developers/tools/build/faucets.mdx b/pages/app-developers/tools/build/faucets.mdx index 4ec689135..9e3cc9389 100644 --- a/pages/app-developers/tools/build/faucets.mdx +++ b/pages/app-developers/tools/build/faucets.mdx @@ -29,19 +29,19 @@ The Superchain Faucet is a great place to start if you're looking for testnet ET ## Additional faucets -| Faucet Name | Supported Networks | -|--------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------| -| [Alchemy Faucet](https://sepoliafaucet.com) | Sepolia | -| [Infura Faucet](https://www.infura.io/faucet/sepolia) | Sepolia | -| [QuickNode Faucet](https://faucet.quicknode.com/optimism/) | Sepolia, OP Sepolia | -| [Farcaster Frame Faucet by LearnWeb3](https://warpcast.com/haardikkk/0x28f4237d) | Sepolia, OP Sepolia | -| [LearnWeb3 Web App Faucet](https://learnweb3.io/faucets) | Sepolia, OP Sepolia | -| [Native USDC Faucet](https://faucet.circle.com/) | Sepolia, OP Sepolia | -| [ETHGlobal Testnet Faucet](https://ethglobal.com/faucet) | Sepolia, OP Sepolia, Base Sepolia, Zora Sepolia, Holesky | -| [Ethereum Ecosystem Faucets](https://www.ethereum-ecosystem.com/faucets) | Sepolia, OP Sepolia, Base Sepolia | -| [thirdweb Sepolia Faucet](https://thirdweb.com/sepolia?utm_source=opdocs\&utm_medium=docs) | Sepolia | -| [thirdweb OP Sepolia Faucet](https://thirdweb.com/op-sepolia-testnet?utm_source=opdocs\&utm_medium=docs) | OP Sepolia | -| [Tenderly Unlimited Faucet](https://docs.tenderly.co/virtual-testnets/unlimited-faucet?mtm_campaign=ext-docs&mtm_kwd=optimism) | OP Sepolia, OP Mainnet, and [85+ other networks](https://docs.tenderly.co/supported-networks?mtm_campaign=ext-docs&mtm_kwd=optimism) | +| Faucet Name | Supported Networks | +| ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | +| [Alchemy Faucet](https://sepoliafaucet.com) | Sepolia | +| [Infura Faucet](https://www.infura.io/faucet/sepolia) | Sepolia | +| [QuickNode Faucet](https://faucet.quicknode.com/optimism/) | Sepolia, OP Sepolia | +| [Farcaster Frame Faucet by LearnWeb3](https://warpcast.com/haardikkk/0x28f4237d) | Sepolia, OP Sepolia | +| [LearnWeb3 Web App Faucet](https://learnweb3.io/faucets) | Sepolia, OP Sepolia | +| [Native USDC Faucet](https://faucet.circle.com/) | Sepolia, OP Sepolia | +| [ETHGlobal Testnet Faucet](https://ethglobal.com/faucet) | Sepolia, OP Sepolia, Base Sepolia, Zora Sepolia, Holesky | +| [Ethereum Ecosystem Faucets](https://www.ethereum-ecosystem.com/faucets) | Sepolia, OP Sepolia, Base Sepolia | +| [thirdweb Sepolia Faucet](https://thirdweb.com/sepolia?utm_source=opdocs\&utm_medium=docs) | Sepolia | +| [thirdweb OP Sepolia Faucet](https://thirdweb.com/op-sepolia-testnet?utm_source=opdocs\&utm_medium=docs) | OP Sepolia | +| [Tenderly Unlimited Faucet](https://docs.tenderly.co/virtual-testnets/unlimited-faucet?mtm_campaign=ext-docs\&mtm_kwd=optimism) | OP Sepolia, OP Mainnet, and [85+ other networks](https://docs.tenderly.co/supported-networks?mtm_campaign=ext-docs\&mtm_kwd=optimism) | ## Bridge from Sepolia diff --git a/pages/app-developers/transactions/parameters.mdx b/pages/app-developers/transactions/parameters.mdx index 5723dafe1..1cb53861a 100644 --- a/pages/app-developers/transactions/parameters.mdx +++ b/pages/app-developers/transactions/parameters.mdx @@ -28,29 +28,27 @@ Note that, like Ethereum, the base fee is not explicitly defined within a transa Instead, the maximum base fee is determined as the difference between the `maxFeePerGas` and the `maxPriorityFeePerGas` fields of any given transaction. + {

Retrieve the latest block

} -{

Retrieve the latest block

} + Using the JSON-RPC API or your favorite Ethereum library, retrieve the latest block on OP Mainnet. -Using the JSON-RPC API or your favorite Ethereum library, retrieve the latest block on OP Mainnet. + {

Retrieve the base fee and gas used

} -{

Retrieve the base fee and gas used

} + From the block, retrieve the `baseFeePerGas` and `gasUsed` fields. -From the block, retrieve the `baseFeePerGas` and `gasUsed` fields. + {

Predict the next base fee

} -{

Predict the next base fee

} + OP Mainnet adjusts the base fee based on the amount of gas used in the previous block. + If the previous block used more than 5m gas (of the 30m gas limit), then the base fee will increase by up to 10%. + If the previous block used less than 5m gas, then the base fee will decrease by up to 10%. + Refer to the [OP Mainnet EIP-1559 Parameters](/stack/differences#eip-1559-parameters) section for more details. -OP Mainnet adjusts the base fee based on the amount of gas used in the previous block. -If the previous block used more than 5m gas (of the 30m gas limit), then the base fee will increase by up to 10%. -If the previous block used less than 5m gas, then the base fee will decrease by up to 10%. -Refer to the [OP Mainnet EIP-1559 Parameters](/stack/differences#eip-1559-parameters) section for more details. - -{

Select a base fee per gas

} - -Using the current base fee per gas and the amount of gas used in the previous block, you can predict the next base fee per gas. -If you are highly sensitive to the base fee, you may want to select a base fee per gas that is either 10% higher or 10% lower than the previous base fee. -However, you may run the risk that your transaction will not be included in a block quickly. -If you are less sensitive to the base fee, you may wish to simply use a large multiple of the previous base fee (e.g. 2x). + {

Select a base fee per gas

} + Using the current base fee per gas and the amount of gas used in the previous block, you can predict the next base fee per gas. + If you are highly sensitive to the base fee, you may want to select a base fee per gas that is either 10% higher or 10% lower than the previous base fee. + However, you may run the risk that your transaction will not be included in a block quickly. + If you are less sensitive to the base fee, you may wish to simply use a large multiple of the previous base fee (e.g. 2x).
## Selecting the priority fee @@ -63,4 +61,4 @@ Many Ethereum libraries will provide a function to call this JSON-RPC method. You can also use the [`eth_feeHistory`](https://docs.alchemy.com/reference/eth-feehistory) JSON-RPC method to retrieve historical priority fee data. You can then use this data to predict a reasonable priority fee for your transaction. -Alternatively, you can rely on Tenderly's [`tenderly_gasPrice`](https://docs.tenderly.co/node/rpc-reference/optimism-mainnet/tenderly_gasPrice?mtm_campaign=ext-docs&mtm_kwd=optimism) to get real-time gas predictions with 3 levels of likelihood for transaction inclusion. \ No newline at end of file +Alternatively, you can rely on Tenderly's [`tenderly_gasPrice`](https://docs.tenderly.co/node/rpc-reference/optimism-mainnet/tenderly_gasPrice?mtm_campaign=ext-docs\&mtm_kwd=optimism) to get real-time gas predictions with 3 levels of likelihood for transaction inclusion. diff --git a/pages/stack/interop/tutorials/message-passing.mdx b/pages/stack/interop/tutorials/message-passing.mdx index a50f6ef8e..0e43a5b24 100644 --- a/pages/stack/interop/tutorials/message-passing.mdx +++ b/pages/stack/interop/tutorials/message-passing.mdx @@ -231,7 +231,7 @@ For development purposes, we'll first use autorelay mode to handle message execu 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). @@ -500,33 +500,32 @@ In production we will not have this, we need to create our own executing message
Explanation - ```typescript file=/public/tutorials/app_v2.mts#L11-L15 hash=721ed87241535b606be281539baa8770 - ``` - - Import from the [`@eth-optimism/viem`](https://www.npmjs.com/package/@eth-optimism/viem) package. + ```typescript file=/public/tutorials/app_v2.mts#L11-L15 hash=721ed87241535b606be281539baa8770 + ``` - ```typescript file=/public/tutorials/app_v2.mts#L22-L28 hash=ffa76edb1191121e15eb4286e16ad041 - ``` + Import from the [`@eth-optimism/viem`](https://www.npmjs.com/package/@eth-optimism/viem) package. - 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#L22-L28 hash=ffa76edb1191121e15eb4286e16ad041 + ``` - ```typescript file=/public/tutorials/app_v2.mts#L59 hash=23aa6f24baeb5757130361f30c1b0e9c - ``` + 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. - 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#L59 hash=23aa6f24baeb5757130361f30c1b0e9c + ``` - ```typescript file=/public/tutorials/app_v2.mts#L61-L63 hash=da4b8733c578a393eb36f154a4e816e1 - ``` + 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. - 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#L61-L63 hash=da4b8733c578a393eb36f154a4e816e1 + ``` - ```typescript file=/public/tutorials/app_v2.mts#L64-L70 hash=6bfcd99f2e79df79897d230f36d4a682 - ``` + 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. - Here we first send the relay message on chain B, and then wait for the receipt for it. + ```typescript file=/public/tutorials/app_v2.mts#L64-L70 hash=6bfcd99f2e79df79897d230f36d4a682 + ``` + 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. From 2d467b9fb8c2d68b0e3d91b97e87d94dc8cfc447 Mon Sep 17 00:00:00 2001 From: Bradley Camacho <42678939+bradleycamacho@users.noreply.github.com> Date: Wed, 19 Feb 2025 11:40:41 -0800 Subject: [PATCH 2/3] Attempt to fix message parsing indents --- pages/stack/interop/message-passing.mdx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pages/stack/interop/message-passing.mdx b/pages/stack/interop/message-passing.mdx index d4aef22eb..60de05607 100644 --- a/pages/stack/interop/message-passing.mdx +++ b/pages/stack/interop/message-passing.mdx @@ -49,7 +49,8 @@ sequenceDiagram * `_destination`: The chain ID of the destination blockchain. * `_target`: The address of the contract on that blockchain. * `_message`: The actual message. - This message is provided to `_target` as calldata, which means it includes a function selector and the parameters for that function call. + + This message is provided to `_target` as calldata, which means it includes a function selector and the parameters for that function call. 3. `L2ToL2CrossDomainMessenger` on the source chain verifies the message is legitimate: * The destination chain is one to which this chain can send messages. @@ -98,14 +99,15 @@ sequenceDiagram * The destination chain ID is correct. * The target is neither `CrossL2Inbox` nor `L2ToL2CrossDomainMessenger`. * This message has not been relayed before. - This is the reason we need the nonce value, to enable us to send multiple messages that would be otherwise identical. + + This is the reason we need the nonce value, to enable us to send multiple messages that would be otherwise identical. 5. If everything checks out, `L2ToL2CrossDomainMessenger` calls the destination contract with the calldata provided in the message. -## Next steps +## Next steps dasd -* Read how [messages get from one blockchain to another (`CrossL2Inbox`)](explainer#how-messages-get-from-one-chain-to-the-other). -* Try [Supersim](tools/supersim) for testing cross-chain messages locally. -* Learn about [manually relaying messages](/stack/interop/tutorials/relay-messages-viem). +* Read how [messages get from one blockchain to another (`CrossL2Inbox`)](explainer#how-messages-get-from-one-chain-to-the-other). +* Try [Supersim](tools/supersim) for testing cross-chain messages locally. +* Learn about [manually relaying messages](/stack/interop/tutorials/relay-messages-viem). {/* After the tutorial for L2ToL2CrossDomainMessenger is written, need to add a link here */} From 54b7e7b4f7b695317ae211637c0fd1f6b9304aab Mon Sep 17 00:00:00 2001 From: Bradley Camacho <42678939+bradleycamacho@users.noreply.github.com> Date: Wed, 19 Feb 2025 11:45:39 -0800 Subject: [PATCH 3/3] Message passing fix --- pages/stack/interop/message-passing.mdx | 8 +- .../interop/tutorials/message-passing.mdx | 144 +++++++++--------- 2 files changed, 76 insertions(+), 76 deletions(-) diff --git a/pages/stack/interop/message-passing.mdx b/pages/stack/interop/message-passing.mdx index 60de05607..a5a421471 100644 --- a/pages/stack/interop/message-passing.mdx +++ b/pages/stack/interop/message-passing.mdx @@ -104,10 +104,10 @@ sequenceDiagram 5. If everything checks out, `L2ToL2CrossDomainMessenger` calls the destination contract with the calldata provided in the message. -## Next steps dasd +## Next steps -* Read how [messages get from one blockchain to another (`CrossL2Inbox`)](explainer#how-messages-get-from-one-chain-to-the-other). -* Try [Supersim](tools/supersim) for testing cross-chain messages locally. -* Learn about [manually relaying messages](/stack/interop/tutorials/relay-messages-viem). +* Read how [messages get from one blockchain to another (`CrossL2Inbox`)](explainer#how-messages-get-from-one-chain-to-the-other). +* Try [Supersim](tools/supersim) for testing cross-chain messages locally. +* Learn about [manually relaying messages](/stack/interop/tutorials/relay-messages-viem). {/* After the tutorial for L2ToL2CrossDomainMessenger is written, need to add a link here */} diff --git a/pages/stack/interop/tutorials/message-passing.mdx b/pages/stack/interop/tutorials/message-passing.mdx index 0e43a5b24..202b9e310 100644 --- a/pages/stack/interop/tutorials/message-passing.mdx +++ b/pages/stack/interop/tutorials/message-passing.mdx @@ -155,49 +155,49 @@ For development purposes, we'll first use autorelay mode to handle message execu GREETER_B_ADDR=`forge create --rpc-url $RPC_B --private-key $PRIV_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 $RPC_B --private-key $PRIV_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_ADDR= + ``` +
-
- Sanity check +
+ Sanity check - Run these commands to verify the contract works. - The first and third commands retrieve the current greeting, while the second command updates it. + Run these commands to verify the contract works. + 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 - ``` -
+ ```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 + ``` +
4. Install the Optimism Solidity libraries into the project. @@ -222,18 +222,18 @@ For development purposes, we'll first use autorelay mode to handle message execu ```solidity file=/public/tutorials/GreetingSender.sol#L1-L28 hash=75d197d1e1da112421785c2160f6a55a ``` -
- 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. @@ -315,19 +315,19 @@ In this section we change `Greeter.sol` to emit a separate event in it receives } ``` -
- Explanation +
+ Explanation - ```solidity - if (msg.sender == Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER) { - (address sender, uint256 chainId) = - messenger.crossDomainMessageContext(); - emit CrossDomainSetGreeting(sender, chainId, _greeting); - } - ``` + ```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). -
+ 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. @@ -497,36 +497,36 @@ In production we will not have this, we need to create our own executing message ```typescript file=/public/tutorials/app_v2.mts hash=a7b0f60aa6f1e48fc9994178ed3d5498 ``` -
- Explanation +
+ Explanation - ```typescript file=/public/tutorials/app_v2.mts#L11-L15 hash=721ed87241535b606be281539baa8770 - ``` + ```typescript file=/public/tutorials/app_v2.mts#L11-L15 hash=721ed87241535b606be281539baa8770 + ``` - Import from the [`@eth-optimism/viem`](https://www.npmjs.com/package/@eth-optimism/viem) package. + 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=ffa76edb1191121e15eb4286e16ad041 - ``` + ```typescript file=/public/tutorials/app_v2.mts#L22-L28 hash=ffa76edb1191121e15eb4286e16ad041 + ``` - 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. + 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=23aa6f24baeb5757130361f30c1b0e9c - ``` + ```typescript file=/public/tutorials/app_v2.mts#L59 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. + 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=da4b8733c578a393eb36f154a4e816e1 - ``` + ```typescript file=/public/tutorials/app_v2.mts#L61-L63 hash=da4b8733c578a393eb36f154a4e816e1 + ``` - 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. + 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=6bfcd99f2e79df79897d230f36d4a682 - ``` + ```typescript file=/public/tutorials/app_v2.mts#L64-L70 hash=6bfcd99f2e79df79897d230f36d4a682 + ``` - Here we first send the relay message on chain B, and then wait for the receipt for it. -
+ 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.