Skip to content
This repository was archived by the owner on Dec 16, 2025. It is now read-only.

Commit de34819

Browse files
JonathanOppenheimermichaelkaplan13ceyonuralarso16
authored
test: convert warp npm test to go test (#1907)
Signed-off-by: Jonathan Oppenheimer <jonathan.oppenheimer@avalabs.org> Signed-off-by: Jonathan Oppenheimer <147infiniti@gmail.com> Co-authored-by: Michael Kaplan <55204436+michaelkaplan13@users.noreply.github.com> Co-authored-by: Ceyhun Onur <ceyhun.onur@avalabs.org> Co-authored-by: Austin Larson <78000745+alarso16@users.noreply.github.com>
1 parent 62c87e4 commit de34819

File tree

13 files changed

+1095
-607
lines changed

13 files changed

+1095
-607
lines changed

contracts/bindings/gen_examplewarp.go

Lines changed: 0 additions & 369 deletions
This file was deleted.

contracts/contracts/interfaces/IWarpMessenger.sol

Lines changed: 0 additions & 48 deletions
This file was deleted.

contracts/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export { test } from './test/utils';
1+
export { Roles } from './test/utils';

contracts/test/utils.ts

Lines changed: 1 addition & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
import { ethers } from "hardhat"
2-
import { Overrides } from "ethers"
3-
import assert from "assert"
4-
51
/*
62
*
73
* The `test` function is a wrapper around Mocha's `it` function. It provides a normalized framework for running the
@@ -37,96 +33,10 @@ import assert from "assert"
3733
*/
3834

3935
// Below are the types that help define all the different ways to call `test`
40-
type FnNameOrObject = string | string[] | MethodObject | MethodObject[]
41-
42-
// Limit `from` property to be a `string` instead of `string | Promise<string>`
43-
type CallOverrides = Overrides & { from?: string }
44-
45-
type MethodObject = { method: string, debug?: boolean, overrides?: CallOverrides, shouldFail?: boolean }
46-
47-
// This type is after all default values have been applied
48-
type MethodWithDebugAndOverrides = MethodObject & { debug: boolean, overrides: CallOverrides, shouldFail: boolean }
49-
50-
// `test` is used very similarly to `it` from Mocha
51-
export const test = (name, fnNameOrObject, overrides = {}) => it(name, buildTestFn(fnNameOrObject, overrides))
52-
// `test.only` is used very similarly to `it.only` from Mocha, it will isolate all tests marked with `test.only`
53-
test.only = (name, fnNameOrObject, overrides = {}) => it.only(name, buildTestFn(fnNameOrObject, overrides))
54-
// `test.debug` is used to apply `debug: true` to all DSTest contract method calls in the test
55-
test.debug = (name, fnNameOrObject, overrides = {}) => it.only(name, buildTestFn(fnNameOrObject, overrides, true))
56-
// `test.skip` is used very similarly to `it.skip` from Mocha, it will skip all tests marked with `test.skip`
57-
test.skip = (name, fnNameOrObject, overrides = {}) => it.skip(name, buildTestFn(fnNameOrObject, overrides))
58-
59-
// `buildTestFn` is a higher-order function. It returns a function that can be used as the test function for `it`
60-
const buildTestFn = (fnNameOrObject: FnNameOrObject, overrides = {}, debug = false) => {
61-
// normalize the input to an array of objects
62-
const fnObjects: MethodWithDebugAndOverrides[] = (Array.isArray(fnNameOrObject) ? fnNameOrObject : [fnNameOrObject]).map(fnNameOrObject => {
63-
fnNameOrObject = typeof fnNameOrObject === 'string' ? { method: fnNameOrObject } : fnNameOrObject
64-
// assign all default values and overrides
65-
fnNameOrObject.overrides = Object.assign({}, overrides, fnNameOrObject.overrides ?? {})
66-
fnNameOrObject.debug = fnNameOrObject.debug ?? debug
67-
fnNameOrObject.shouldFail = fnNameOrObject.shouldFail ?? false
68-
69-
return fnNameOrObject as MethodWithDebugAndOverrides
70-
})
71-
72-
// only `step_` prefixed functions can be called on the `DSTest` contracts to clearly separate tests and helpers
73-
assert(fnObjects.every(({ method }) => method.startsWith('step_')), "Solidity test functions must be prefixed with 'step_'")
74-
75-
// return the test function that will be used by `it`
76-
// this function must be defined with the `function` keyword so that `this` is bound to the Mocha context
77-
return async function () {
78-
// `Array.prototype.reduce` is used here to ensure that the test functions are called in order.
79-
// Each test function waits for its predecessor to complete before starting
80-
return fnObjects.reduce((p: Promise<undefined>, fn) => p.then(async () => {
81-
const contract = fn.overrides.from
82-
? this.testContract.connect(await ethers.getSigner(fn.overrides.from))
83-
: this.testContract
84-
const tx = await contract[fn.method](fn.overrides).catch(err => {
85-
if (fn.shouldFail) {
86-
if (fn.debug){
87-
console.error(`smart contract call failed with error:\n${err}\n`)
88-
}
89-
90-
return { failed: true }
91-
}
92-
93-
console.error("smart contract call failed with error:", err)
94-
throw err
95-
})
96-
97-
// no more assertions necessary if the method-call should fail and did fail
98-
if (tx.failed && fn.shouldFail) return
99-
100-
const txReceipt = await tx.wait().catch(err => {
101-
if (fn.debug) console.error(`tx failed with error:\n${err}\n`)
102-
return err.receipt
103-
})
104-
105-
// `txReceipt.status` will be `0` if the transaction failed.
106-
// `contract.failed` will return `true` if any of the `DSTest` assertions failed.
107-
const failed = txReceipt.status === 0 ? true : await contract.failed.staticCall()
108-
if (fn.debug || failed) {
109-
console.log('')
110-
111-
if (!txReceipt.events) console.warn('WARNING: No parseable events found in tx-receipt\n')
112-
113-
// If `DSTest` assertions failed, the contract will emit logs describing the assertion failure(s).
114-
txReceipt
115-
.events
116-
?.filter(event => fn.debug || event.event?.startsWith('log'))
117-
.map(event => event.args?.forEach(arg => console.log(arg)))
118-
119-
console.log('')
120-
}
121-
122-
assert(!failed, `${fn.method} failed`)
123-
}), Promise.resolve())
124-
}
125-
}
12636

12737
export const Roles = {
12838
None: 0,
12939
Enabled: 1,
13040
Admin: 2,
13141
Manager: 3,
132-
}
42+
}

