Skip to content

Commit 2ad5093

Browse files
EVM tilt tests (#206)
* Add tilt tests --------- Co-authored-by: marcomariscal <42938673+marcomariscal@users.noreply.github.com> --------- Co-authored-by: Keating <keating.dev@protonmail.com>
1 parent f0f56a9 commit 2ad5093

File tree

85 files changed

+17011
-281
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+17011
-281
lines changed

.github/workflows/tilt-tests.yml

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: Integration tests
2+
3+
on:
4+
workflow_dispatch:
5+
pull_request:
6+
push:
7+
branches:
8+
- main
9+
10+
jobs:
11+
tilt:
12+
runs-on: tilt-kube-public
13+
14+
# Cancel previous builds on the same branch/ref. Full runs are expensive
15+
# and capacity is limited, so we want to avoid running multiple builds
16+
# in parallel even if it means skipping CI runs on permanent branches
17+
# (unfortunately, we can't differentiate between temporary and permanent
18+
# refs without duplicating the entire logic).
19+
# concurrency:
20+
# group: ${{ github.workflow }}-tilt-${{ github.ref }}
21+
# cancel-in-progress: true
22+
23+
steps:
24+
# - name: Clear repository
25+
# run: |
26+
# rm -rf $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
27+
- uses: actions/checkout@v4
28+
with:
29+
submodules: recursive
30+
- name: Expand for link to Tilt dashboard (only available during build)
31+
run: >
32+
echo "Tilt progress dashboard: https://$DASHBOARD_URL"
33+
- run: |
34+
kubectl config set-context ci --namespace=$DEPLOY_NS
35+
kubectl config use-context ci
36+
37+
- run: tilt ci -- --evm2 --query_server=true --namespace=$DEPLOY_NS
38+
timeout-minutes: 30
39+
40+
# Clean up k8s resources
41+
- run: kubectl delete --namespace=$DEPLOY_NS service,statefulset,configmap,pod,job --all
42+
if: always()

.gitignore

+7-20
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,9 @@
1-
# Compiler files
2-
cache/
3-
out/
4-
evm/cache/
5-
evm/out/
1+
# Wormhole git directory
2+
.wormhole/.git/
3+
.wormhole/.git/*
4+
.wormhole/
65

7-
8-
9-
# Ignores development broadcast logs
10-
!/broadcast
11-
/broadcast/*/31337/
12-
/broadcast/**/dry-run/
13-
14-
# Dotenv file
6+
# Common files to ignore
7+
node_modules/
158
.env
16-
17-
# Coverage
18-
lcov.info
19-
20-
# IDEs
21-
.vscode
22-
.idea
9+
*.log

Tiltfile

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
load('ext://namespace', 'namespace_create', 'namespace_inject')
2+
load('ext://git_resource', 'git_checkout')
3+
4+
# Add platform settings for M3 Mac
5+
def get_architecture():
6+
arch = str(local('uname -m', quiet=True))
7+
return '--platform=linux/arm64' if 'arm64' in arch else ''
8+
9+
git_checkout('https://github.com/wormhole-foundation/wormhole.git#main', '.wormhole/', unsafe_mode=True)
10+
load(".wormhole/Tiltfile", "namespace", "k8s_yaml_with_ns")
11+
12+
# CI tests (includes EVM contracts in build)
13+
custom_build(
14+
ref = "multi-gov-ci",
15+
command = 'DOCKER_BUILDKIT=1 docker build --network=host %s --progress=plain --build-arg BUILDKIT_INLINE_CACHE=1 -t $EXPECTED_REF -f ./integration-tests/Dockerfile .' % get_architecture(),
16+
deps = ['./integration-tests', './evm'],
17+
ignore=['node_modules', '.wormhole', 'cache', 'out']
18+
)
19+
20+
k8s_yaml_with_ns("./integration-tests/ci.yaml")
21+
k8s_resource(
22+
"multi-gov-tests",
23+
labels = ["multi-gov"],
24+
resource_deps = ["eth-devnet", "eth-devnet2", "query-server"],
25+
)

biome.json

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"$schema": "https://biomejs.dev/schemas/1.4.1/schema.json",
3+
"extends": ["./integration-tests/biome.json"],
4+
"files": {
5+
"ignore": [
6+
"node_modules/**",
7+
"dist/**",
8+
"build/**",
9+
"bun.lockb",
10+
"**/evm/**",
11+
"**/solana/**"
12+
]
13+
}
14+
}

