From dd1c488826f1b346a33093b3a606a5d19fd32bdc Mon Sep 17 00:00:00 2001 From: Ori Pomerantz Date: Tue, 3 Jun 2025 18:00:50 -0500 Subject: [PATCH 01/11] Foundry sending works --- pages/interop/tutorials/unit-tests.mdx | 29 ++++ pages/interop/tutorials/unit-tests/_meta.json | 4 + .../interop/tutorials/unit-tests/foundry.mdx | 91 ++++++++++++ .../interop/tutorials/unit-tests/hardhat.mdx | 24 +++ public/tutorials/setup-for-testing.sh | 140 ++++++++++++++++++ 5 files changed, 288 insertions(+) create mode 100644 pages/interop/tutorials/unit-tests.mdx create mode 100644 pages/interop/tutorials/unit-tests/_meta.json create mode 100644 pages/interop/tutorials/unit-tests/foundry.mdx create mode 100644 pages/interop/tutorials/unit-tests/hardhat.mdx create mode 100644 public/tutorials/setup-for-testing.sh diff --git a/pages/interop/tutorials/unit-tests.mdx b/pages/interop/tutorials/unit-tests.mdx new file mode 100644 index 000000000..e5467827f --- /dev/null +++ b/pages/interop/tutorials/unit-tests.mdx @@ -0,0 +1,29 @@ +--- +title: Interop and unit tests +description: Learn how to write unit tests for interop +lang: en-US +content_type: landing-page +topic: interop-tutorial-unit-tests +personas: + - app-developer +categories: + - protocol + - interoperability + - cross-chain-messaging + - tutorial + - testing +is_imported_content: 'false' +--- + +import { Card, Cards } from 'nextra/components' + +# Interop and unit tests + +Documentation covering Interop related tutorials. + + + } /> + + } /> + + diff --git a/pages/interop/tutorials/unit-tests/_meta.json b/pages/interop/tutorials/unit-tests/_meta.json new file mode 100644 index 000000000..e9cbbaa02 --- /dev/null +++ b/pages/interop/tutorials/unit-tests/_meta.json @@ -0,0 +1,4 @@ +{ + "foundry": "Foundry", + "hardhat": "Hardhat" +} diff --git a/pages/interop/tutorials/unit-tests/foundry.mdx b/pages/interop/tutorials/unit-tests/foundry.mdx new file mode 100644 index 000000000..3154c87d7 --- /dev/null +++ b/pages/interop/tutorials/unit-tests/foundry.mdx @@ -0,0 +1,91 @@ +--- +title: Interop and unit tests using Foundry +description: Learn how to write unit tests for interop when using Foundry +lang: en-US +content_type: tutorial +topic: interop-tutorial-unit-tests-foundry +personas: + - app-developer +categories: + - protocol + - interoperability + - cross-chain-messaging + - tutorial + - testing + - foundry +is_imported_content: 'false' +--- + +import { Callout, Steps } from 'nextra/components' +import { InteropCallout } from '@/components/WipCallout' + + + +# Interop and unit tests using Foundry + +Most of parts of the contracts can be [tested normally](/app-developers/testing-apps). +This tutorials teaches you how to verify that a message has been sent successfully, and how to fake receiving a message, the two functions that tie directly into interop. +To show how this works, we test [the `Greeter` and `GreetingSender` contracts](/interop/tutorials/message-passing). + +## Setup + +The results of this step are similar to what the [message passing tutorial](/interop/tutorials/message-passing) would produce, + +This script creates a Foundry project (in `testing/forge`) and a Hardhat project (in `testing/hardhat`) with the necessary files. +Execute it in a UNIX or Linux environment. + +```sh file=/public/tutorials/setup-for-testing.sh hash=a77f9926b61271c1895ad2c9527f9fd1 +``` + +## Test sending a message + +The easiest way to test sending a message is to see [the event emitted by `L2ToL2CrossDomainMessenger.sendMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L160). + +To see this in action, run these commands: + +``` +cd testing/forge +forge test GreetingSender --fork-url https://interop-alpha-0.optimism.io +``` + +The default [`anvil`](https://book.getfoundry.sh/anvil/overview) instance created by `forge test` does not contain the interop contracts, so we need to fork [a blockchain that does](/interop/tools/devnet). + +The test is implemented by `tests/GreetingSender.t.sol`. + +
+ + Explanation + + ```sh file=/public/tutorials/setup-for-testing.sh#L109-L117 hash=e8c77299b01dd6f03d3e36d2e9d82608 + ``` + + The definition for the event we expect to see, [from the `L2ToL2CrossDomainMessenger` source code](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L160). + + ```sh file=/public/tutorials/setup-for-testing.sh#L119-L121 hash=645c522fafccb282df37b7d3df27bd3f + ``` + + Create a new `GreetingSender` instance for each test. + + ```sh file=/public/tutorials/setup-for-testing.sh#L124-L129 hash=5e79ce67c4e5f54eee5b8d09ace39860 + ``` + + Calculate the message to be sent, the same way that `GreetingSender` does. + + ```sh file=/public/tutorials/setup-for-testing.sh#L132-L132 hash=028411291cccc262557abde834549fc2 + ``` + + Out of the indexed topics, verify the first (destination chain) and second (address on the destination chain). + Ignore the third topic, the nonce, because it can vary. + Finally, verify that the unindexed data of the log entry (the sender address and the message) is correct. + + ```sh file=/public/tutorials/setup-for-testing.sh#L133-L133 hash=37203df9264e95e763befaf2e5dbbfab + ``` + + Emit the message we expect to see. + + ```sh file=/public/tutorials/setup-for-testing.sh#L135-L135 hash=9322933b2f965ddc75bb8d3b2ab4c95d + ``` + + Call the code being tested, which should emit a similar log entry to the one we just emitted. + +
\ No newline at end of file diff --git a/pages/interop/tutorials/unit-tests/hardhat.mdx b/pages/interop/tutorials/unit-tests/hardhat.mdx new file mode 100644 index 000000000..3ed8ad0c7 --- /dev/null +++ b/pages/interop/tutorials/unit-tests/hardhat.mdx @@ -0,0 +1,24 @@ +--- +title: Interop and unit tests using Hardhat +description: Learn how to write unit tests for interop when using Hardhat +lang: en-US +content_type: tutorial +topic: interop-tutorial-unit-tests-hardhat +personas: + - app-developer +categories: + - protocol + - interoperability + - cross-chain-messaging + - tutorial + - testing + - foundry +is_imported_content: 'false' +--- + +import { Callout, Steps } from 'nextra/components' +import { InteropCallout } from '@/components/WipCallout' + + + +# Interop and unit tests using Hardhat diff --git a/public/tutorials/setup-for-testing.sh b/public/tutorials/setup-for-testing.sh new file mode 100644 index 000000000..3ee2271ab --- /dev/null +++ b/public/tutorials/setup-for-testing.sh @@ -0,0 +1,140 @@ +#! /bin/sh + +rm -rf testing +mkdir -p testing/forge +cd testing/forge + +forge init +find . -name 'Counter*' -exec rm {} \; +cd lib +npm install @eth-optimism/contracts-bedrock +cd .. +echo @eth-optimism/=lib/node_modules/@eth-optimism/ >> remappings.txt + +cat > src/Greeter.sol < src/GreetingSender.sol < test/GreetingSender.t.sol < Date: Tue, 3 Jun 2025 18:01:25 -0500 Subject: [PATCH 02/11] Auto-fix: Update breadcrumbs, spelling dictionary and other automated fixes --- .../interop/tutorials/unit-tests/foundry.mdx | 46 +++++++++---------- words.txt | 1 + 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/pages/interop/tutorials/unit-tests/foundry.mdx b/pages/interop/tutorials/unit-tests/foundry.mdx index 3154c87d7..7980672b4 100644 --- a/pages/interop/tutorials/unit-tests/foundry.mdx +++ b/pages/interop/tutorials/unit-tests/foundry.mdx @@ -53,39 +53,37 @@ The default [`anvil`](https://book.getfoundry.sh/anvil/overview) instance create The test is implemented by `tests/GreetingSender.t.sol`.
+ Explanation - Explanation + ```sh file=/public/tutorials/setup-for-testing.sh#L109-L117 hash=e8c77299b01dd6f03d3e36d2e9d82608 + ``` - ```sh file=/public/tutorials/setup-for-testing.sh#L109-L117 hash=e8c77299b01dd6f03d3e36d2e9d82608 - ``` + The definition for the event we expect to see, [from the `L2ToL2CrossDomainMessenger` source code](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L160). - The definition for the event we expect to see, [from the `L2ToL2CrossDomainMessenger` source code](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L160). + ```sh file=/public/tutorials/setup-for-testing.sh#L119-L121 hash=645c522fafccb282df37b7d3df27bd3f + ``` - ```sh file=/public/tutorials/setup-for-testing.sh#L119-L121 hash=645c522fafccb282df37b7d3df27bd3f - ``` + Create a new `GreetingSender` instance for each test. - Create a new `GreetingSender` instance for each test. + ```sh file=/public/tutorials/setup-for-testing.sh#L124-L129 hash=5e79ce67c4e5f54eee5b8d09ace39860 + ``` - ```sh file=/public/tutorials/setup-for-testing.sh#L124-L129 hash=5e79ce67c4e5f54eee5b8d09ace39860 - ``` + Calculate the message to be sent, the same way that `GreetingSender` does. - Calculate the message to be sent, the same way that `GreetingSender` does. + ```sh file=/public/tutorials/setup-for-testing.sh#L132-L132 hash=028411291cccc262557abde834549fc2 + ``` - ```sh file=/public/tutorials/setup-for-testing.sh#L132-L132 hash=028411291cccc262557abde834549fc2 - ``` + Out of the indexed topics, verify the first (destination chain) and second (address on the destination chain). + Ignore the third topic, the nonce, because it can vary. + Finally, verify that the unindexed data of the log entry (the sender address and the message) is correct. - Out of the indexed topics, verify the first (destination chain) and second (address on the destination chain). - Ignore the third topic, the nonce, because it can vary. - Finally, verify that the unindexed data of the log entry (the sender address and the message) is correct. + ```sh file=/public/tutorials/setup-for-testing.sh#L133-L133 hash=37203df9264e95e763befaf2e5dbbfab + ``` - ```sh file=/public/tutorials/setup-for-testing.sh#L133-L133 hash=37203df9264e95e763befaf2e5dbbfab - ``` + Emit the message we expect to see. - Emit the message we expect to see. + ```sh file=/public/tutorials/setup-for-testing.sh#L135-L135 hash=9322933b2f965ddc75bb8d3b2ab4c95d + ``` - ```sh file=/public/tutorials/setup-for-testing.sh#L135-L135 hash=9322933b2f965ddc75bb8d3b2ab4c95d - ``` - - Call the code being tested, which should emit a similar log entry to the one we just emitted. - -
\ No newline at end of file + Call the code being tested, which should emit a similar log entry to the one we just emitted. + diff --git a/words.txt b/words.txt index 367ff3cb5..53a585a4a 100644 --- a/words.txt +++ b/words.txt @@ -429,6 +429,7 @@ uncensorable uncountered undercollateralize Unichain +unindexed Unprotect unsubmitted UPNP From 048f8ab0c22e9f7e04b20efa08ed3b1281812f0c Mon Sep 17 00:00:00 2001 From: Ori Pomerantz Date: Wed, 4 Jun 2025 04:24:53 -0500 Subject: [PATCH 03/11] Foundry testing --- .../interop/tutorials/unit-tests/foundry.mdx | 60 +++++++++++++++- public/tutorials/setup-for-testing.sh | 72 +++++++++++++++++++ 2 files changed, 129 insertions(+), 3 deletions(-) diff --git a/pages/interop/tutorials/unit-tests/foundry.mdx b/pages/interop/tutorials/unit-tests/foundry.mdx index 7980672b4..3b3815682 100644 --- a/pages/interop/tutorials/unit-tests/foundry.mdx +++ b/pages/interop/tutorials/unit-tests/foundry.mdx @@ -29,12 +29,12 @@ To show how this works, we test [the `Greeter` and `GreetingSender` contracts](/ ## Setup -The results of this step are similar to what the [message passing tutorial](/interop/tutorials/message-passing) would produce, - This script creates a Foundry project (in `testing/forge`) and a Hardhat project (in `testing/hardhat`) with the necessary files. Execute it in a UNIX or Linux environment. -```sh file=/public/tutorials/setup-for-testing.sh hash=a77f9926b61271c1895ad2c9527f9fd1 +The results of this step are similar to what the [message passing tutorial](/interop/tutorials/message-passing) produces. + +```sh file=/public/tutorials/setup-for-testing.sh hash=1a87986e9f78d6d233d9f1ebb4022c7c ``` ## Test sending a message @@ -87,3 +87,57 @@ The test is implemented by `tests/GreetingSender.t.sol`. Call the code being tested, which should emit a similar log entry to the one we just emitted. + +## Test receiving a message + +To simulate receiving a message, we need to ensure two conditions are fulfilled: + +- The tested code is called by [`L2ToL2CrossDomainMessenger`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol). +- The tested code can receive additional information through simulations of: + - [`L2ToL2CrossDomainMessenger.crossDomainMessageSender`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L102-L108) + - [`L2ToL2CrossDomainMessenger.crossDomainMessageSource`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L110-L116) + - [`L2ToL2CrossDomainMessenger.crossDomainMessageContext`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L118-L126) + +To see this in action, run these commands: + +``` +cd testing/forge +forge test Greeter +``` + +The test is implemented by `tests/Greeter.t.sol`. + +
+ Explanation + + ```sh file=/public/tutorials/setup-for-testing.sh#L171 hash=d9bb7b8ca88e8856bd86c256934a0b0b + ``` + + This function sets up the environment for a pretend interop call. + + ```sh file=/public/tutorials/setup-for-testing.sh#L172-L182 hash=65aae51c8573ecb296b942c7073a3379 + ``` + + Use [`vm.mockCall`](https://book.getfoundry.sh/reference/cheatcodes/mock-call) to specify the responses to calls to `L2ToL2CrossDomainMessenger`. + + ```sh file=/public/tutorials/setup-for-testing.sh#L183-L187 hash=478229c219493adbbfea088cf266dec5 + ``` + + At writing `crossDomainMessageContext` is not available in the [contracts npm package](https://www.npmjs.com/package/@eth-optimism/contracts-bedrock), so we calculate the selector directly using `bytes4(keccak256("crossDomainMessageContext()"))`. + + ```sh file=/public/tutorials/setup-for-testing.sh#L188-L189 hash=18498ce1031cf749a13f6207d0828ca7 + ``` + + Use [`vm.prank`](https://book.getfoundry.sh/reference/cheatcodes/prank) to make it appear the tested code is called by `L2ToL2CrossDomainMessenger`. + + ```sh file=/public/tutorials/setup-for-testing.sh#L191-L201 hash=035afa3348edfa18a0be06b9f9991c38 + ``` + + Test how `Greeter` acts when the greeting is set from another chain. + + ```sh file=/public/tutorials/setup-for-testing.sh#L203-L210 hash=ea83b0fcf27566b5ae9221d1091bfc6b + ``` + + Test how `Greeter` acts when the greeting is set from this chain. + +
\ No newline at end of file diff --git a/public/tutorials/setup-for-testing.sh b/public/tutorials/setup-for-testing.sh index 3ee2271ab..9d0635600 100644 --- a/public/tutorials/setup-for-testing.sh +++ b/public/tutorials/setup-for-testing.sh @@ -137,4 +137,76 @@ contract GreetingSenderTest is Test { } EOF +cat > test/Greeter.t.sol < Date: Wed, 4 Jun 2025 04:25:22 -0500 Subject: [PATCH 04/11] Auto-fix: Update breadcrumbs, spelling dictionary and other automated fixes --- pages/interop/tutorials/unit-tests/foundry.mdx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/pages/interop/tutorials/unit-tests/foundry.mdx b/pages/interop/tutorials/unit-tests/foundry.mdx index 3b3815682..ddd4735ec 100644 --- a/pages/interop/tutorials/unit-tests/foundry.mdx +++ b/pages/interop/tutorials/unit-tests/foundry.mdx @@ -92,11 +92,11 @@ The test is implemented by `tests/GreetingSender.t.sol`. To simulate receiving a message, we need to ensure two conditions are fulfilled: -- The tested code is called by [`L2ToL2CrossDomainMessenger`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol). -- The tested code can receive additional information through simulations of: - - [`L2ToL2CrossDomainMessenger.crossDomainMessageSender`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L102-L108) - - [`L2ToL2CrossDomainMessenger.crossDomainMessageSource`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L110-L116) - - [`L2ToL2CrossDomainMessenger.crossDomainMessageContext`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L118-L126) +* The tested code is called by [`L2ToL2CrossDomainMessenger`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol). +* The tested code can receive additional information through simulations of: + * [`L2ToL2CrossDomainMessenger.crossDomainMessageSender`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L102-L108) + * [`L2ToL2CrossDomainMessenger.crossDomainMessageSource`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L110-L116) + * [`L2ToL2CrossDomainMessenger.crossDomainMessageContext`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L118-L126) To see this in action, run these commands: @@ -139,5 +139,4 @@ The test is implemented by `tests/Greeter.t.sol`. ``` Test how `Greeter` acts when the greeting is set from this chain. - - \ No newline at end of file + From 2b484e56744c3138a5bf7253e2847f017c6dfc26 Mon Sep 17 00:00:00 2001 From: Ori Pomerantz Date: Fri, 6 Jun 2025 13:39:24 -0500 Subject: [PATCH 05/11] Tests work --- .../interop/tutorials/unit-tests/hardhat.mdx | 14 ++ public/tutorials/setup-for-testing.sh | 206 +++++++++++++++++- 2 files changed, 219 insertions(+), 1 deletion(-) diff --git a/pages/interop/tutorials/unit-tests/hardhat.mdx b/pages/interop/tutorials/unit-tests/hardhat.mdx index 3ed8ad0c7..e514e63e5 100644 --- a/pages/interop/tutorials/unit-tests/hardhat.mdx +++ b/pages/interop/tutorials/unit-tests/hardhat.mdx @@ -22,3 +22,17 @@ import { InteropCallout } from '@/components/WipCallout' # Interop and unit tests using Hardhat + +Most of parts of the contracts can be [tested normally](/app-developers/testing-apps). +This tutorials teaches you how to verify that a message has been sent successfully, and how to fake receiving a message, the two functions that tie directly into interop. +To show how this works, we test [the `Greeter` and `GreetingSender` contracts](/interop/tutorials/message-passing). + +## Setup + +This script creates a Foundry project (in `testing/forge`) and a Hardhat project (in `testing/hardhat`) with the necessary files. +Execute it in a UNIX or Linux environment. + +The results of this step are similar to what the [message passing tutorial](/interop/tutorials/message-passing) produces. + +```sh file=/public/tutorials/setup-for-testing.sh hash=1a87986e9f78d6d233d9f1ebb4022c7c +``` \ No newline at end of file diff --git a/public/tutorials/setup-for-testing.sh b/public/tutorials/setup-for-testing.sh index 9d0635600..18b1aeb48 100644 --- a/public/tutorials/setup-for-testing.sh +++ b/public/tutorials/setup-for-testing.sh @@ -209,4 +209,208 @@ contract GreeterTest is Test { greeter.setGreeting(greeting); } } -EOF \ No newline at end of file +EOF + +cd .. +mkdir hardhat +cd hardhat +npm init -y +npm install --save-dev hardhat +export HARDHAT_CREATE_JAVASCRIPT_PROJECT_WITH_DEFAULTS=1 +export HARDHAT_DISABLE_TELEMETRY_PROMPT=true +npx hardhat init --yes +cp ../forge/src/Greeter.sol contracts +cat ../forge/src/GreetingSender.sol | sed 's/src\/Greeter.sol/contracts\/Greeter.sol/' > contracts/GreetingSender.sol +find . -name 'Lock*' -exec rm {} \; +npm install @eth-optimism/contracts-bedrock dotenv @eth-optimism/viem + +cat > hardhat.config.js < test/GreetingSender.js < { + + const GreetingSender = await ethers.getContractFactory( + "GreetingSender" + ) + const greetingSender = await GreetingSender.deploy( + targetGreeter, + targetChain + ) + + const messenger = new ethers.Contract( + contracts.l2ToL2CrossDomainMessenger.address, + l2ToL2CrossDomainMessengerAbi, + ethers.provider + ); + + return { greetingSender, messenger }; + } + + it("emits SentMessage with the right arguments", async () => { + const { greetingSender, messenger } = await deployFixture() + + const greeting = "Hello" + + // build the exact calldata the test expects + const iface = new ethers.Interface([ + "function setGreeting(string)", + ]) + const calldata = iface.encodeFunctionData("setGreeting", [ + greeting, + ]) + + await expect(greetingSender.setGreeting(greeting)) + .to.emit(messenger, "SentMessage") + .withArgs( + targetChain, + targetGreeter, + anyValue, + greetingSender.target, + calldata + ) + }) +}) +EOF + +cat > test/Greeter.js < { + const fakeSender = "0x0123456789012345678901234567890123456789"; + const fakeSourceChain = 901; + + async function deployFixture() { + + const MockMessenger = await ethers.getContractFactory("MockL2ToL2Messenger"); + const mock = await MockMessenger.deploy(fakeSender, fakeSourceChain); + + // overwrite predeploy with mock code + await network.provider.send("hardhat_setCode", [ + contracts.l2ToL2CrossDomainMessenger.address, + await ethers.provider.getCode(mock.target), + ]); + + const Greeter = await ethers.getContractFactory("Greeter"); + const greeter = await Greeter.deploy(); + + const messenger = new ethers.Contract( + contracts.l2ToL2CrossDomainMessenger.address, + MockMessenger.interface, + ethers.provider + ); + + return { greeter, messenger, mockMessenger: mock }; + } + + it("emits SetGreeting with the right arguments when called locally", async () => { + const { greeter } = await deployFixture(); + const greeting = "Hello"; + + await expect(greeter.setGreeting(greeting)) + .to.emit(greeter, "SetGreeting") + .withArgs((await ethers.getSigners())[0].address, greeting); + }); + + it("emits SetGreeting and CrossDomainSetGreeting with the right arguments when called remotely", + async () => { + const { greeter } = await deployFixture(); + const greeting = "Hello"; + + const impersonatedMessenger = + await ethers.getImpersonatedSigner(contracts.l2ToL2CrossDomainMessenger.address); + const tx = await (await ethers.getSigners())[0].sendTransaction({ + to: contracts.l2ToL2CrossDomainMessenger.address, + value: ethers.parseEther("1.0") + }); + + + await expect( + greeter.connect(impersonatedMessenger).setGreeting(greeting) + ) + .to.emit(greeter, "SetGreeting") + .withArgs(contracts.l2ToL2CrossDomainMessenger.address, greeting); + + await expect( + greeter.connect(impersonatedMessenger).setGreeting(greeting) + ) + .to.emit(greeter, "CrossDomainSetGreeting") + .withArgs(fakeSender, fakeSourceChain, greeting); + }); +}); +EOF + +cat > contracts/MockL2ToL2Messenger.sol < Date: Fri, 6 Jun 2025 13:39:53 -0500 Subject: [PATCH 06/11] Auto-fix: Update breadcrumbs, spelling dictionary and other automated fixes --- pages/interop/tutorials/unit-tests/hardhat.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/interop/tutorials/unit-tests/hardhat.mdx b/pages/interop/tutorials/unit-tests/hardhat.mdx index e514e63e5..b787e3624 100644 --- a/pages/interop/tutorials/unit-tests/hardhat.mdx +++ b/pages/interop/tutorials/unit-tests/hardhat.mdx @@ -35,4 +35,4 @@ Execute it in a UNIX or Linux environment. The results of this step are similar to what the [message passing tutorial](/interop/tutorials/message-passing) produces. ```sh file=/public/tutorials/setup-for-testing.sh hash=1a87986e9f78d6d233d9f1ebb4022c7c -``` \ No newline at end of file +``` From a8b8eec2f7f23b42834e26b4a0eb0ee6cecca395 Mon Sep 17 00:00:00 2001 From: Ori Pomerantz Date: Sun, 8 Jun 2025 14:55:24 -0500 Subject: [PATCH 07/11] Full version --- .../interop/tutorials/unit-tests/foundry.mdx | 34 ++-- .../interop/tutorials/unit-tests/hardhat.mdx | 153 +++++++++++++++++- public/tutorials/setup-for-testing.sh | 5 +- 3 files changed, 174 insertions(+), 18 deletions(-) diff --git a/pages/interop/tutorials/unit-tests/foundry.mdx b/pages/interop/tutorials/unit-tests/foundry.mdx index ddd4735ec..a837217d6 100644 --- a/pages/interop/tutorials/unit-tests/foundry.mdx +++ b/pages/interop/tutorials/unit-tests/foundry.mdx @@ -34,7 +34,7 @@ Execute it in a UNIX or Linux environment. The results of this step are similar to what the [message passing tutorial](/interop/tutorials/message-passing) produces. -```sh file=/public/tutorials/setup-for-testing.sh hash=1a87986e9f78d6d233d9f1ebb4022c7c +```sh file=/public/tutorials/setup-for-testing.sh hash=4d0fa175564131911ab6a12fb110294c ``` ## Test sending a message @@ -43,7 +43,7 @@ The easiest way to test sending a message is to see [the event emitted by `L2ToL To see this in action, run these commands: -``` +```sh cd testing/forge forge test GreetingSender --fork-url https://interop-alpha-0.optimism.io ``` @@ -55,34 +55,34 @@ The test is implemented by `tests/GreetingSender.t.sol`.
Explanation - ```sh file=/public/tutorials/setup-for-testing.sh#L109-L117 hash=e8c77299b01dd6f03d3e36d2e9d82608 + ```solidity file=/public/tutorials/setup-for-testing.sh#L109-L117 hash=e8c77299b01dd6f03d3e36d2e9d82608 ``` The definition for the event we expect to see, [from the `L2ToL2CrossDomainMessenger` source code](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L160). - ```sh file=/public/tutorials/setup-for-testing.sh#L119-L121 hash=645c522fafccb282df37b7d3df27bd3f + ```solidity file=/public/tutorials/setup-for-testing.sh#L119-L121 hash=645c522fafccb282df37b7d3df27bd3f ``` Create a new `GreetingSender` instance for each test. - ```sh file=/public/tutorials/setup-for-testing.sh#L124-L129 hash=5e79ce67c4e5f54eee5b8d09ace39860 + ```solidity file=/public/tutorials/setup-for-testing.sh#L124-L129 hash=5e79ce67c4e5f54eee5b8d09ace39860 ``` Calculate the message to be sent, the same way that `GreetingSender` does. - ```sh file=/public/tutorials/setup-for-testing.sh#L132-L132 hash=028411291cccc262557abde834549fc2 + ```solidity file=/public/tutorials/setup-for-testing.sh#L132-L132 hash=028411291cccc262557abde834549fc2 ``` Out of the indexed topics, verify the first (destination chain) and second (address on the destination chain). Ignore the third topic, the nonce, because it can vary. Finally, verify that the unindexed data of the log entry (the sender address and the message) is correct. - ```sh file=/public/tutorials/setup-for-testing.sh#L133-L133 hash=37203df9264e95e763befaf2e5dbbfab + ```solidity file=/public/tutorials/setup-for-testing.sh#L133-L133 hash=37203df9264e95e763befaf2e5dbbfab ``` Emit the message we expect to see. - ```sh file=/public/tutorials/setup-for-testing.sh#L135-L135 hash=9322933b2f965ddc75bb8d3b2ab4c95d + ```solidity file=/public/tutorials/setup-for-testing.sh#L135-L135 hash=9322933b2f965ddc75bb8d3b2ab4c95d ``` Call the code being tested, which should emit a similar log entry to the one we just emitted. @@ -110,33 +110,39 @@ The test is implemented by `tests/Greeter.t.sol`.
Explanation - ```sh file=/public/tutorials/setup-for-testing.sh#L171 hash=d9bb7b8ca88e8856bd86c256934a0b0b + ```solidity file=/public/tutorials/setup-for-testing.sh#L171 hash=d9bb7b8ca88e8856bd86c256934a0b0b ``` This function sets up the environment for a pretend interop call. - ```sh file=/public/tutorials/setup-for-testing.sh#L172-L182 hash=65aae51c8573ecb296b942c7073a3379 + ```solidity file=/public/tutorials/setup-for-testing.sh#L172-L182 hash=65aae51c8573ecb296b942c7073a3379 ``` Use [`vm.mockCall`](https://book.getfoundry.sh/reference/cheatcodes/mock-call) to specify the responses to calls to `L2ToL2CrossDomainMessenger`. - ```sh file=/public/tutorials/setup-for-testing.sh#L183-L187 hash=478229c219493adbbfea088cf266dec5 + ```solidity file=/public/tutorials/setup-for-testing.sh#L183-L187 hash=478229c219493adbbfea088cf266dec5 ``` At writing `crossDomainMessageContext` is not available in the [contracts npm package](https://www.npmjs.com/package/@eth-optimism/contracts-bedrock), so we calculate the selector directly using `bytes4(keccak256("crossDomainMessageContext()"))`. - ```sh file=/public/tutorials/setup-for-testing.sh#L188-L189 hash=18498ce1031cf749a13f6207d0828ca7 + ```solidity file=/public/tutorials/setup-for-testing.sh#L188-L189 hash=18498ce1031cf749a13f6207d0828ca7 ``` Use [`vm.prank`](https://book.getfoundry.sh/reference/cheatcodes/prank) to make it appear the tested code is called by `L2ToL2CrossDomainMessenger`. - ```sh file=/public/tutorials/setup-for-testing.sh#L191-L201 hash=035afa3348edfa18a0be06b9f9991c38 + ```solidity file=/public/tutorials/setup-for-testing.sh#L191-L201 hash=035afa3348edfa18a0be06b9f9991c38 ``` Test how `Greeter` acts when the greeting is set from another chain. - ```sh file=/public/tutorials/setup-for-testing.sh#L203-L210 hash=ea83b0fcf27566b5ae9221d1091bfc6b + ```solidity file=/public/tutorials/setup-for-testing.sh#L203-L210 hash=ea83b0fcf27566b5ae9221d1091bfc6b ``` Test how `Greeter` acts when the greeting is set from this chain.
+ + +## Next steps + +* Write a revolutionary app that uses multiple blockchains within the Superchain. +* Write tests to make sure it works correctly. \ No newline at end of file diff --git a/pages/interop/tutorials/unit-tests/hardhat.mdx b/pages/interop/tutorials/unit-tests/hardhat.mdx index b787e3624..93fc254ce 100644 --- a/pages/interop/tutorials/unit-tests/hardhat.mdx +++ b/pages/interop/tutorials/unit-tests/hardhat.mdx @@ -34,5 +34,156 @@ Execute it in a UNIX or Linux environment. The results of this step are similar to what the [message passing tutorial](/interop/tutorials/message-passing) produces. -```sh file=/public/tutorials/setup-for-testing.sh hash=1a87986e9f78d6d233d9f1ebb4022c7c +```sh file=/public/tutorials/setup-for-testing.sh hash=4d0fa175564131911ab6a12fb110294c ``` + +## Test sending a message + +The easiest way to test sending a message is to see [the event emitted by `L2ToL2CrossDomainMessenger.sendMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L160). + +To see this in action, run these commands: + +```sh +cd testing/hardhat +npx hardhat test test/GreetingSender.js +``` + +Of course, Hardhat does not include the interop contracts by default. +To have `L2ToL2CrossDomainMessenger.sendMessage` we fork [a blockchain that does have it](/interop/tools/devnet). +This is specified in `hardhat.config.js`. + +The test is implemented by `test/GreetingSender.js`. + +
+ Explanation + + ```js file=/public/tutorials/setup-for-testing.sh#L258-L264 hash=3f669191f745ca77f1186d5d6b8dd062 + ``` + + Deploy a `GreetingSender`. + + ```js file=/public/tutorials/setup-for-testing.sh#L266-L270 hash=40785947670a88582c43f31e37d7cb28 + ``` + + Create a contract object for `L2ToL2CrossDomainMessenger`. + + ```js file=/public/tutorials/setup-for-testing.sh#L280-L286 hash=80f81c9dafbea8a958f0bfacb12e9389 + ``` + + Calculate the calldata that will be sent by `L2ToL2CrossDomainMessenger`. + + ```js file=/public/tutorials/setup-for-testing.sh#L288 hash=ea3c2728d499ef1536178d53fdb5497a + ``` + + The operation we're testing, `greetingSender.setGreeting(greeting)`. + + ```js file=/public/tutorials/setup-for-testing.sh#L289 hash=76eeeefe7b7605474ab8e43105e7dc0d + ``` + + The expected result, to have the `messenger` contract emit a `SentMessage` log entry. + + ```js file=/public/tutorials/setup-for-testing.sh#L290-L296 hash=14bf71dc909944de148fda7bcc4d0f2d + ``` + + The parameters in the log entry. + We use `anyValue` for the nonce because we do not know in advance what value it would be. + +
+ +## Test receiving a message + +To simulate receiving a message, we need to ensure two conditions are fulfilled: + +* The tested code is called by [`L2ToL2CrossDomainMessenger`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol). +* The tested code can receive additional information through simulations of: + * [`L2ToL2CrossDomainMessenger.crossDomainMessageSender`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L102-L108) + * [`L2ToL2CrossDomainMessenger.crossDomainMessageSource`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L110-L116) + * [`L2ToL2CrossDomainMessenger.crossDomainMessageContext`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L118-L126) + +To see this in action, run these commands: + +``` +cd testing/hardhat +npx hardhat test test/Greeter.js +``` + +This test is implemented by two files, `contracts/MockL2ToL2Messenger.sol` which replaces `L2ToL2CrossDomainMessenger` with a contract we control, and `test/Greeter.js` which actually has the tests. + +
+ Explanation of `contracts/MockL2ToL2Messenger.sol` + + ```solidity file=/public/tutorials/setup-for-testing.sh#L374-L380 hash=870b143463550d8f0915a4db9d584cea + ``` + + When the tested code receive a message, these are the source chain and address where it originates. + + ```solidity file=/public/tutorials/setup-for-testing.sh#L382-L392 hash=7f9cf709fa17ce391ec40728267b82a0 + ``` + + These are the three functions we need to implement for tested code, such as `Greeter`, to call. + + ```solidity file=/public/tutorials/setup-for-testing.sh#L394-L408 hash=13b29fd8bbcccfc6c7a5201f5d316d0a + ``` + + Because we are replacing the `L2ToL2CrossDomainMessenger` with this contract, and the orer in which tests are executed is not deterministic, we need this contract to work for the `GreetingSender` test. + The code here is copied from [`L2ToL2CrossDomainMessenger.sendMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L128-L161), with the irrelevant parts removed. + + ```solidity file=/public/tutorials/setup-for-testing.sh#L410-L413 hash=0797417fc01fcc3a27511f55729e1cbe + ``` + + The interop message `Greeter` gets has to come from the `L2ToL2CrossDomainMessenger` address. + We can either send a transaction into `MockL2ToL2Messenger` that then calls `Greeter`, or give the `L2ToL2CrossDomainMessenger` address some ETH and send the transaction directly from it. + This function enables us to give the contract ETH. + +
+ +
+ Explanation of `test/Greeter.js` + + ```js file=/public/tutorials/setup-for-testing.sh#L310 hash=6fd176fc44208d2f92f0210015c8e806 + ``` + + This function deploys the fixtures we need to run the tests. + + ```js file=/public/tutorials/setup-for-testing.sh#L312-L319 hash=7d218ce8fead9bc8412e79303d026c16 + ``` + + This is the code that first deploys `MockL2ToL2Messenger` and then tells Hardhat to direct calls to the `L2ToL2CrossDomainMessenger` contract to it instead. + + ```js file=/public/tutorials/setup-for-testing.sh#L321-L322 hash=b6df4166a44f7b5f006d269f97a4e34a + ``` + + Deploy a `Greeter` to test. + + ```js file=/public/tutorials/setup-for-testing.sh#L324-L328 hash=ee7023cfaf1b9672914aa77b75e77285 + ``` + + Create a contract object for `L2ToL2CrossDomainMessenger`. + + ```js file=/public/tutorials/setup-for-testing.sh#L334-L340 hash=d44100c903a4fd42aedadce81455226a + ``` + + Run the test for local messages. + + ```js file=/public/tutorials/setup-for-testing.sh#L347-L352 hash=b37199ac43cee36514ab508d763049f8 + ``` + + Create an object for `MockL2ToL2Messenger` and give it some ETH to be able to send transactions. + + ```js file=/public/tutorials/setup-for-testing.sh#L354-L358 hash=7ae6ae561d95426670ea1d0311bc9711 + ``` + + Test that when receiving an interop message, `Greeter` still emits `SetGreeting` correctly. + + ```js file=/public/tutorials/setup-for-testing.sh#L360-L364 hash=e0b49ce1ca70cc58378abcfba8d1d2ca + ``` + + Test that when receiving an interop, `Greeter` also emits `CrossDomainSetGreeting`. + +
+ + +## Next steps + +* Write a revolutionary app that uses multiple blockchains within the Superchain. +* Write tests to make sure it works correctly. \ No newline at end of file diff --git a/public/tutorials/setup-for-testing.sh b/public/tutorials/setup-for-testing.sh index 18b1aeb48..9580c138c 100644 --- a/public/tutorials/setup-for-testing.sh +++ b/public/tutorials/setup-for-testing.sh @@ -351,15 +351,14 @@ describe("Greeter", () => { value: ethers.parseEther("1.0") }); - await expect( - greeter.connect(impersonatedMessenger).setGreeting(greeting) + greeter.connect(impersonatedMessenger).setGreeting(greeting) ) .to.emit(greeter, "SetGreeting") .withArgs(contracts.l2ToL2CrossDomainMessenger.address, greeting); await expect( - greeter.connect(impersonatedMessenger).setGreeting(greeting) + greeter.connect(impersonatedMessenger).setGreeting(greeting) ) .to.emit(greeter, "CrossDomainSetGreeting") .withArgs(fakeSender, fakeSourceChain, greeting); From 75319c125ee7da20fad39f9ff3219803459d13fb Mon Sep 17 00:00:00 2001 From: Ori Pomerantz Date: Sun, 8 Jun 2025 14:57:29 -0500 Subject: [PATCH 08/11] Auto-fix: Update breadcrumbs, spelling dictionary and other automated fixes --- pages/interop/tutorials/unit-tests/foundry.mdx | 3 +-- pages/interop/tutorials/unit-tests/hardhat.mdx | 14 +++++--------- words.txt | 1 + 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/pages/interop/tutorials/unit-tests/foundry.mdx b/pages/interop/tutorials/unit-tests/foundry.mdx index a837217d6..a52b08c19 100644 --- a/pages/interop/tutorials/unit-tests/foundry.mdx +++ b/pages/interop/tutorials/unit-tests/foundry.mdx @@ -141,8 +141,7 @@ The test is implemented by `tests/Greeter.t.sol`. Test how `Greeter` acts when the greeting is set from this chain.
- ## Next steps * Write a revolutionary app that uses multiple blockchains within the Superchain. -* Write tests to make sure it works correctly. \ No newline at end of file +* Write tests to make sure it works correctly. diff --git a/pages/interop/tutorials/unit-tests/hardhat.mdx b/pages/interop/tutorials/unit-tests/hardhat.mdx index 93fc254ce..77e50235a 100644 --- a/pages/interop/tutorials/unit-tests/hardhat.mdx +++ b/pages/interop/tutorials/unit-tests/hardhat.mdx @@ -48,7 +48,7 @@ cd testing/hardhat npx hardhat test test/GreetingSender.js ``` -Of course, Hardhat does not include the interop contracts by default. +Of course, Hardhat does not include the interop contracts by default. To have `L2ToL2CrossDomainMessenger.sendMessage` we fork [a blockchain that does have it](/interop/tools/devnet). This is specified in `hardhat.config.js`. @@ -87,7 +87,6 @@ The test is implemented by `test/GreetingSender.js`. The parameters in the log entry. We use `anyValue` for the nonce because we do not know in advance what value it would be. - ## Test receiving a message @@ -131,10 +130,9 @@ This test is implemented by two files, `contracts/MockL2ToL2Messenger.sol` which ```solidity file=/public/tutorials/setup-for-testing.sh#L410-L413 hash=0797417fc01fcc3a27511f55729e1cbe ``` - The interop message `Greeter` gets has to come from the `L2ToL2CrossDomainMessenger` address. + The interop message `Greeter` gets has to come from the `L2ToL2CrossDomainMessenger` address. We can either send a transaction into `MockL2ToL2Messenger` that then calls `Greeter`, or give the `L2ToL2CrossDomainMessenger` address some ETH and send the transaction directly from it. This function enables us to give the contract ETH. -
@@ -158,7 +156,7 @@ This test is implemented by two files, `contracts/MockL2ToL2Messenger.sol` which ```js file=/public/tutorials/setup-for-testing.sh#L324-L328 hash=ee7023cfaf1b9672914aa77b75e77285 ``` - Create a contract object for `L2ToL2CrossDomainMessenger`. + Create a contract object for `L2ToL2CrossDomainMessenger`. ```js file=/public/tutorials/setup-for-testing.sh#L334-L340 hash=d44100c903a4fd42aedadce81455226a ``` @@ -166,7 +164,7 @@ This test is implemented by two files, `contracts/MockL2ToL2Messenger.sol` which Run the test for local messages. ```js file=/public/tutorials/setup-for-testing.sh#L347-L352 hash=b37199ac43cee36514ab508d763049f8 - ``` + ``` Create an object for `MockL2ToL2Messenger` and give it some ETH to be able to send transactions. @@ -179,11 +177,9 @@ This test is implemented by two files, `contracts/MockL2ToL2Messenger.sol` which ``` Test that when receiving an interop, `Greeter` also emits `CrossDomainSetGreeting`. -
- ## Next steps * Write a revolutionary app that uses multiple blockchains within the Superchain. -* Write tests to make sure it works correctly. \ No newline at end of file +* Write tests to make sure it works correctly. diff --git a/words.txt b/words.txt index 53a585a4a..139a1bc1f 100644 --- a/words.txt +++ b/words.txt @@ -273,6 +273,7 @@ opcm Openfort oplabs opnode's +orer outfile Pausability pcscdpath From 639d45bcaf6bf4f3059e3bf67451f9dffc0d7b23 Mon Sep 17 00:00:00 2001 From: Ori Pomerantz Date: Sun, 8 Jun 2025 19:51:57 -0500 Subject: [PATCH 09/11] Typo --- pages/interop/tutorials/unit-tests/hardhat.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/interop/tutorials/unit-tests/hardhat.mdx b/pages/interop/tutorials/unit-tests/hardhat.mdx index 77e50235a..d7a2ea135 100644 --- a/pages/interop/tutorials/unit-tests/hardhat.mdx +++ b/pages/interop/tutorials/unit-tests/hardhat.mdx @@ -124,7 +124,7 @@ This test is implemented by two files, `contracts/MockL2ToL2Messenger.sol` which ```solidity file=/public/tutorials/setup-for-testing.sh#L394-L408 hash=13b29fd8bbcccfc6c7a5201f5d316d0a ``` - Because we are replacing the `L2ToL2CrossDomainMessenger` with this contract, and the orer in which tests are executed is not deterministic, we need this contract to work for the `GreetingSender` test. + Because we are replacing the `L2ToL2CrossDomainMessenger` with this contract, and the order in which tests are executed is not deterministic, we need this contract to work for the `GreetingSender` test. The code here is copied from [`L2ToL2CrossDomainMessenger.sendMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L128-L161), with the irrelevant parts removed. ```solidity file=/public/tutorials/setup-for-testing.sh#L410-L413 hash=0797417fc01fcc3a27511f55729e1cbe @@ -176,7 +176,7 @@ This test is implemented by two files, `contracts/MockL2ToL2Messenger.sol` which ```js file=/public/tutorials/setup-for-testing.sh#L360-L364 hash=e0b49ce1ca70cc58378abcfba8d1d2ca ``` - Test that when receiving an interop, `Greeter` also emits `CrossDomainSetGreeting`. + Test that when receiving an interop message, `Greeter` also emits `CrossDomainSetGreeting`. ## Next steps From ebae0a58eb1b321a2f65f2fe7155fc904b4981e1 Mon Sep 17 00:00:00 2001 From: Ori Pomerantz Date: Sun, 8 Jun 2025 19:54:13 -0500 Subject: [PATCH 10/11] Words --- words.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/words.txt b/words.txt index 139a1bc1f..53a585a4a 100644 --- a/words.txt +++ b/words.txt @@ -273,7 +273,6 @@ opcm Openfort oplabs opnode's -orer outfile Pausability pcscdpath From 746e01d96f4f72f4e08348231b2ff6bb363b5198 Mon Sep 17 00:00:00 2001 From: Ori Pomerantz Date: Tue, 10 Jun 2025 09:31:38 -0700 Subject: [PATCH 11/11] Coderabbit Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- pages/interop/tutorials/unit-tests/foundry.mdx | 4 ++-- pages/interop/tutorials/unit-tests/hardhat.mdx | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pages/interop/tutorials/unit-tests/foundry.mdx b/pages/interop/tutorials/unit-tests/foundry.mdx index a52b08c19..bf5f7156f 100644 --- a/pages/interop/tutorials/unit-tests/foundry.mdx +++ b/pages/interop/tutorials/unit-tests/foundry.mdx @@ -23,8 +23,8 @@ import { InteropCallout } from '@/components/WipCallout' # Interop and unit tests using Foundry -Most of parts of the contracts can be [tested normally](/app-developers/testing-apps). -This tutorials teaches you how to verify that a message has been sent successfully, and how to fake receiving a message, the two functions that tie directly into interop. +Most parts of the contracts can be [tested normally](/app-developers/testing-apps). +This tutorial teaches you how to verify that a message has been sent successfully and to simulate receiving a message, the two functions that tie directly into interop. To show how this works, we test [the `Greeter` and `GreetingSender` contracts](/interop/tutorials/message-passing). ## Setup diff --git a/pages/interop/tutorials/unit-tests/hardhat.mdx b/pages/interop/tutorials/unit-tests/hardhat.mdx index d7a2ea135..1a58bc7c8 100644 --- a/pages/interop/tutorials/unit-tests/hardhat.mdx +++ b/pages/interop/tutorials/unit-tests/hardhat.mdx @@ -12,7 +12,7 @@ categories: - cross-chain-messaging - tutorial - testing - - foundry + - hardhat is_imported_content: 'false' --- @@ -23,8 +23,8 @@ import { InteropCallout } from '@/components/WipCallout' # Interop and unit tests using Hardhat -Most of parts of the contracts can be [tested normally](/app-developers/testing-apps). -This tutorials teaches you how to verify that a message has been sent successfully, and how to fake receiving a message, the two functions that tie directly into interop. +Most parts of the contracts can be [tested normally](/app-developers/testing-apps). +This tutorial teaches you how to verify that a message has been sent successfully and to simulate receiving a message, the two functions that tie directly into interop. To show how this works, we test [the `Greeter` and `GreetingSender` contracts](/interop/tutorials/message-passing). ## Setup