Skip to content
This repository was archived by the owner on Dec 12, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[submodule "cross-dom-comm/foundry/lib/forge-std"]
path = cross-dom-comm/foundry/lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "getting-started/foundry/lib/forge-std"]
path = getting-started/foundry/lib/forge-std
url = https://github.com/foundry-rs/forge-std
2 changes: 0 additions & 2 deletions cross-dom-comm/.env.example

This file was deleted.

8 changes: 8 additions & 0 deletions cross-dom-comm/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,11 @@ node_modules
#Hardhat files
cache
artifacts


# Foundry files
out

#We don't want the mnemonic file
mnem.delme

157 changes: 116 additions & 41 deletions cross-dom-comm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,89 +10,94 @@ You will learn how run a contract on Ethereum that runs another contract on Opti

## Seeing it in action

To show how this works we installed [a slightly modified version of HardHat's `Greeter.sol`](contracts/Greeter.sol) on both L1 Kovan and Optimistic Kovan
To show how this works we installed [a slightly modified version of HardHat's `Greeter.sol`](hardhat/contracts/Greeter.sol) on both L1 Goerli and Optimistic Goerli


| Network | Greeter address |
| ------- | ---------------- |
| Kovan (L1) | [0x11fB328D5Bd8E27917535b6d40b881d35BC39Be0](https://kovan.etherscan.io/address/0x11fB328D5Bd8E27917535b6d40b881d35BC39Be0) |
| Optimistic Kovan (L2) | [0xD4c204223d6F1Dfad0b7a0b05BB0bCaB6665e0c9](https://kovan-optimistic.etherscan.io/address/0xD4c204223d6F1Dfad0b7a0b05BB0bCaB6665e0c9) |
| Goerli (L1) | [0x7fA4D972bB15B71358da2D937E4A830A9084cf2e](https://goerli.etherscan.io/address/0x7fA4D972bB15B71358da2D937E4A830A9084cf2e) |
| Optimistic Goerli (L2) | [0xC0836cCc8FBa87637e782Dde6e6572aD624fb984](https://blockscout.com/optimism/goerli/address/0xC0836cCc8FBa87637e782Dde6e6572aD624fb984) |

::: Tip What if somebody else uses the same contracts at the same time?
If somebody else uses these contracts while you are going through the tutorial, they might update the greeting after you.
In that case you'll see the wrong greeting when you call the `Greeter` contract.
However, you can still verify your controller works in one of two ways:
1. Find the transaction on either [Kovan Etherscan](https://kovan.etherscan.io/address/0x11fB328D5Bd8E27917535b6d40b881d35BC39Be0#internaltx) or [Optimistic Kovan Etherscan]https://kovan-optimistic.etherscan.io/address/0xD4c204223d6F1Dfad0b7a0b05BB0bCaB6665e0c9#internaltx).
1. Find the transaction on either [Goerli Etherscan](https://goerli.etherscan.io/address/0x7fA4D972bB15B71358da2D937E4A830A9084cf2e#internaltx) or [Optimistic Goerli BlockScount](https://blockscout.com/optimism/goerli/address/0xC0836cCc8FBa87637e782Dde6e6572aD624fb984/internal-transactions#address-tabs).
In either case, it will be an internal transaction because the contract called directly is the cross domain messenger.
1. Just try again.
:::

### Setup
### Hardhat

This is how you can see communication between domains work in hardhat.

#### Setup

This setup assumes you already have [Node.js](https://nodejs.org/en/) and [yarn](https://classic.yarnpkg.com/) installed on your system.

1. Copy `.env.example` to `.env` and edit it:

1. Set `MNEMONIC` to point to an account that has ETH on the Kovan test network.
1. Set `KOVAN_URL` to point to a URL that accesses the Kovan test network.
1. Set `MNEMONIC` to point to an account that has ETH on the Goerli test network as well as the Optimistic Goerli test network.
1. Set `GOERLI_URL` to point to a URL that accesses the Goerli test network.
1. Set `OPTI_GOERLI_URL` to point to a URL that accesses the Goerli test network.

1. Install the necessary packages.

```sh
yarn
```

### Ethereum message to Optimism
#### Ethereum message to Optimism

1. [Browse to the Greeter contract on Etherscan](https://kovan-optimistic.etherscan.io/address/0xD4c204223d6F1Dfad0b7a0b05BB0bCaB6665e0c9#readContract) and click **greet** to see the greeting.
1. [Browse to the Greeter contract on BlockScout](https://blockscout.com/optimism/goerli/address/0xC0836cCc8FBa87637e782Dde6e6572aD624fb984/read-contract#address-tabs) to see the result of **greet**.

1. Connect the Hardhat console to Kovan (L1):

```sh
yarn hardhat console --network kovan
yarn hardhat console --network goerli
```

1. Deploy and call the `ControlL2Greeter` contract.
1. Deploy and call the `FromL2_ControlL2Greeter` contract.

```js
Controller = await ethers.getContractFactory("ControlL2Greeter")
Controller = await ethers.getContractFactory("FromL2_ControlL2Greeter")
controller = await Controller.deploy()
tx = await controller.setGreeting("Shalom")
rcpt = await tx.wait()
```

1. Make a note of the address of `ControlL2Greeter`.
1. Make a note of the address of `FromL2_ControlL2Greeter`.

```js
controller.address
```

1. [Browse to the Greeter contract on Etherscan](https://kovan-optimistic.etherscan.io/address/0xD4c204223d6F1Dfad0b7a0b05BB0bCaB6665e0c9#readContract) and click **greet** to see the new greeting.
1. [Browse to the Greeter contract on Etherscan](https://blockscout.com/optimism/goerli/address/0xC0836cCc8FBa87637e782Dde6e6572aD624fb984/read-contract#address-tabs) to see the new greeting.



### Optimism message to Ethereum
#### Optimism message to Ethereum

#### Send the message
##### Send the message

1. [Browse to the Greeter contract on Etherscan](https://kovan.etherscan.io/address/0x11fB328D5Bd8E27917535b6d40b881d35BC39Be0#readContract) and click **greet** to see the greeting.
1. [Browse to the Greeter contract on Etherscan](https://goerli.etherscan.io/address/0x7fA4D972bB15B71358da2D937E4A830A9084cf2e#readContract) and click **greet** to see the greeting.

1. Connect the Hardhat console to Optimistic Kovan (L2):
1. Connect the Hardhat console to Optimistic Goerli (L2):

```sh
yarn hardhat console --network optimistic-kovan
yarn hardhat console --network optimistic-goerli
```

1. Deploy and call the `ControlL1Greeter` contract.
1. Deploy and call the `FromL2_ControlL1Greeter` contract.

```js
Controller = await ethers.getContractFactory("ControlL1Greeter")
Controller = await ethers.getContractFactory("FromL2_ControlL1Greeter")
controller = await Controller.deploy()
tx = await controller.setGreeting("Shalom")
rcpt = await tx.wait()
```

1. Make a note of the address of `ControlL1Greeter`.
1. Make a note of the address of `FromL2_ControlL1Greeter`.

```js
controller.address
Expand All @@ -104,18 +109,18 @@ This setup assumes you already have [Node.js](https://nodejs.org/en/) and [yarn]
tx.hash
```

#### Receive the message
##### Receive the message

Transactions from Optimism to Ethereum are not accepted immediately, because we need to wait [to make sure there are no successful challenges](https://community.optimism.io/docs/how-optimism-works/#fault-proofs).
Once the fault challenge period is over (one minute on Kovan, seven days on the production network) it is necessary to claim the transaction on L1.
This is a complex process that requires a [Merkle proof](https://medium.com/crypto-0-nite/merkle-proofs-explained-6dd429623dc5).
You can do it using [the Optimism SDK](https://www.npmjs.com/package/@eth-optimism/sdk).


1. Connect the Hardhat console to Kovan (L1):
1. Connect the Hardhat console to Goerli (L1):

```sh
yarn hardhat console --network kovan
yarn hardhat console --network goerli
```

1. Get the SDK (it is already in `node_modules`).
Expand All @@ -128,9 +133,9 @@ You can do it using [the Optimism SDK](https://www.npmjs.com/package/@eth-optimi

```js
l1Signer = await ethers.getSigner()
crossChainMessenger = new sdk.CrossChainMessenger({ l1ChainId: 42,
crossChainMessenger = new sdk.CrossChainMessenger({ l1ChainId: 5,
l1SignerOrProvider: l1Signer,
l2SignerOrProvider: new ethers.providers.JsonRpcProvider("https://kovan.optimism.io")
l2SignerOrProvider: new ethers.providers.JsonRpcProvider("https://goerli.optimism.io")
})
```

Expand All @@ -148,13 +153,76 @@ You can do it using [the Optimism SDK](https://www.npmjs.com/package/@eth-optimi
(await crossChainMessenger.finalizeMessage(hash))
```

1. To verify the change, [browse to the Greeter contract on Etherscan](https://kovan.etherscan.io/address/0x11fB328D5Bd8E27917535b6d40b881d35BC39Be0#readContract) again and click **greet** to see the new greeting.
1. To verify the change, [browse to the Greeter contract on Etherscan](https://goerli.etherscan.io/address/0x7fA4D972bB15B71358da2D937E4A830A9084cf2e#readContract) again and click **greet** to see the new greeting.


### Foundry

#### Setup

1. Install the `@eth-optimims/contracts` library (assuming you already have Noe.js and yarn):

```sh
cd foundry/lib
yarn
```

1. Create environment variables for the URLs for Goerli and Optimistic Goerli:

```sh
cd ..
GOERLI_URL= ...
OPTI_GOERLI_URL= ...
```

1. Create environment variables for the Greeter contract's addresses

```sh
GREETER_L1=0x7fA4D972bB15B71358da2D937E4A830A9084cf2e
GREETER_L2=0xC0836cCc8FBa87637e782Dde6e6572aD624fb984
```

1. Put your account mnemonic in the file `mnem.delme`.


#### Control the L2 Greeter from L1

1. See the current greeting.

```sh
cast call --rpc-url $OPTI_GOERLI_URL $GREETER_L2 "greet()" | cast --to-ascii
```

1. Deploy the `FromL1_ControlL2Greeter` contract.

```sh
forge create FromL1_ControlL2Greeter --rpc-url $GOERLI_URL --mnemonic-path mnem.delme
```

1. Create an environment variable for the `Deployed to:` address:

```sh
CONTROLLER= << address >>
```

1. Send a transaction to change the L2 greeting:

```sh
cast send --rpc-url $GOERLI_URL --gas-limit 150000 \
--mnemonic-path mnem.delme \
$CONTROLLER "setGreeting(string)" '"Salam"'
```

1. See the greeting has changed. Note that the change might take a few minutes to propagate.

```sh
cast call --rpc-url $OPTI_GOERLI_URL $GREETER_L2 "greet()" | cast --to-ascii
```

## How it's done (in Solidity)

We'll go over the L1 contract that controls Greeter on L2, [`ControlL2Greeter.sol`](contracts/ControlL2Greeter.sol).
Except for addresses, the contract going the other direction, [`ControlL1Greeter.sol`](contracts/ControlL21reeter.sol), is identical.
We'll go over the L1 contract that controls Greeter on L2, [`FromL1_ControlL2Greeter.sol`](hardhat/contracts/FromL1_ControlL2Greeter.sol).
Except for addresses, the contract going the other direction, [`FromL2_ControlL1Greeter.sol`](hardhat/contracts/FromL2_ControlL21reeter.sol), is identical.

```solidity
//SPDX-License-Identifier: Unlicense
Expand All @@ -169,19 +237,19 @@ This line imports the interface to send messages, [`ICrossDomainMessenger.sol`](


```solidity
contract ControlL2Greeter {
contract FromL1_ControlL2Greeter {
address crossDomainMessengerAddr = 0x4361d0F75A0186C05f971c566dC6bEa5957483fD;
```

This is the address of [`Proxy_OVM_L1CrossDomainMessenger`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/deployments/kovan/Proxy__OVM_L1CrossDomainMessenger.json#L2) on Kovan.
This is the address of [`Proxy_OVM_L1CrossDomainMessenger`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/deployments/goerli/Proxy__OVM_L1CrossDomainMessenger.json#L2) on Kovan.
To call L2 from L1 on mainnet, you need to [use this address](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/deployments/mainnet/Proxy__OVM_L1CrossDomainMessenger.json#L2).
To call L1 from L2, on either mainnet or Kovan, use the address of `L2CrossDomainMessenger`, 0x4200000000000000000000000000000000000007.

```solidity
address greeterL2Addr = 0xD4c204223d6F1Dfad0b7a0b05BB0bCaB6665e0c9;
address greeterL2Addr = 0xC0836cCc8FBa87637e782Dde6e6572aD624fb984;
```

This is the address on which `Greeter` is installed on Optimistic Kovan.
This is the address on which `Greeter` is installed on Optimistic Goerli.


```solidity
Expand Down Expand Up @@ -225,13 +293,13 @@ This call actually sends the message. It gets three parameters:

```solidity
} // function setGreeting
} // contract ControlL2Greeter
} // contract FromL1_ControlL2Greeter
```


## Getting the source address

If you look at Etherscan, for either the [L1 Greeter](https://kovan.etherscan.io/address/0x11fB328D5Bd8E27917535b6d40b881d35BC39Be0#events) or the [L2 Greeter](https://kovan-optimistic.etherscan.io/address/0xD4c204223d6F1Dfad0b7a0b05BB0bCaB6665e0c9#events), you will see events with the source address on the other layer.
If you look at Etherscan, for either the [L1 Greeter](https://goerli.etherscan.io/address/0x7fA4D972bB15B71358da2D937E4A830A9084cf2e#events) or the [L2 Greeter](https://blockscout.com/optimism/goerli/address/0xC0836cCc8FBa87637e782Dde6e6572aD624fb984/logs#address-tabs), you will see events with the source address on the other layer.
The way this works is that the cross domain messenger that calls the target contract has a method, `xDomainMessageSender()`, that returns the source address. It is used by the `getXsource` function in `Greeter`.

```solidity
Expand All @@ -240,23 +308,30 @@ The way this works is that the cross domain messenger that calls the target cont
address cdmAddr = address(0);
```

It might look like it would be more efficient to calculate the address of the cross domain messanger just once, but that would involve changing the state, which is an expensive operation. This way it can be a `view` function without a gas cost.
It might look like it would be more efficient to calculate the address of the cross domain messanger just once, but that would involve changing the state, which is an expensive operation.
Unless we are going to run this code thousands of times, it is more efficient to just have a few `if` statements.

```solidity
// Mainnet
if (block.chainid == 1)
cdmAddr = 0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1;

// Kovan
if (block.chainid == 42)
cdmAddr = 0x4361d0F75A0186C05f971c566dC6bEa5957483fD;

// L2
if (block.chainid == 10 || block.chainid == 69)
// Goerli
if (block.chainid == 5)
cdmAddr = 0x5086d1eEF304eb5284A0f6720f79403b4e9bE294;

// L2 (same address on every network)
if (block.chainid == 10 || block.chainid == 69 || block.chainid == 420)
cdmAddr = 0x4200000000000000000000000000000000000007;

```

The three possibilities for the cross domain messenger's address.
On L2 Optimism has full control of the genesis block, so we can put all of our contracts on convenient addresses. L1 does not afford us this luxury.
There are three possibilities for the cross domain messenger's address on L1, because the address is not under our control.
On L2 Optimism has full control of the genesis block, so we can put all of our contracts on convenient addresses.

```solidity
// If this isn't a cross domain message
Expand Down
6 changes: 6 additions & 0 deletions cross-dom-comm/foundry/foundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[default]
src = 'src'
out = 'out'
libs = ['lib']

# See more config options https://github.com/foundry-rs/foundry/tree/master/config
1 change: 1 addition & 0 deletions cross-dom-comm/foundry/lib/forge-std
Submodule forge-std added at 6f3b43
5 changes: 5 additions & 0 deletions cross-dom-comm/foundry/lib/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"@eth-optimism/contracts": "^0.5.29"
}
}
Loading