Skip to content

Commit

Permalink
EVM: Add deploy scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
bruce-riley committed Oct 23, 2024
1 parent 6a4c85f commit 39a6425
Show file tree
Hide file tree
Showing 11 changed files with 376 additions and 133 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/svm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
run: |
ANCHOR_VERSION="$(awk '/anchor_version =/ { print substr($3, 2, length($3)-2) }' Anchor.toml)"
echo "::set-output name=version::${ANCHOR_VERSION}"
- uses: evan-gray/anchor-test@24c04ecece7b484fa1218bab4318818b36436005
- uses: evan-gray/anchor-test@06370fbca011ee48b176211b8f858789d6c33282
with:
anchor-version: "${{steps.anchor.outputs.version}}"
solana-cli-version: "${{steps.solana.outputs.version}}"
Expand Down
6 changes: 3 additions & 3 deletions evm/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ cache/
out/

# Ignores development broadcast logs
!/broadcast
/broadcast/*/31337/
/broadcast/**/dry-run/
broadcast
broadcast/*/31337/
broadcast/**/dry-run/

# Docs
docs/
Expand Down
100 changes: 89 additions & 11 deletions evm/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,82 @@
## Foundry
# EVM Documentation

## Design

The WormholeTransceiver is responsible for sending and receiving messages for a Router via the Wormhole core network.

The WormholeTransceiver contract is associated with exactly one Router contract. It may be configured to support multiple peer transceivers with at most one per chain. All peer contracts must implement the WormholeTransceiver message format as defined in `_encodePayload`. The peers are added by an admin contract. Once a peer is set for a chain, it may not be updated.

It is expected that the Router will use this transceiver to send messages.

This transceiver expects to receive messages from external relayers. If a message is valid, the transceiver will attest it to the router.

Note that this transceiver does not do replay protection because that is done by the router.

### Constructor Parameters

All of these parameters are part of the contract state as public attributes so anyone may read them.

#### Chain Identifiers

The `ourChain` parameter specifies the Wormhole chain ID of the chain to which this WormholeTransceiver is deployed.

The `evmChain` parameters specifies the EVM chain ID of this chain. It is used to detect forks when attesting messages.

The chain values are immutable.

#### Router

A Router is the on-chain contract which will call `sendMessage` on the WormholeTransceiver. From the WormholeTransceiver perspective, the Router is the `msg.sender` of `sendMessage`. Additionally, the WormholeTransceiver will call `attestMessage` on the Router contract.

The Router contract must implement that `IRouterTransceiver` interface. The Router address is immutable.

#### Admin

The Admin contract is used to administer the WormholeTransceiver. The admin is the only contract that is allowed to call `setPeer`. Additionally, only the admin may call `updateAdmin`, `transferAdmin` and `discardAdmin` to update the admin contract.

#### Wormhole Contract

The Wormhole contract should be set to the canonical Wormhole Core contract on this chain. The Wormhole address is immutable. The WormholeTransceiver uses the Wormhole contract to quote the delivery price, send messages and validate received messages.

#### Consistency Level

The `consistencyLevel` parameter is passed into the `IWormhole` `publishMessage` call. It configures whether the Wormhole network should publish the message immediately (value 200), when the block is marked safe (value 201) or when the block is finalized (any other value). The consistency level is immutable.

### Contract Administration:

- The admin contract is set at construction time.
- Only the current admin may update the admin.
- The admin privileges may be transferred immediately using `updateAdmin`.
- The admin privileges may be transferred in a two step process using `transferAdmin`. This requires the new admin contract to call `claimAdmin` to actually become the admin contract.
- The current admin contract may cancel a transfer by calling `claimAdmin` with `msg.sender`.
- The current admin may discard the admin privileges by calling `discardAdmin`. This makes the WormholeTransceiver immutable, allowing not further peers to be set. THIS IS NOT REVERSIBLE.

### Other External Interfaces

