1
- import { mnemonicToAccount } from "viem/accounts" ;
2
- import { ANVIL_MNEMONIC } from "./consts" ;
3
- import { test } from "bun:test" ;
1
+ import { serializeLayout } from "@wormhole-foundation/sdk-base" ;
2
+ import { relayInstructionsLayout } from "@wormhole-foundation/sdk-definitions" ;
3
+ import axios from "axios" ;
4
+ import { sleep } from "bun" ;
5
+ import { expect , test } from "bun:test" ;
4
6
import {
5
7
createPublicClient ,
6
8
createWalletClient ,
7
9
getContract ,
8
10
http ,
11
+ isHex ,
9
12
padHex ,
10
13
toHex ,
14
+ type Account ,
15
+ type Chain ,
16
+ type PublicClient ,
17
+ type WalletClient ,
11
18
} from "viem" ;
12
- import { anvil , sepolia } from "viem/chains" ;
13
- import { serializeLayout } from "@wormhole-foundation/sdk-base" ;
14
- import {
15
- quoteLayout ,
16
- relayInstructionsLayout ,
17
- signedQuoteLayout ,
18
- } from "@wormhole-foundation/sdk-definitions" ;
19
- import axios from "axios" ;
20
- import { deserialize } from "binary-layout" ;
19
+ import { mnemonicToAccount } from "viem/accounts" ;
20
+ import forgeOutput from "../evm/out/ExecutorVAAv1Integration.sol/ExecutorVAAv1Integration.json" ;
21
+ import { enabledChains } from "./chains" ;
22
+ import { ANVIL_MNEMONIC } from "./consts" ;
23
+ import { RelayStatus } from "./types" ;
21
24
22
25
const ABI = [
23
26
{
@@ -113,7 +116,90 @@ const ABI = [
113
116
} ,
114
117
] as const ;
115
118
119
+ async function deployIntegrationContract (
120
+ publicClient : PublicClient ,
121
+ client : WalletClient ,
122
+ account : Account ,
123
+ viemChain : Chain ,
124
+ coreContractAddress : string ,
125
+ executorAddress : string ,
126
+ ) {
127
+ if ( ! isHex ( forgeOutput . bytecode . object ) ) {
128
+ throw new Error ( "invalid bytecode" ) ;
129
+ }
130
+ if ( ! isHex ( coreContractAddress ) ) {
131
+ throw new Error ( "invalid coreContractAddress" ) ;
132
+ }
133
+ if ( ! isHex ( executorAddress ) ) {
134
+ throw new Error ( "invalid executorAddress" ) ;
135
+ }
136
+ const hash = await client . deployContract ( {
137
+ account,
138
+ chain : viemChain ,
139
+ abi : ABI ,
140
+ bytecode : forgeOutput . bytecode . object ,
141
+ args : [ coreContractAddress , executorAddress , 200 ] ,
142
+ } ) ;
143
+ const receipt = await publicClient . waitForTransactionReceipt ( {
144
+ hash,
145
+ } ) ;
146
+ if ( ! isHex ( receipt . contractAddress ) ) {
147
+ throw new Error ( "invalid contractAddress" ) ;
148
+ }
149
+ return receipt . contractAddress ;
150
+ }
151
+
116
152
test ( "it performs a VAA v1 relay" , async ( ) => {
153
+ const srcChain = enabledChains [ 10002 ] ! ;
154
+ const dstChain = enabledChains [ 10004 ] ! ;
155
+ const account = mnemonicToAccount ( ANVIL_MNEMONIC , { addressIndex : 0 } ) ;
156
+ if ( ! srcChain . viemChain || ! dstChain . viemChain ) {
157
+ throw new Error ( "invalid viem chain" ) ;
158
+ }
159
+ const srcTransport = http ( srcChain . rpc ) ;
160
+ const srcPublicClient = createPublicClient ( {
161
+ chain : srcChain . viemChain ,
162
+ transport : srcTransport ,
163
+ } ) ;
164
+ const srcClient = createWalletClient ( {
165
+ account,
166
+ chain : srcChain . viemChain ,
167
+ transport : srcTransport ,
168
+ } ) ;
169
+ const dstTransport = http ( dstChain . rpc ) ;
170
+ const dstPublicClient = createPublicClient ( {
171
+ chain : dstChain . viemChain ,
172
+ transport : dstTransport ,
173
+ } ) ;
174
+ const dstClient = createWalletClient ( {
175
+ account,
176
+ chain : dstChain . viemChain ,
177
+ transport : dstTransport ,
178
+ } ) ;
179
+ const srcContract = await deployIntegrationContract (
180
+ srcPublicClient ,
181
+ srcClient ,
182
+ account ,
183
+ srcChain . viemChain ,
184
+ srcChain . coreContractAddress ,
185
+ srcChain . executorAddress ,
186
+ ) ;
187
+ console . log ( `Deployed source contract: ${ srcContract } ` ) ;
188
+ const dstContract = await deployIntegrationContract (
189
+ dstPublicClient ,
190
+ dstClient ,
191
+ account ,
192
+ dstChain . viemChain ,
193
+ dstChain . coreContractAddress ,
194
+ dstChain . executorAddress ,
195
+ ) ;
196
+ console . log ( `Deployed destination contract: ${ dstContract } ` ) ;
197
+ const dstTestContract = getContract ( {
198
+ address : srcContract ,
199
+ abi : ABI ,
200
+ client : srcClient ,
201
+ } ) ;
202
+ expect ( await dstTestContract . read . number ( ) ) . toBe ( 0n ) ;
117
203
const relayInstructions = toHex (
118
204
serializeLayout ( relayInstructionsLayout , {
119
205
requests : [
@@ -127,27 +213,20 @@ test("it performs a VAA v1 relay", async () => {
127
213
] ,
128
214
} ) ,
129
215
) ;
130
- const response = await axios . post ( "http://localhost :3000/v0/quote" , {
216
+ const response = await axios . post ( "http://executor :3000/v0/quote" , {
131
217
srcChain : 10002 ,
132
218
dstChain : 10004 ,
133
219
relayInstructions,
134
220
} ) ;
135
- const transport = http ( "http://localhost:8545" ) ;
136
- const account = mnemonicToAccount ( ANVIL_MNEMONIC , { addressIndex : 0 } ) ;
137
- const client = createWalletClient ( {
138
- account,
139
- chain : sepolia ,
140
- transport,
141
- } ) ;
142
- const testContract = getContract ( {
143
- address : "0x8e98Bd10a6f4c1Ee0C4b5d9F50a18D1a7E20EaF8" ,
221
+ const srcTestContract = getContract ( {
222
+ address : srcContract ,
144
223
abi : ABI ,
145
- client,
224
+ client : srcClient ,
146
225
} ) ;
147
- const tx = await testContract . write . incrementAndSend (
226
+ const hash = await srcTestContract . write . incrementAndSend (
148
227
[
149
228
10004 ,
150
- padHex ( "0x7d77360666066967579a2235332d271587cd62dC" , {
229
+ padHex ( dstContract , {
151
230
dir : "left" ,
152
231
size : 32 ,
153
232
} ) ,
@@ -160,6 +239,29 @@ test("it performs a VAA v1 relay", async () => {
160
239
{ value : BigInt ( response . data . estimatedCost ) } ,
161
240
) ;
162
241
console . log (
163
- `https://wormholelabs-xyz.github.io/executor-explorer/#/chain/10002/tx/${ tx } ?endpoint=http%3A%2F%2Flocalhost%3A3000&env=Testnet` ,
242
+ `Request execution: https://wormholelabs-xyz.github.io/executor-explorer/#/chain/10002/tx/${ hash } ?endpoint=http%3A%2F%2Flocalhost%3A3000&env=Testnet` ,
164
243
) ;
165
- } ) ;
244
+ await srcPublicClient . waitForTransactionReceipt ( {
245
+ hash,
246
+ } ) ;
247
+ let statusResult ;
248
+ while (
249
+ ! statusResult ||
250
+ statusResult . data ?. [ 0 ] . status === RelayStatus . Pending
251
+ ) {
252
+ console . log ( `Statusing tx: ${ hash } ` ) ;
253
+ if ( statusResult ) {
254
+ await sleep ( 1000 ) ;
255
+ }
256
+ statusResult = await axios . post ( "http://executor:3000/v0/status/tx" , {
257
+ chainId : srcChain . wormholeChainId ,
258
+ txHash : hash ,
259
+ } ) ;
260
+ if ( statusResult . data . length !== 1 ) {
261
+ throw new Error ( `unexpected status result length` ) ;
262
+ }
263
+ }
264
+ expect ( statusResult . data ?. [ 0 ] . status ) . toBe ( RelayStatus . Submitted ) ;
265
+ expect ( await srcTestContract . read . number ( ) ) . toBe ( 1n ) ;
266
+ expect ( await dstTestContract . read . number ( ) ) . toBe ( 1n ) ;
267
+ } , 60000 ) ;
0 commit comments