Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

evm: add forge deployment script #215

Merged
merged 13 commits into from
Mar 13, 2024
92 changes: 82 additions & 10 deletions evm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
A client calls on [`transfer`] to initiate an NTT transfer. The client must specify at minimum, the amount of the transfer, the recipient chain, and the recipient address on the recipient chain. [`transfer`] also supports a flag to specify whether the `NttManager` should queue rate-limited transfers or revert. Clients can also include additional instructions to forward along to the Transceiver on the source chain. Depending on mode set in the initial configuration of the `NttManager` contract, transfers are either "locked" or "burned". Once the transfer has been forwarded to the Transceiver, the `NttManager` emits the `TransferSent` event.

_Events_
``` solidity

```solidity
/// @notice Emitted when a message is sent from the nttManager.
/// @dev Topic0
/// 0x9716fe52fe4e02cf924ae28f19f5748ef59877c6496041b986fbad3dae6a8ecf
Expand All @@ -30,15 +31,16 @@ Similarly, transfers that are rate-limited on the destination chain are added to
If the client attempts to release the transfer from the queue before the expiry of the `rateLimitDuration`, the contract reverts with a `InboundQueuedTransferStillQueued` error.

_Events_
``` solidity

```solidity
/// @notice Emitted whenn an outbound transfer is queued.
/// @dev Topic0
/// 0x69add1952a6a6b9cb86f04d05f0cb605cbb469a50ae916139d34495a9991481f.
/// @param queueSequence The location of the transfer in the queue.
event OutboundTransferQueued(uint64 queueSequence);
```

``` solidity
```solidity
/// @notice Emitted when an outbound transfer is rate limited.
/// @dev Topic0
/// 0x754d657d1363ee47d967b415652b739bfe96d5729ccf2f26625dcdbc147db68b.
Expand All @@ -50,7 +52,7 @@ event OutboundTransferRateLimited(
);
```

``` solidity
```solidity
/// @notice Emitted when an inbound transfer is queued
/// @dev Topic0
/// 0x7f63c9251d82a933210c2b6d0b0f116252c3c116788120e64e8e8215df6f3162.
Expand All @@ -65,7 +67,8 @@ Once the `NttManager` forwards the message to the Transceiver, the message is tr
Once the message has been transmitted, the contract emits the `SendTransceiverMessage` event.

_Events_
``` solidity

```solidity
/// @notice Emitted when a message is sent from the transceiver.
/// @dev Topic0
/// 0x53b3e029c5ead7bffc739118953883859d30b1aaa086e0dca4d0a1c99cd9c3f5.
Expand All @@ -90,7 +93,8 @@ NTT implements replay protection, so if a given Transceiver attempts to deliver
If a message had already been executed, the contract ends execution early and emits the `MessageAlreadyExecuted` event instead of reverting via an error. This mitigates the possibility of race conditions from transceivers attempting to deliver the same message when the threshold is less than the total number of available of Transceivers (i.e. threshold < totalTransceivers) and notifies the client (off-chain process) so they don't attempt redundant message delivery.

