@@ -5,13 +5,15 @@ import {
5
5
ChainAddress ,
6
6
ChainContext ,
7
7
NativeSigner ,
8
+ Platform ,
8
9
Signer ,
9
10
VAA ,
10
11
Wormhole ,
11
12
WormholeMessageId ,
12
13
amount ,
13
14
chainToPlatform ,
14
15
encoding ,
16
+ keccak256 ,
15
17
serialize ,
16
18
signSendWait as ssw ,
17
19
toChainId ,
@@ -24,6 +26,7 @@ import { ethers } from "ethers";
24
26
import { DummyTokenMintAndBurn__factory } from "../evm/ethers-ci-contracts/factories/DummyToken.sol/DummyTokenMintAndBurn__factory.js" ;
25
27
import { DummyToken__factory } from "../evm/ethers-ci-contracts/factories/DummyToken.sol/DummyToken__factory.js" ;
26
28
import { ERC1967Proxy__factory } from "../evm/ethers-ci-contracts/factories/ERC1967Proxy__factory.js" ;
29
+ import { IWormholeRelayer__factory } from "../evm/ethers-ci-contracts/factories/IWormholeRelayer.sol/IWormholeRelayer__factory.js" ;
27
30
import { NttManager__factory } from "../evm/ethers-ci-contracts/factories/NttManager__factory.js" ;
28
31
import { TransceiverStructs__factory } from "../evm/ethers-ci-contracts/factories/TransceiverStructs__factory.js" ;
29
32
import { TrimmedAmountLib__factory } from "../evm/ethers-ci-contracts/factories/TrimmedAmount.sol/TrimmedAmountLib__factory.js" ;
@@ -44,14 +47,21 @@ export const NETWORK: "Devnet" = "Devnet";
44
47
45
48
const ETH_PRIVATE_KEY =
46
49
"0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d" ; // Ganache default private key
50
+
47
51
const SOL_PRIVATE_KEY = web3 . Keypair . fromSecretKey (
48
52
new Uint8Array ( solanaTiltKey )
49
53
) ;
50
54
51
- interface Signers {
55
+ type NativeSdkSigner < P extends Platform > = P extends "Evm"
56
+ ? ethers . Wallet
57
+ : P extends "Solana"
58
+ ? web3 . Keypair
59
+ : never ;
60
+
61
+ interface Signers < P extends Platform = Platform > {
52
62
address : ChainAddress ;
53
63
signer : Signer ;
54
- nativeSigner : any ;
64
+ nativeSigner : NativeSdkSigner < P > ;
55
65
}
56
66
57
67
interface StartingCtx {
@@ -98,9 +108,20 @@ export async function link(chainInfos: Ctx[]) {
98
108
99
109
// first submit hub init to accountant
100
110
const hub = chainInfos [ 0 ] ! ;
101
- await submitAccountantVAA ( serialize ( await getVaa ( hub , 0n ) ) ) ;
102
111
const hubChain = hub . context . chain ;
103
112
113
+ const msgId : WormholeMessageId = {
114
+ chain : hubChain ,
115
+ emitter : Wormhole . chainAddress (
116
+ hubChain ,
117
+ hub . contracts ! . transceiver . wormhole
118
+ ) . address . toUniversalAddress ( ) ,
119
+ sequence : 0n ,
120
+ } ;
121
+
122
+ const vaa = await wh . getVaa ( msgId , "Ntt:TransceiverInfo" ) ;
123
+ await submitAccountantVAA ( serialize ( vaa ! ) ) ;
124
+
104
125
// [target, peer, vaa]
105
126
const registrations : [ string , string , VAA < "Ntt:TransceiverRegistration" > ] [ ] =
106
127
[ ] ;
@@ -172,32 +193,7 @@ export async function link(chainInfos: Ctx[]) {
172
193
}
173
194
}
174
195
175
- async function getVaa ( ctx : Ctx , sequence : bigint ) : Promise < VAA > {
176
- const chain = ctx . context . chain ;
177
- const msgId = {
178
- chain,
179
- emitter : Wormhole . chainAddress (
180
- chain ,
181
- ctx . contracts ! . transceiver . wormhole
182
- ) . address . toUniversalAddress ( ) ,
183
- sequence,
184
- } ;
185
-
186
- const vaa = await wh . getVaa (
187
- msgId ,
188
- sequence === 0n ? "Ntt:TransceiverInfo" : "Ntt:TransceiverRegistration"
189
- ) ;
190
- if ( ! vaa )
191
- throw new Error ( `Failed to get VAA for: ${ msgId . chain } : ${ msgId . sequence } ` ) ;
192
-
193
- return vaa ;
194
- }
195
-
196
- export async function transferWithChecks (
197
- sourceCtx : Ctx ,
198
- destinationCtx : Ctx ,
199
- useRelayer : boolean = false
200
- ) {
196
+ export async function transferWithChecks ( sourceCtx : Ctx , destinationCtx : Ctx ) {
201
197
const sendAmt = "0.01" ;
202
198
203
199
const srcAmt = amount . units (
@@ -221,9 +217,17 @@ export async function transferWithChecks(
221
217
dstSigner . address ( )
222
218
) ;
223
219
220
+ const useRelayer =
221
+ chainToPlatform ( sourceCtx . context . chain ) === "Evm" &&
222
+ chainToPlatform ( destinationCtx . context . chain ) === "Evm" ;
223
+
224
224
console . log ( "Calling transfer on: " , sourceCtx . context . chain ) ;
225
225
const srcNtt = await getNtt ( sourceCtx ) ;
226
- const transferTxs = srcNtt . transfer ( sender . address , srcAmt , receiver , false ) ;
226
+ const transferTxs = srcNtt . transfer ( sender . address , srcAmt , receiver , {
227
+ queue : false ,
228
+ automatic : useRelayer ,
229
+ gasDropoff : 0n ,
230
+ } ) ;
227
231
const txids = await signSendWait ( sourceCtx . context , transferTxs , srcSigner ) ;
228
232
229
233
const srcCore = await sourceCtx . context . getWormholeCore ( ) ;
@@ -232,6 +236,7 @@ export async function transferWithChecks(
232
236
) [ 0 ] ! ;
233
237
234
238
if ( ! useRelayer ) await receive ( msgId , destinationCtx ) ;
239
+ else await waitForRelay ( msgId , destinationCtx ) ;
235
240
236
241
const [ managerBalanceAfterSend , userBalanceAfterSend ] =
237
242
await getManagerAndUserBalance ( sourceCtx ) ;
@@ -253,6 +258,38 @@ export async function transferWithChecks(
253
258
) ;
254
259
}
255
260
261
+ async function waitForRelay (
262
+ msgId : WormholeMessageId ,
263
+ dst : Ctx ,
264
+ retryTime : number = 2000
265
+ ) {
266
+ console . log ( "Sleeping for 1 min to allow signing of VAA" ) ;
267
+ await new Promise ( ( resolve ) => setTimeout ( resolve , 60 * 1000 ) ) ;
268
+
269
+ // long timeout because the relayer has consistency level set to 15
270
+ const vaa = await wh . getVaa ( msgId , "Uint8Array" , 2 * 60 * 1000 ) ;
271
+ const deliveryHash = keccak256 ( vaa ! . hash ) ;
272
+
273
+ const wormholeRelayer = IWormholeRelayer__factory . connect (
274
+ dst . context . config . contracts . relayer ! ,
275
+ await dst . context . getRpc ( )
276
+ ) ;
277
+
278
+ let success = false ;
279
+ while ( ! success ) {
280
+ try {
281
+ const successBlock = await wormholeRelayer . deliverySuccessBlock (
282
+ deliveryHash
283
+ ) ;
284
+ if ( successBlock > 0 ) success = true ;
285
+ console . log ( "Relayer delivery: " , success ) ;
286
+ } catch ( e ) {
287
+ console . error ( e ) ;
288
+ }
289
+ await new Promise ( ( resolve ) => setTimeout ( resolve , retryTime ) ) ;
290
+ }
291
+ }
292
+
256
293
// Wrap signSendWait from sdk to provide full error message
257
294
async function signSendWait (
258
295
ctx : ChainContext < typeof NETWORK > ,
@@ -270,17 +307,7 @@ async function signSendWait(
270
307
async function getNtt (
271
308
ctx : Ctx
272
309
) : Promise < Ntt < typeof NETWORK , typeof ctx . context . chain > > {
273
- const ctor = ctx . context . platform . getProtocolInitializer ( "Ntt" ) ;
274
- // @ts -ignore
275
- return new ctor (
276
- ctx . context . network ,
277
- ctx . context . chain ,
278
- await ctx . context . getRpc ( ) ,
279
- {
280
- ...ctx . context . config . contracts ! ,
281
- ntt : ctx . contracts ,
282
- }
283
- ) ;
310
+ return ctx . context . getProtocol ( "Ntt" , { ntt : ctx . contracts } ) ;
284
311
}
285
312
286
313
function getNativeSigner ( ctx : Partial < Ctx > ) : any {
@@ -304,7 +331,7 @@ async function getSigners(ctx: Partial<Ctx>): Promise<Signers> {
304
331
switch ( platform ) {
305
332
case "Evm" :
306
333
signer = await evm . getSigner ( rpc , nativeSigner ) ;
307
- nativeSigner = ( signer as NativeSigner ) . unwrap ( ) as ethers . Wallet ;
334
+ nativeSigner = ( signer as NativeSigner ) . unwrap ( ) ;
308
335
break ;
309
336
case "Solana" :
310
337
signer = await solana . getSigner ( rpc , nativeSigner ) ;
@@ -323,7 +350,7 @@ async function getSigners(ctx: Partial<Ctx>): Promise<Signers> {
323
350
}
324
351
325
352
async function deployEvm ( ctx : Ctx ) : Promise < Ctx > {
326
- const { signer, nativeSigner : wallet } = ctx . signers ;
353
+ const { signer, nativeSigner : wallet } = ctx . signers as Signers < "Evm" > ;
327
354
328
355
// Deploy libraries used by various things
329
356
console . log ( "Deploying transceiverStructs" ) ;
@@ -412,14 +439,15 @@ async function deployEvm(ctx: Ctx): Promise<Ctx> {
412
439
// // Setup with the proxy
413
440
console . log ( "Deploy transceiver proxy" ) ;
414
441
const transceiverProxyFactory = new ERC1967Proxy__factory ( wallet ) ;
415
- const transceiverProxyAddress = await transceiverProxyFactory . deploy (
442
+ const transceiverProxyDeployment = await transceiverProxyFactory . deploy (
416
443
await WormholeTransceiverAddress . getAddress ( ) ,
417
444
"0x"
418
445
) ;
419
- await transceiverProxyAddress . waitForDeployment ( ) ;
446
+ await transceiverProxyDeployment . waitForDeployment ( ) ;
420
447
448
+ const transceiverProxyAddress = await transceiverProxyDeployment . getAddress ( ) ;
421
449
const transceiver = WormholeTransceiver__factory . connect (
422
- await transceiverProxyAddress . getAddress ( ) ,
450
+ transceiverProxyAddress ,
423
451
wallet
424
452
) ;
425
453
@@ -431,9 +459,7 @@ async function deployEvm(ctx: Ctx): Promise<Ctx> {
431
459
432
460
// Setup the initial calls, like transceivers for the manager
433
461
console . log ( "Set transceiver for manager" ) ;
434
- await tryAndWaitThrice ( ( ) =>
435
- transceiver . getAddress ( ) . then ( ( addr ) => manager . setTransceiver ( addr ) )
436
- ) ;
462
+ await tryAndWaitThrice ( ( ) => manager . setTransceiver ( transceiverProxyAddress ) ) ;
437
463
438
464
console . log ( "Set outbound limit for manager" ) ;
439
465
await tryAndWaitThrice ( ( ) =>
@@ -444,7 +470,7 @@ async function deployEvm(ctx: Ctx): Promise<Ctx> {
444
470
...ctx ,
445
471
contracts : {
446
472
transceiver : {
447
- wormhole : await transceiverProxyAddress . getAddress ( ) ,
473
+ wormhole : transceiverProxyAddress ,
448
474
} ,
449
475
manager : await managerProxyAddress . getAddress ( ) ,
450
476
token : ERC20NTTAddress ,
@@ -453,7 +479,7 @@ async function deployEvm(ctx: Ctx): Promise<Ctx> {
453
479
}
454
480
455
481
async function deploySolana ( ctx : Ctx ) : Promise < Ctx > {
456
- const { signer, nativeSigner : keypair } = ctx . signers ;
482
+ const { signer, nativeSigner : keypair } = ctx . signers as Signers < "Solana" > ;
457
483
const connection = ( await ctx . context . getRpc ( ) ) as Connection ;
458
484
const address = new PublicKey ( signer . address ( ) ) ;
459
485
console . log ( `Using public key: ${ address } ` ) ;
@@ -543,55 +569,59 @@ async function deploySolana(ctx: Ctx): Promise<Ctx> {
543
569
async function setupPeer ( targetCtx : Ctx , peerCtx : Ctx ) {
544
570
const target = targetCtx . context ;
545
571
const peer = peerCtx . context ;
546
-
547
- console . log ( targetCtx . contracts ) ;
548
- console . log ( peerCtx . contracts ) ;
549
-
550
572
const {
551
573
manager,
552
574
transceiver : { wormhole : transceiver } ,
553
575
} = peerCtx . contracts ! ;
554
576
555
- const managerAddress = Wormhole . chainAddress ( peer . chain , manager ) ;
556
- const transceiverEmitter = Wormhole . chainAddress ( peer . chain , transceiver ) ;
577
+ const peerManager = Wormhole . chainAddress ( peer . chain , manager ) ;
578
+ const peerTransceiver = Wormhole . chainAddress ( peer . chain , transceiver ) ;
557
579
558
580
const tokenDecimals = target . config . nativeTokenDecimals ;
559
581
const inboundLimit = amount . units ( amount . parse ( "1000" , tokenDecimals ) ) ;
560
582
561
583
const { signer, address : sender } = targetCtx . signers ;
562
584
563
- // TODO:
564
- // const expectedXcvrAddress = manager.pdas.transceiverPeerAccount(peer.chain);
565
- // console.log("Check me", expectedXcvrAddress);
566
- // const expectedMgrAddress = manager.pdas.peerAccount(peer.chain);
567
- // console.log("Check me", expectedMgrAddress);
568
-
569
585
const nttManager = await getNtt ( targetCtx ) ;
570
586
const setPeerTxs = nttManager . setPeer (
571
- managerAddress ,
587
+ peerManager ,
572
588
tokenDecimals ,
573
589
inboundLimit ,
574
590
sender . address
575
591
) ;
576
592
await signSendWait ( target , setPeerTxs , signer ) ;
577
593
578
594
const setXcvrPeerTxs = nttManager . setWormholeTransceiverPeer (
579
- transceiverEmitter ,
595
+ peerTransceiver ,
580
596
sender . address
581
597
) ;
582
598
const xcvrPeerTxids = await signSendWait ( target , setXcvrPeerTxs , signer ) ;
583
599
const [ whm ] = await target . parseTransaction ( xcvrPeerTxids [ 0 ] ! . txid ) ;
584
- return await wh . getVaa ( whm ! , "Ntt:TransceiverRegistration" ) ;
600
+ console . log ( "Set peers for: " , target . chain , peer . chain ) ;
585
601
586
- // TODO:
587
- // if (targetPlatform === "Evm" && peerPlatform === "Evm") {
588
- // await tryAndWaitThrice(() =>
589
- // transceiver.setIsWormholeEvmChain(peerChainId, true)
590
- // );
591
- // await tryAndWaitThrice(() =>
592
- // transceiver.setIsWormholeRelayingEnabled(peerChainId, true)
593
- // );
594
- // }
602
+ if (
603
+ chainToPlatform ( target . chain ) === "Evm" &&
604
+ chainToPlatform ( peer . chain ) === "Evm"
605
+ ) {
606
+ const nativeSigner = ( signer as NativeSigner ) . unwrap ( ) ;
607
+ const xcvr = WormholeTransceiver__factory . connect (
608
+ targetCtx . contracts ! . transceiver . wormhole ,
609
+ nativeSigner . signer
610
+ ) ;
611
+ const peerChainId = toChainId ( peer . chain ) ;
612
+
613
+ console . log ( "Setting isEvmChain for: " , peer . chain ) ;
614
+ await tryAndWaitThrice ( ( ) =>
615
+ xcvr . setIsWormholeEvmChain . send ( peerChainId , true )
616
+ ) ;
617
+
618
+ console . log ( "Setting wormhole relaying for: " , peer . chain ) ;
619
+ await tryAndWaitThrice ( ( ) =>
620
+ xcvr . setIsWormholeRelayingEnabled . send ( peerChainId , true )
621
+ ) ;
622
+ }
623
+
624
+ return await wh . getVaa ( whm ! , "Ntt:TransceiverRegistration" ) ;
595
625
}
596
626
597
627
async function receive ( msgId : WormholeMessageId , destination : Ctx ) {
@@ -665,6 +695,7 @@ async function tryAndWaitThrice(
665
695
try {
666
696
return await ( await txGen ( ) ) . wait ( ) ;
667
697
} catch ( e ) {
698
+ console . error ( e ) ;
668
699
attempts ++ ;
669
700
if ( attempts < 3 ) {
670
701
console . log ( `retry ${ attempts } ...` ) ;
0 commit comments