contracts/test/warp.ts

Lines changed: 0 additions & 40 deletions
This file was deleted.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
pragma solidity ^0.8.24;
33
pragma experimental ABIEncoderV2;
44

5-
import "./interfaces/IWarpMessenger.sol";
5+
import "precompile/contracts/warp/warpbindings/IWarpMessenger.sol";
66

77
contract ExampleWarp {
88
address constant WARP_ADDRESS = 0x0200000000000000000000000000000000000005;
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.24;
4+
5+
struct WarpMessage {
6+
bytes32 sourceChainID;
7+
address originSenderAddress;
8+
bytes payload;
9+
}
10+
11+
struct WarpBlockHash {
12+
bytes32 sourceChainID;
13+
bytes32 blockHash;
14+
}
15+
16+
interface IWarpMessenger {
17+
event SendWarpMessage(
18+
address indexed sender,
19+
bytes32 indexed messageID,
20+
bytes message
21+
);
22+
23+
// sendWarpMessage emits a request for the subnet to send a warp message from [msg.sender]
24+
// with the specified parameters.
25+
// This emits a SendWarpMessage log from the precompile. When the corresponding block is accepted
26+
// the Accept hook of the Warp precompile is invoked with all accepted logs emitted by the Warp
27+
// precompile.
28+
// Each validator then adds the UnsignedWarpMessage encoded in the log to the set of messages
29+
// it is willing to sign for an off-chain relayer to aggregate Warp signatures.
30+
function sendWarpMessage(
31+
bytes calldata payload
32+
) external returns (bytes32 messageID);
33+
34+
// getVerifiedWarpMessage parses the pre-verified warp message in the
35+
// predicate storage slots as a WarpMessage and returns it to the caller.
36+
// If the message exists and passes verification, returns the verified message
37+
// and true.
38+
// Otherwise, returns false and the empty value for the message.
39+
function getVerifiedWarpMessage(
40+
uint32 index
41+
) external view returns (WarpMessage calldata message, bool valid);
42+
43+
// getVerifiedWarpBlockHash parses the pre-verified WarpBlockHash message in the
44+
// predicate storage slots as a WarpBlockHash message and returns it to the caller.
45+
// If the message exists and passes verification, returns the verified message
46+
// and true.
47+
// Otherwise, returns false and the empty value for the message.
48+
function getVerifiedWarpBlockHash(
49+
uint32 index
50+
) external view returns (WarpBlockHash calldata warpBlockHash, bool valid);
51+
52+
// getBlockchainID returns the snow.Context BlockchainID of this chain.
53+
// This blockchainID is the hash of the transaction that created this blockchain on the P-Chain
54+
// and is not related to the Ethereum ChainID.
55+
function getBlockchainID() external view returns (bytes32 blockchainID);
56+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved.
2+
// See the file LICENSE for licensing terms.
3+
4+
package warpbindings
5+
6+
// Step 1: Compile Solidity contract to generate ABI and bin files
7+
//go:generate solc-v0.8.30 -o artifacts --overwrite --abi --bin --evm-version cancun IWarpMessenger.sol
8+
// Step 2: Generate Go bindings from the compiled artifacts
9+
//go:generate go run github.com/ava-labs/libevm/cmd/abigen --pkg warpbindings --type IWarpMessenger --abi artifacts/IWarpMessenger.abi --bin artifacts/IWarpMessenger.bin --out gen_iwarpmessenger_binding.go
10+
// Step 3: Replace import paths in generated binding to use subnet-evm instead of libevm
11+
// This is necessary because the libevm bindings package is not compatible with the subnet-evm simulated backend, which is used for testing.
12+
//go:generate sh -c "sed -i.bak -e 's|github.com/ava-labs/libevm/accounts/abi|github.com/ava-labs/subnet-evm/accounts/abi|g' -e 's|github.com/ava-labs/libevm/accounts/abi/bind|github.com/ava-labs/subnet-evm/accounts/abi/bind|g' gen_iwarpmessenger_binding.go && rm -f gen_iwarpmessenger_binding.go.bak"

0 commit comments

Comments
 (0)