evm/.gitignore

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Compiler files
2+
cache/
3+
out/
4+
evm/cache/
5+
evm/out/
6+
7+
# Ignores development broadcast logs
8+
!/broadcast
9+
/broadcast/*/31337/
10+
/broadcast/**/dry-run/
11+
/broadcast/*devnet*/**
12+
13+
# Dotenv file
14+
.env
15+
16+
# Coverage
17+
lcov.info
18+
19+
# IDEs
20+
.vscode
21+
.idea
22+
23+
# Artifacts
24+
artifacts/
25+
26+
# Abis
27+
abis/

evm/Dockerfile

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
FROM ghcr.io/foundry-rs/foundry@sha256:8b843eb65cc7b155303b316f65d27173c862b37719dc095ef3a2ef27ce8d3c00 as builder
2+
3+
WORKDIR /app
4+
COPY foundry.toml foundry.toml
5+
COPY lib lib
6+
COPY src src
7+
8+
RUN FOUNDRY_PROFILE=ir forge build
9+
10+
FROM scratch AS foundry-export
11+
12+
COPY --from=builder /app/out .

evm/broadcast/DeploySpokeContractsOptimismSepolia.sol/11155420/dry-run/run-1728493337.json

-125
This file was deleted.

evm/broadcast/DeploySpokeContractsOptimismSepolia.sol/11155420/dry-run/run-latest.json

-125
This file was deleted.

evm/foundry.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts",
88
"wormhole/=lib/wormhole/ethereum/contracts",
99
"wormhole-sdk/=lib/wormhole-solidity-sdk/src",
10-
10+
"src/=src/",
11+
"test/=test/",
12+
"script/=script/",
1113
]
1214
solc_version = "0.8.23"
1315
verbosity = 3

evm/generate_abis.sh

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/bin/bash
2+
3+
# List of main contracts
4+
main_contracts=(
5+
"HubEvmSpokeAggregateProposer"
6+
"HubEvmSpokeVoteDecoder"
7+
"HubGovernor"
8+
"HubMessageDispatcher"
9+
"HubProposalExtender"
10+
"HubProposalMetadata"
11+
"HubSolanaMessageDispatcher"
12+
"HubSolanaSpokeVoteDecoder"
13+
"HubVotePool"
14+
"SpokeAirlock"
15+
"SpokeMessageExecutor"
16+
"SpokeMetadataCollector"
17+
"SpokeVoteAggregator"
18+
"WormholeDispatcher"
19+
"ERC20VotesFake"
20+
"TimelockController"
21+
"ERC1967Proxy"
22+
)
23+
24+
# Create a directory for the ABIs if it doesn't exist
25+
mkdir -p abis
26+
27+
# Loop through each main contract and generate its ABI
28+
for contract in "${main_contracts[@]}"
29+
do
30+
forge inspect $contract abi > abis/${contract}_abi.json
31+
echo "Generated ABI for $contract"
32+
done
33+
34+
echo "ABIs for main contracts generated in the 'abis' directory."
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// SPDX-License-Identifier: Apache 2
2+
pragma solidity ^0.8.23;
3+
4+
import {Vm} from "forge-std/Vm.sol";
5+
import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
6+
import {DeployHubContractsBaseImpl} from "script/DeployHubContractsBaseImpl.s.sol";
7+
import {ERC20VotesFake} from "test/fakes/ERC20VotesFake.sol";
8+
9+
/// @notice Deploy the hub contracts for EthDevnet1 when using the Wormhole Tilt testing environment (Devnet).
10+
/// @dev Set the environment variable DEPLOYER_PRIVATE_KEY to the private key of the account that will be used to deploy
11+
/// the contracts.
12+
/// @dev Deploy with:
13+
/// forge script script/DeployHubContractsEthDevnet1.sol:DeployHubContractsEthDevnet1 --rpc-url
14+
/// http://localhost:8545 --broadcast --via-ir
15+
contract DeployHubContractsEthDevnet1 is DeployHubContractsBaseImpl {
16+
function _getDeploymentConfiguration() internal override returns (DeploymentConfiguration memory) {
17+
Vm.Wallet memory wallet = _deploymentWallet();
18+
19+
vm.startBroadcast(wallet.privateKey);
20+
21+
bytes32 salt = keccak256(abi.encodePacked("WormholeGovernanceHubContracts"));
22+
bytes memory bytecode =
23+
abi.encodePacked(type(ERC20VotesFake).creationCode, abi.encode("MultiGov Governance Token", "MGT", 18));
24+
address tokenAddress = Create2.deploy(0, salt, bytecode);
25+
// Deploy ERC20VotesFake using CREATE2
26+
ERC20VotesFake token = ERC20VotesFake(tokenAddress);
27+
28+
uint256 initialSupply = 1_000_000_000e18; // 1 billion tokens
29+
token.mint(wallet.addr, initialSupply);
30+
vm.stopBroadcast();
31+
32+
return DeploymentConfiguration({
33+
minDelay: 300,
34+
name: "Wormhole EthDevnet1 Governor",
35+
token: address(token),
36+
initialVotingDelay: 1.5 minutes,
37+
initialVotingPeriod: 30 minutes,
38+
initialProposalThreshold: 500_000e18,
39+
initialQuorum: 1_000_000e18,
40+
wormholeCore: 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550, // EthDevnet1 Wormhole Core
41+
voteWeightWindow: 10 minutes,
42+
voteExtenderAdmin: wallet.addr,
43+
voteTimeExtension: 5 minutes,
44+
minimumExtensionTime: 1 minutes,
45+
consistencyLevel: 0,
46+
initialMaxQueryTimestampOffset: 10 minutes,
47+
solanaTokenDecimals: 8
48+
});
49+
}
50+
}

