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 22, 2024
1 parent 6a4c85f commit eee199a
Show file tree
Hide file tree
Showing 10 changed files with 238 additions and 68 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
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));
}
}
26 changes: 26 additions & 0 deletions evm/script/SetPeer.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// 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, address peerAddress) public {
_setPeer(wormholeTransceiver, peerChain, peerAddress);
}

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

function _setPeer(address wormholeTransceiver, uint16 peerChain, address peerAddress) internal {
WormholeTransceiver wormholeTransceiverContract = WormholeTransceiver(wormholeTransceiver);
wormholeTransceiverContract.setPeer(
peerChain, UniversalAddressLibrary.fromAddress(address(peerAddress)).toBytes32()
);
}
}
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=0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1 ./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,address)" $WT_ADDR $PEER_CHAIN_ID $PEER_ADDR \
--rpc-url $RPC_URL \
--private-key $MNEMONIC \
--broadcast
43 changes: 33 additions & 10 deletions evm/src/WormholeTransceiver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,43 @@ contract WormholeTransceiver is IWormholeTransceiver {
// =============== Storage ===============================================

bytes32 private constant WORMHOLE_PEERS_SLOT = bytes32(uint256(keccak256("whTransceiver.peers")) - 1);
bytes32 private constant CHAINS_SLOT = bytes32(uint256(keccak256("whTransceiver.chains")) - 1);

// =============== Storage Setters/Getters ========================================

function _getWormholePeersStorage() internal pure returns (mapping(uint16 => bytes32) storage $) {
function _getPeersStorage() internal pure returns (mapping(uint16 => bytes32) storage $) {
uint256 slot = uint256(WORMHOLE_PEERS_SLOT);
assembly ("memory-safe") {
$.slot := slot
}
}

function _getChainsStorage() internal pure returns (uint16[] storage $) {
uint256 slot = uint256(CHAINS_SLOT);
assembly ("memory-safe") {
$.slot := slot
}
}

// =============== Public Getters ======================================================

/// @inheritdoc IWormholeTransceiver
function getWormholePeer(uint16 chainId) public view returns (bytes32) {
return _getWormholePeersStorage()[chainId];
function getPeer(uint16 chainId) public view returns (bytes32) {
return _getPeersStorage()[chainId];
}

/// @inheritdoc IWormholeTransceiver
function getPeers() public view returns (PeerEntry[] memory results) {
uint16[] storage chains = _getChainsStorage();
uint256 len = chains.length;
results = new PeerEntry[](len);
for (uint256 idx = 0; idx < len;) {
results[idx].chain = chains[idx];
results[idx].addr = getPeer(chains[idx]);
unchecked {
++idx;
}
}
}

// =============== Admin ===============================================================
Expand Down Expand Up @@ -138,23 +160,24 @@ contract WormholeTransceiver is IWormholeTransceiver {
}

/// @inheritdoc IWormholeTransceiver
function setWormholePeer(uint16 peerChain, bytes32 peerContract) external payable onlyAdmin {
function setPeer(uint16 peerChain, bytes32 peerContract) external payable onlyAdmin {
if (peerChain == 0) {
revert InvalidWormholeChainZero();
}
if (peerContract == bytes32(0)) {
revert InvalidWormholePeerZeroAddress();
revert InvalidPeerZeroAddress();
}

bytes32 oldPeerContract = _getWormholePeersStorage()[peerChain];
bytes32 oldPeerContract = _getPeersStorage()[peerChain];

// SPEC: MUST not set the peer if it is already set.
if (oldPeerContract != bytes32(0)) {
revert PeerAlreadySet(peerChain, oldPeerContract);
}

_getWormholePeersStorage()[peerChain] = peerContract;
emit SetWormholePeer(peerChain, peerContract);
_getPeersStorage()[peerChain] = peerContract;
_getChainsStorage().push(peerChain);
emit SetPeer(peerChain, peerContract);
}

// =============== Interface ===============================================================
Expand Down Expand Up @@ -274,7 +297,7 @@ contract WormholeTransceiver is IWormholeTransceiver {

// Ensure that the message came from the registered peer contract.
if (!_verifyPeer(vm)) {
revert InvalidWormholePeer(vm.emitterChainId, vm.emitterAddress);
revert InvalidPeer(vm.emitterChainId, vm.emitterAddress);
}

emit MessageReceived(vm.hash, vm.emitterChainId, vm.emitterAddress, vm.sequence);
Expand All @@ -283,7 +306,7 @@ contract WormholeTransceiver is IWormholeTransceiver {

function _verifyPeer(IWormhole.VM memory vm) internal view returns (bool) {
checkFork(evmChain);
return getWormholePeer(vm.emitterChainId) == vm.emitterAddress;
return getPeer(vm.emitterChainId) == vm.emitterAddress;
}

function _checkLength(bytes memory payload, uint256 expected) private pure {
Expand Down
25 changes: 16 additions & 9 deletions evm/src/interfaces/IWormholeTransceiver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ pragma solidity >=0.8.8 <0.9.0;
import "example-gmp-router/interfaces/ITransceiver.sol";

interface IWormholeTransceiver is ITransceiver {
/// @notice Defines each entry in the array returned by getPeers.
struct PeerEntry {
uint16 chain;
bytes32 addr;
}

/// @notice Emitted when the admin is changed for an integrator.
/// @dev Topic0
/// 0x101b8081ff3b56bbf45deb824d86a3b0fd38b7e3dd42421105cf8abe9106db0b
Expand All @@ -29,7 +35,7 @@ interface IWormholeTransceiver is ITransceiver {
/// 0xa559263ee060c7a2560843b3a064ff0376c9753ae3e2449b595a3b615d326466
/// @param chainId The chain ID of the peer.
/// @param peerContract The address of the peer contract.
event SetWormholePeer(uint16 chainId, bytes32 peerContract);
event SetPeer(uint16 chainId, bytes32 peerContract);

/// @notice Emitted when a message is received.
/// @dev Topic0
Expand Down Expand Up @@ -82,7 +88,7 @@ interface IWormholeTransceiver is ITransceiver {

/// @notice Error the peer contract cannot be the zero address.
/// @dev Selector: 0x26e0c7de
error InvalidWormholePeerZeroAddress();
error InvalidPeerZeroAddress();

/// @notice The chain ID cannot be zero.
/// @dev Selector: 0x30dfa769
Expand All @@ -97,28 +103,29 @@ interface IWormholeTransceiver is ITransceiver {
/// @dev Selector: 0x79b1ce56
/// @param chainId The chain ID of the peer.
/// @param peerAddress The address of the invalid peer.
error InvalidWormholePeer(uint16 chainId, bytes32 peerAddress);
error InvalidPeer(uint16 chainId, bytes32 peerAddress);

/// @notice Length of transceiver payload is wrong.
/// @dev Selector: 0xc37906a0
/// @param received Number of payload bytes received.
/// @param expected Number of payload bytes expected.
error InvalidPayloadLength(uint256 received, uint256 expected);

/// @notice Get the corresponding Transceiver contract on other chains that have been registered
/// via governance. This design should be extendable to other chains, so each Transceiver would
/// be potentially concerned with Transceivers on multiple other chains.
/// @dev that peers are registered under Wormhole chain ID values.
/// @notice Get the peer Transceiver contract on the specified chain.
/// @param chainId The Wormhole chain ID of the peer to get.
/// @return peerContract The address of the peer contract on the given chain.
function getWormholePeer(uint16 chainId) external view returns (bytes32);
function getPeer(uint16 chainId) external view returns (bytes32);

/// @notice Returns an array of all the peers to which this transceiver is connected.
/// @return results An array of all of the connected peers including the chain id and contract address of each.
function getPeers() external view returns (PeerEntry[] memory results);

/// @notice Set the Wormhole peer contract for the given chain.
/// @dev This function is only callable by the `owner`.
/// Once the peer is set for a chain it may not be changed.
/// @param chainId The Wormhole chain ID of the peer to set.
/// @param peerContract The address of the peer contract on the given chain.
function setWormholePeer(uint16 chainId, bytes32 peerContract) external payable;
function setPeer(uint16 chainId, bytes32 peerContract) external payable;

/// @notice Receive an attested message from the verification layer.
/// This function should verify the `encodedVm` and then deliver the attestation
Expand Down
Loading

0 comments on commit eee199a

Please sign in to comment.