- Any contract may call `getTransceiverType` to get the string identifier of this transceiver.
- Any contract may call `quoteDeliveryPrice` to compute the cost of delivering a router message to the specified peer.
- The Router may call `sendMessage` to send a message to a given connected peer.
- Any contract may call `receiveMessage` to post a message to the transceiver. If the message is valid, the WormholeTransceiver will call `attestMessage` on the Router.

- Any contract may call `getPeer` to determine if the WormholeTransceiver is connected to a given chain, and if so what is the peer address.
- Any contract may call `getPeers` to get a list of all connected peers.


### Message Format

The payload of the Wormhole messages consists of the following fields encoded using `abi.encodePacked`.

```code
UniversalAddress srcAddr,
uint64 sequence,
uint16 dstChain,
UniversalAddress dstAddr,
bytes32 payloadHash
```

## Development

### Foundry

**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.**

Expand All @@ -9,55 +87,55 @@ Foundry consists of:
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network.
- **Chisel**: Fast, utilitarian, and verbose solidity REPL.

## Documentation
### Documentation

https://book.getfoundry.sh/

## Usage
### Usage

### Build
#### Build

```shell
$ forge build
```

### Test
#### Test

```shell
$ forge test
```

### Format
#### Format

```shell
$ forge fmt
```

### Gas Snapshots
#### Gas Snapshots

```shell
$ forge snapshot
```

### Anvil
#### Anvil

```shell
$ anvil
```

### Deploy
#### Deploy

```shell
$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key>
```

### Cast
#### Cast

```shell
$ cast <subcommand>
```

### Help
#### Help