evm/script/DeploySpokeContractsBaseImpl.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ abstract contract DeploySpokeContractsBaseImpl is Script {
3737

3838
error InvalidAddressConfiguration();
3939

40-
function _getDeploymentConfiguration() internal pure virtual returns (DeploymentConfiguration memory);
40+
function _getDeploymentConfiguration() internal virtual returns (DeploymentConfiguration memory);
4141

4242
function _deploymentWallet() internal virtual returns (Vm.Wallet memory) {
4343
uint256 deployerPrivateKey = vm.envOr("DEPLOYER_PRIVATE_KEY", DEFAULT_DEPLOYER_PRIVATE_KEY);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// SPDX-License-Identifier: Apache 2
2+
pragma solidity ^0.8.23;
3+
4+
import {Vm} from "forge-std/Vm.sol";
5+
import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
6+
import {toWormholeFormat} from "wormhole-sdk/Utils.sol";
7+
import {DeploySpokeContractsBaseImpl} from "./DeploySpokeContractsBaseImpl.sol";
8+
import {ERC20VotesFake} from "test/fakes/ERC20VotesFake.sol";
9+
10+
/// @notice Deploy the spoke contracts for EthDevnet2 when using the Wormhole Tilt testing environment (Devnet).
11+
/// @dev Set the environment variable DEPLOYER_PRIVATE_KEY to the private key of the account that will be used to deploy
12+
/// the contracts.
13+
/// @dev Deploy with:
14+
/// forge script script/DeploySpokeContractsEthDevnet2.sol:DeploySpokeContractsEthDevnet2 --rpc-url
15+
/// http://localhost:8546 --broadcast --via-ir
16+
contract DeploySpokeContractsEthDevnet2 is DeploySpokeContractsBaseImpl {
17+
error ContractNotFound(string contractName);
18+
19+
function _findContractAddress(string memory json, string memory contractName) internal pure returns (address) {
20+
// First get the transactions array from the broadcast object
21+
bytes[] memory txs = abi.decode(vm.parseJson(json, "$.transactions"), (bytes[]));
22+
uint256 length = txs.length;
23+
24+
for (uint256 i = 0; i < length; i++) {
25+
string memory namePath = string.concat("$.transactions[", vm.toString(i), "].contractName");
26+
string memory currentName = vm.parseJsonString(json, namePath);
27+
28+
if (keccak256(bytes(currentName)) == keccak256(bytes(contractName))) {
29+
string memory addrPath = string.concat("$.transactions[", vm.toString(i), "].contractAddress");
30+
bytes memory addrBytes = vm.parseJson(json, addrPath);
31+
return abi.decode(addrBytes, (address));
32+
}
33+
}
34+
35+
revert ContractNotFound(contractName);
36+
}
37+
38+
function _getDeploymentConfiguration() internal override returns (DeploymentConfiguration memory) {
39+
Vm.Wallet memory wallet = _deploymentWallet();
40+
41+
vm.startBroadcast(wallet.privateKey);
42+
43+
bytes32 salt = keccak256(abi.encodePacked("WormholeGovernanceHubContracts"));
44+
bytes memory bytecode =
45+
abi.encodePacked(type(ERC20VotesFake).creationCode, abi.encode("MultiGov Governance Token", "MGT", 18));
46+
address tokenAddress = Create2.deploy(0, salt, bytecode);
47+
// Deploy ERC20VotesFake using CREATE2
48+
ERC20VotesFake token = ERC20VotesFake(tokenAddress);
49+
50+
uint256 initialSupply = 1_000_000_000e18; // 1 billion tokens
51+
token.mint(wallet.addr, initialSupply);
52+
vm.stopBroadcast();
53+
54+
// Read the latest hub deployment to get the addresses
55+
string memory root = vm.projectRoot();
56+
string memory path = string.concat(root, "/broadcast/DeployHubContractsEthDevnet1.sol/1337/run-latest.json");
57+
string memory json = vm.readFile(path);
58+
59+
address hubProposalMetadata = _findContractAddress(json, "HubProposalMetadata");
60+
address hubDispatcher = _findContractAddress(json, "HubMessageDispatcher");
61+
62+
return DeploymentConfiguration({
63+
wormholeCore: 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550, // EthDevnet2 Wormhole Core
64+
hubChainId: 2, // EthDevnet1 Wormhole chain ID
65+
hubProposalMetadata: hubProposalMetadata,
66+
votingToken: address(token),
67+
voteWeightWindow: 10 minutes,
68+
hubDispatcher: toWormholeFormat(hubDispatcher),
69+
spokeChainId: 4 // EthDevnet2 Wormhole chain ID
70+
});
71+
}
72+
}

evm/test/HubGovernor.t.sol

+6-5
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ contract HubGovernorTest is WormholeEthQueryTest, ProposalTest {
5151
initialVotingPeriod: 3 days,
5252
initialProposalThreshold: 500_000e18,
5353
initialQuorum: 100e18,
54-
hubVotePool: address(timelock),
54+
hubVotePool: address(hubVotePool),
5555
wormholeCore: address(wormhole),
5656
governorProposalExtender: address(extender),
5757
initialVoteWeightWindow: VOTE_WEIGHT_WINDOW
@@ -148,7 +148,7 @@ contract Constructor is HubGovernorTest {
148148
initialVotingPeriod: _initialVotingPeriod,
149149
initialProposalThreshold: _initialProposalThreshold,
150150
initialQuorum: _initialQuorum,
151-
hubVotePool: _timelock,
151+
hubVotePool: address(hubVotePool),
152152
wormholeCore: address(wormhole),
153153
governorProposalExtender: address(_voteExtender),
154154
initialVoteWeightWindow: 1 days
@@ -184,6 +184,7 @@ contract Constructor is HubGovernorTest {
184184
HubProposalExtender _voteExtender = new HubProposalExtender(
185185
initialOwner, VOTE_TIME_EXTENSION, address(_extenderOwner), _deployer, MINIMUM_VOTE_EXTENSION
186186
);
187+
HubVotePool hubVotePool = new HubVotePool(address(wormhole), address(0), address(timelock));
187188

188189
HubGovernor.ConstructorParams memory params = HubGovernor.ConstructorParams({
189190
name: _name,
@@ -193,7 +194,7 @@ contract Constructor is HubGovernorTest {
193194
initialVotingPeriod: _initialVotingPeriod,
194195
initialProposalThreshold: _initialProposalThreshold,
195196
initialQuorum: _initialQuorum,
196-
hubVotePool: _timelock,
197+
hubVotePool: address(hubVotePool),
197198
wormholeCore: address(wormhole),
198199
governorProposalExtender: address(_voteExtender),
199200
initialVoteWeightWindow: 1 days
@@ -225,7 +226,7 @@ contract Constructor is HubGovernorTest {
225226
initialVotingPeriod: _initialVotingPeriod,
226227
initialProposalThreshold: _initialProposalThreshold,
227228
initialQuorum: _initialQuorum,
228-
hubVotePool: _timelock,
229+
hubVotePool: address(hubVotePool),
229230
wormholeCore: address(wormhole),
230231
governorProposalExtender: _voteExtender,
231232
initialVoteWeightWindow: 1 days
@@ -252,7 +253,7 @@ contract Constructor is HubGovernorTest {
252253
initialVotingPeriod: 0,
253254
initialProposalThreshold: _initialProposalThreshold,
254255
initialQuorum: _initialQuorum,
255-
hubVotePool: _timelock,
256+
hubVotePool: address(hubVotePool),
256257
wormholeCore: address(wormhole),
257258
governorProposalExtender: _voteExtender,
258259
initialVoteWeightWindow: 1 days

0 commit comments

Comments
 (0)