_Events_
``` solidity

```solidity
/// @notice Emitted when a relayed message is received.
/// @dev Topic0
/// 0xf557dbbb087662f52c815f6c7ee350628a37a51eae9608ff840d996b65f87475
Expand Down Expand Up @@ -128,6 +132,7 @@ event MessageAlreadyExecuted(bytes32 indexed sourceNttManager, bytes32 indexed m
Once a transfer has been successfully verified, the tokens can be minted (if the mode is "burning") or unlocked (if the mode is "locking") to the recipient on the destination chain. Note that the source token decimals are bounded betweeen 0 and `TRIMMED_DECIMALS` as enforced in the wire format. The transfer amount is untrimmed (scaled-up) if the destination chain token decimals exceed `TRIMMED_DECIMALS`. Once the approriate number of tokens have been minted or unlocked to the recipient, the `TransferRedeemed` event is emitted.

_Events_

```solidity
/// @notice Emitted when a transfer has been redeemed
/// (either minted or unlocked on the recipient chain).
Expand All @@ -136,26 +141,35 @@ _Events_
/// @param digest The digest of the message.
event TransferRedeemed(bytes32 indexed digest);
```

## Prerequisites

### Installation

Install Foundry tools(https://book.getfoundry.sh/getting-started/installation), which include forge, anvil and cast CLI tools.

### Build

Run the following command to install necessary dependencies and to build the smart contracts:

```shell
$ make build-evm
```

### Test

To run the full evm test-suite run the following command:

```shell
$ make test-evm
```

The test-suite includes unit tests, along with property-based fuzz tests, and integration-tests.

### Format

To format the files run this command from the root directory.

```shell
$ make fix-fmt
```
Expand All @@ -166,9 +180,67 @@ $ make fix-fmt
$ cd evm && forge snapshot
```

### Contract Deployment
TODO
### Cast

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

### Help

```shell
$ forge --help
$ anvil --help
$ cast --help
```

### Deploy Wormhole NTT

#### Environment Setup

Copy the sample environment file located in `env/` into the target subdirectory of your choice (e.g., `testnet` or `mainnet`) and prefix the filename with your blockchain of choice:

```
mkdir env/testnet
cp env/.env.sample env/testnet/sepolia.env
```

Do this for each blockchain network that the `NTTManager` and `WormholeTransceiver` contracts will be deployed to. Then configure each `.env` file and set the `RPC` variables.

#### Config Setup

Before deploying the contracts, navigate to the `evm/cfg` directory and copy the sample file. Make sure to preserve the existing name:

```
cd cfg

cp WormholeNttConfig.json.sample WormholeNttConfig.json
```

Configure each network to your liking (including adding/removing networks). We will eventually add the addresses of the deployed contracts to this file. Navigate back to the `evm` directory.

#### Deploy

Deploy the `NttManager` and `WormholeTransceiver` contracts by running the following command for each target network:

### Initial Contract Configuration
TODO
```
bash sh/deploy_wormhole_ntt.sh -n NETWORK_TYPE -c CHAIN_NAME -k PRIVATE_KEY

# Argument examples
-n testnet, mainnet
-c avalanche, ethereum, sepolia
```

Save the deployed proxy contract addresses (see the forge script output) in the `WormholeNttConfig.json` file.

#### Configuration

Once all of the contracts have been deployed and the addresses have been saved, run the following command for each target network:

```
bash sh/configure_wormhole_ntt.sh -n NETWORK_TYPE -c CHAIN_NAME -k PRIVATE_KEY

# Argument examples
-n testnet, mainnet
-c avalanche, ethereum, sepolia
```
24 changes: 24 additions & 0 deletions evm/cfg/WormholeNttConfig.json.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"contracts": [
{
"chainId": 10002,
"decimals": 6,
"inboundLimit": 18446744073709551614,
"isEvmChain": true,
"isWormholeRelayingEnabled": true,
"isSpecialRelayingEnabled": false,
"nttManager": "0x00000000000000000000000000000000000000000000000000000000deadbeef",
"wormholeTransceiver": "0x00000000000000000000000000000000000000000000000000000000deadbeef"
},
{
"chainId": 16,
"decimals": 6,
"inboundLimit": 18446744073709551614,
"isEvmChain": true,
"isWormholeRelayingEnabled": true,
"isSpecialRelayingEnabled": false,
"nttManager": "0x00000000000000000000000000000000000000000000000000000000deadbeef",
"wormholeTransceiver": "0x00000000000000000000000000000000000000000000000000000000deadbeef"
}
]
}
41 changes: 41 additions & 0 deletions evm/env/.env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
export RPC=""

### Foundry profile, we always need to deploy with prod.
export FOUNDRY_PROFILE=prod

# -------------------------- NTT Contract --------------------------

### EVM Token Address
export RELEASE_TOKEN_ADDRESS=

### Mode (Locking == 0, Burning == 1)
export RELEASE_MODE=0

### Rate Limit Duration (specified in seconds)
export RELEASE_RATE_LIMIT_DURATION=86400
export RELEASE_SKIP_RATE_LIMIT=false

### Rolling Window Max Outbound Transfer Limit
export RELEASE_OUTBOUND_LIMIT=18446744073709551614

# -------------------------- Wormhole --------------------------

### Wormhole Chain ID
export RELEASE_WORMHOLE_CHAIN_ID=10002

### Wormhole Core Bridge Address
export RELEASE_CORE_BRIDGE_ADDRESS=0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78

### Wormhole Finality
export RELEASE_CONSISTENCY_LEVEL=201

# -------------------------- Relayer --------------------------

### Wormhole Relayer Address
export RELEASE_WORMHOLE_RELAYER_ADDRESS=0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470

### Specialized Relayer Address
export RELEASE_SPECIAL_RELAYER_ADDRESS=0x0000000000000000000000000000000000000000

### Target Chain Gas Limit
export RELEASE_GAS_LIMIT=500000
1 change: 1 addition & 0 deletions evm/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ fs_permissions = [{ access = "read", path = "./test/payloads"}]

[profile.prod]
via_ir = true
fs_permissions = [{access = "read", path = "./cfg/"}]

[fmt]
line_length = 100
Expand Down
101 changes: 101 additions & 0 deletions evm/script/ConfigureWormholeNtt.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;

import {console2} from "forge-std/Script.sol";
import {stdJson} from "forge-std/StdJson.sol";

import "../src/interfaces/INttManager.sol";
import "../src/interfaces/IWormholeTransceiver.sol";
import "../src/interfaces/IOwnableUpgradeable.sol";

import {ParseNttConfig} from "./helpers/ParseNttConfig.sol";
import {WormholeTransceiver} from "../src/Transceiver/WormholeTransceiver/WormholeTransceiver.sol";

contract ConfigureWormholeNtt is ParseNttConfig {
using stdJson for string;

struct ConfigParams {
uint16 wormholeChainId;
}

function _readEnvVariables() internal view returns (ConfigParams memory params) {
// Chain ID.
params.wormholeChainId = uint16(vm.envUint("RELEASE_WORMHOLE_CHAIN_ID"));
require(params.wormholeChainId != 0, "Invalid chain ID");
}

function configureWormholeTransceiver(
IWormholeTransceiver wormholeTransceiver,
ChainConfig[] memory config,
ConfigParams memory params
) internal {
for (uint256 i = 0; i < config.length; i++) {
ChainConfig memory targetConfig = config[i];
if (targetConfig.chainId == params.wormholeChainId) {
continue;
} else {
// Set relayer.
if (targetConfig.isWormholeRelayingEnabled) {
wormholeTransceiver.setIsWormholeRelayingEnabled(targetConfig.chainId, true);
console2.log("Wormhole relaying enabled for chain", targetConfig.chainId);
} else if (targetConfig.isSpecialRelayingEnabled) {
wormholeTransceiver.setIsSpecialRelayingEnabled(targetConfig.chainId, true);
console2.log("Special relaying enabled for chain", targetConfig.chainId);
}

// Set peer.
wormholeTransceiver.setWormholePeer(
targetConfig.chainId, targetConfig.wormholeTransceiver
);
console2.log("Wormhole peer set for chain", targetConfig.chainId);

// Set EVM chain.
if (targetConfig.isEvmChain) {
wormholeTransceiver.setIsWormholeEvmChain(targetConfig.chainId, true);
console2.log("EVM chain set for chain", targetConfig.chainId);
} else {
console2.log("This is not an EVM chain, doing nothing");
}
}
}
}

function configureNttManager(
INttManager nttManager,
ChainConfig[] memory config,
ConfigParams memory params
) internal {
for (uint256 i = 0; i < config.length; i++) {
ChainConfig memory targetConfig = config[i];
if (targetConfig.chainId == params.wormholeChainId) {
continue;
} else {
// Set peer.
nttManager.setPeer(
targetConfig.chainId,
targetConfig.nttManager,
targetConfig.decimals,
targetConfig.inboundLimit
);
console2.log("Peer set for chain", targetConfig.chainId);
}
}
}

function run() public {
vm.startBroadcast();

// Sanity check deployment parameters.
ConfigParams memory params = _readEnvVariables();
(
ChainConfig[] memory config,
INttManager nttManager,
IWormholeTransceiver wormholeTransceiver
) = _parseAndValidateConfigFile(params.wormholeChainId);

configureWormholeTransceiver(wormholeTransceiver, config, params);
configureNttManager(nttManager, config, params);

vm.stopBroadcast();
}
}
12 changes: 0 additions & 12 deletions evm/script/Counter.s.sol

This file was deleted.

Loading
Loading