```shell
$ forge --help
Expand Down
12 changes: 0 additions & 12 deletions evm/script/Counter.s.sol

This file was deleted.

46 changes: 46 additions & 0 deletions evm/script/DeployWormholeTransceiver.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;

import {WormholeTransceiver} from "../src/WormholeTransceiver.sol";
import "forge-std/Script.sol";

// DeployWormholeTransceiver is a forge script to deploy the WormholeTransceiver contract. Use ./sh/deployWormholeTransceiver.sh to invoke this.
contract DeployWormholeTransceiver is Script {
function dryRun(
uint16 ourChain,
uint256 evmChain,
address admin,
address router,
address wormhole,
uint8 consistencyLevel
) public {
_deploy(ourChain, evmChain, admin, router, wormhole, consistencyLevel);
}

function run(
uint16 ourChain,
uint256 evmChain,
address admin,
address router,
address wormhole,
uint8 consistencyLevel
) public returns (address deployedAddress) {
vm.startBroadcast();
(deployedAddress) = _deploy(ourChain, evmChain, admin, router, wormhole, consistencyLevel);
vm.stopBroadcast();
}

function _deploy(
uint16 ourChain,
uint256 evmChain,
address admin,
address router,
address wormhole,
uint8 consistencyLevel
) internal returns (address deployedAddress) {
WormholeTransceiver wormholeTransceiver =
new WormholeTransceiver(ourChain, evmChain, admin, router, wormhole, consistencyLevel);

return (address(wormholeTransceiver));
}
}
24 changes: 24 additions & 0 deletions evm/script/SetPeer.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;

import {WormholeTransceiver} from "../src/WormholeTransceiver.sol";
import "forge-std/Script.sol";
import "example-gmp-router/libraries/UniversalAddress.sol";

// SetPeer is a forge script to set the peer for a given chain with the WormholeTransceiver contract. Use ./sh/setPeer.sh to invoke this.
contract SetPeer is Script {
function dryRun(address wormholeTransceiver, uint16 peerChain, bytes32 peerAddress) public {
_setPeer(wormholeTransceiver, peerChain, peerAddress);
}

function run(address wormholeTransceiver, uint16 peerChain, bytes32 peerAddress) public {
vm.startBroadcast();
_setPeer(wormholeTransceiver, peerChain, peerAddress);
vm.stopBroadcast();
}

function _setPeer(address wormholeTransceiver, uint16 peerChain, bytes32 peerAddress) internal {
WormholeTransceiver wormholeTransceiverContract = WormholeTransceiver(wormholeTransceiver);
wormholeTransceiverContract.setPeer(peerChain, peerAddress);
}
}
48 changes: 48 additions & 0 deletions evm/sh/deployWormholeTransceiver.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/bash

#
# This script deploys the WormholeTransceiver contract.
# Usage: RPC_URL= MNEMONIC= OUR_CHAIN_ID= EVM_CHAIN_ID= ADMIN= ROUTER= WORMHOLE= CONSISTENCY_LEVEL= ./sh/deployWormholeTransceiver.sh
# tilt: ROUTER=0x1aBE68277AE236083947f2551FEe8b885efCA8f5 ./sh/deployWormholeTransceiver.sh
#

[[ -z $ROUTER ]] && { echo "Missing ROUTER"; exit 1; }

if [ "${RPC_URL}X" == "X" ]; then
RPC_URL=http://localhost:8545
fi

if [ "${MNEMONIC}X" == "X" ]; then
MNEMONIC=0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d
fi

if [ "${OUR_CHAIN_ID}X" == "X" ]; then
OUR_CHAIN_ID=2
fi

if [ "${EVM_CHAIN_ID}X" == "X" ]; then
EVM_CHAIN_ID=1337
fi

if [ "${ADMIN}X" == "X" ]; then
ADMIN=0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1
fi

if [ "${WORMHOLE}X" == "X" ]; then
WORMHOLE=0xC89Ce4735882C9F0f0FE26686c53074E09B0D550
fi

if [ "${CONSISTENCY_LEVEL}X" == "X" ]; then
CONSISTENCY_LEVEL=200
fi

forge script ./script/DeployWormholeTransceiver.s.sol:DeployWormholeTransceiver \
--sig "run(uint16,uint256,address,address,address,uint8)" $OUR_CHAIN_ID $EVM_CHAIN_ID $ADMIN $ROUTER $WORMHOLE $CONSISTENCY_LEVEL \
--rpc-url "$RPC_URL" \
--private-key "$MNEMONIC" \
--broadcast ${FORGE_ARGS}

returnInfo=$(cat ./broadcast/DeployWormholeTransceiver.s.sol/$EVM_CHAIN_ID/run-latest.json)

DEPLOYED_ADDRESS=$(jq -r '.returns.deployedAddress.value' <<< "$returnInfo")
echo "Deployed transceiver address: $DEPLOYED_ADDRESS"
25 changes: 25 additions & 0 deletions evm/sh/setPeer.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/bash

#
# This script sets the peer for a given chain with the WormholeTransceiver contract.
# Usage: RPC_URL= MNEMONIC= WT_ADDR= PEER_CHAIN_ID= PEER_ADDR= ./sh/registerPeer.sh
# tilt: WT_ADDR=0x1aBE68277AE236083947f2551FEe8b885efCA8f5 PEER_CHAIN_ID=4 PEER_ADDR=0x00000000000000000000000090F8bf6A479f320ead074411a4B0e7944Ea8c9C1 ./sh/setPeer.sh
#

[[ -z $WT_ADDR ]] && { echo "Missing WT_ADDR"; exit 1; }
[[ -z $PEER_CHAIN_ID ]] && { echo "Missing PEER_CHAIN_ID"; exit 1; }
[[ -z $PEER_ADDR ]] && { echo "Missing PEER_ADDR"; exit 1; }

if [ "${RPC_URL}X" == "X" ]; then
RPC_URL=http://localhost:8545
fi

if [ "${MNEMONIC}X" == "X" ]; then
MNEMONIC=0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d
fi

forge script ./script/SetPeer.s.sol:SetPeer \
--sig "run(address,uint16,bytes32)" $WT_ADDR $PEER_CHAIN_ID $PEER_ADDR \
--rpc-url $RPC_URL \
--private-key $MNEMONIC \
--broadcast
Loading

0 comments on commit 39a6425

Please sign in to comment.