@@ -61,9 +61,26 @@ export class EvmNttWormholeTranceiver<N extends Network, C extends EvmChains>
61
61
}
62
62
63
63
async getTransceiverType ( ) : Promise < string > {
64
- // NOTE: We hardcode the type here as transceiver type is only available for versions >1.1.0
65
- // For those versions, we can return `this.transceiver.getTransceiverType()` directly
66
- return "wormhole" ;
64
+ const contract = new Contract (
65
+ this . address ,
66
+ [ "function getTransceiverType() public view returns (string)" ] ,
67
+ this . manager . provider
68
+ ) ;
69
+ try {
70
+ const transceiverType : string = await contract
71
+ . getFunction ( "getTransceiverType" )
72
+ . staticCall ( ) ;
73
+ if ( ! transceiverType ) {
74
+ throw new Error ( "getTransceiverType not found" ) ;
75
+ }
76
+ return Buffer . from ( transceiverType ) . filter ( ( x ) => x !== 0 ) . toString ( ) . trim ( ) ;
77
+ } catch ( e ) {
78
+ console . error ( e ) ; // TODO: only when the method is not available should we return wormhole
79
+ // NOTE: if the transceiver doesn't have a getTransceiverType method, it
80
+ // means it's an old one that didn't have this function exposed.
81
+ // Only wormhole transceivers were deployed using the old version
82
+ return "wormhole"
83
+ }
67
84
}
68
85
69
86
getAddress ( ) : ChainAddress < C > {
@@ -143,6 +160,16 @@ export class EvmNttWormholeTranceiver<N extends Network, C extends EvmChains>
143
160
) ;
144
161
}
145
162
163
+ async isRelayingAvailable ( destination : Chain ) : Promise < boolean > {
164
+ // TODO: how to handle executor?
165
+ const [ wh , special ] = await Promise . all ( [
166
+ this . isWormholeRelayingEnabled ( destination ) ,
167
+ this . isSpecialRelayingEnabled ( destination )
168
+ ] )
169
+
170
+ return wh || special
171
+ }
172
+
146
173
async isWormholeRelayingEnabled ( destChain : Chain ) : Promise < boolean > {
147
174
return await this . transceiver . isWormholeRelayingEnabled (
148
175
toChainId ( destChain )
@@ -186,7 +213,7 @@ export class EvmNtt<N extends Network, C extends EvmChains>
186
213
tokenAddress : string ;
187
214
readonly chainId : bigint ;
188
215
manager : NttManagerBindings . NttManager ;
189
- xcvrs : EvmNttWormholeTranceiver < N , C > [ ] ;
216
+ xcvrs : { [ type : string ] : EvmNttTransceiver < N , C , Ntt . Attestation > } ;
190
217
managerAddress : string ;
191
218
192
219
constructor (
@@ -213,38 +240,52 @@ export class EvmNtt<N extends Network, C extends EvmChains>
213
240
this . provider
214
241
) ;
215
242
216
- this . xcvrs = [ ] ;
217
- if (
218
- "wormhole" in contracts . ntt . transceiver &&
219
- contracts . ntt . transceiver [ "wormhole" ]
220
- ) {
221
- const transceiverTypes = [
222
- "wormhole" , // wormhole xcvr should be ix 0
223
- ...Object . keys ( contracts . ntt . transceiver ) . filter ( ( transceiverType ) => {
224
- transceiverType !== "wormhole" ;
225
- } ) ,
226
- ] ;
227
- transceiverTypes . map ( ( transceiverType ) => {
228
- // we currently only support wormhole transceivers
229
- if ( transceiverType !== "wormhole" ) {
230
- throw new Error ( `Unsupported transceiver type: ${ transceiverType } ` ) ;
231
- }
243
+ this . xcvrs = { } ;
244
+ Object . entries ( contracts . ntt . transceiver ) . map ( ( [ transceiverType , transceiver ] ) => {
245
+ // we currently only support wormhole transceivers
246
+ if ( ! [ "wormhole" , "paxos" ] . includes ( transceiverType ) ) {
247
+ throw new Error ( `Unsupported transceiver type: ${ transceiverType } ` ) ;
248
+ }
232
249
233
- // Enable more Transceivers here
234
- this . xcvrs . push (
235
- new EvmNttWormholeTranceiver (
236
- this ,
237
- contracts . ntt ! . transceiver [ transceiverType ] ! ,
238
- abiBindings !
239
- )
250
+ // Enable more Transceivers here
251
+ this . xcvrs [ transceiverType ] =
252
+ new EvmNttWormholeTranceiver (
253
+ this ,
254
+ transceiver instanceof Object ? transceiver . address : transceiver ,
255
+ abiBindings !
240
256
) ;
241
- } ) ;
242
- }
257
+ } ) ;
243
258
}
244
259
245
- async getTransceiver ( ix : number ) : Promise < NttTransceiver < N , C , any > | null > {
260
+ async getTransceiver ( type : string ) : Promise < NttTransceiver < N , C , any > | null > {
246
261
// TODO: should we make an RPC call here, or just trust that the xcvrs are set up correctly?
247
- return this . xcvrs [ ix ] || null ;
262
+ return this . xcvrs [ type ] || null ;
263
+ }
264
+
265
+ async getTransceivers ( ) : Promise < { [ type : string ] : NttTransceiver < N , C , any > } > {
266
+ return this . xcvrs
267
+ }
268
+
269
+ async isTransceiverRegistered ( type : string ) : Promise < boolean > {
270
+ const transceiver = this . xcvrs [ type ] ;
271
+ if ( ! transceiver ) {
272
+ throw new Error ( `Transceiver not found (${ type } )` ) ;
273
+ }
274
+ const transceivers = await this . manager . getTransceivers ( ) ;
275
+ return transceivers . map ( ( a ) => new EvmAddress ( a ) . unwrap ( ) ) . includes ( new EvmAddress ( transceiver . getAddress ( ) . address ) . unwrap ( ) ) ;
276
+ }
277
+
278
+ async * registerTransceiver ( type : string ) {
279
+ const transceiver = this . xcvrs [ type ] ;
280
+ if ( ! transceiver ) {
281
+ throw new Error ( `Transceiver not found (${ type } )` ) ;
282
+ }
283
+
284
+ const canonicalTransceiver = new EvmAddress ( transceiver . getAddress ( ) . address ) . toString ( ) ;
285
+ const tx = await this . manager . setTransceiver . populateTransaction (
286
+ canonicalTransceiver
287
+ ) ;
288
+ yield this . createUnsignedTx ( tx , "Ntt.registerTransceiver" ) ;
248
289
}
249
290
250
291
async getMode ( ) : Promise < Ntt . Mode > {
@@ -290,19 +331,18 @@ export class EvmNtt<N extends Network, C extends EvmChains>
290
331
yield this . createUnsignedTx ( tx , "Ntt.setPauser" ) ;
291
332
}
292
333
334
+ async * setThreshold ( threshold : number ) {
335
+ const tx = await this . manager . setThreshold . populateTransaction ( threshold ) ;
336
+ yield this . createUnsignedTx ( tx , "Ntt.setThreshold" ) ;
337
+ }
338
+
293
339
async getThreshold ( ) : Promise < number > {
294
340
return Number ( await this . manager . getThreshold ( ) ) ;
295
341
}
296
342
297
343
async isRelayingAvailable ( destination : Chain ) : Promise < boolean > {
298
344
const enabled = await Promise . all (
299
- this . xcvrs . map ( async ( x ) => {
300
- const [ wh , special ] = await Promise . all ( [
301
- x . isWormholeRelayingEnabled ( destination ) ,
302
- x . isSpecialRelayingEnabled ( destination ) ,
303
- ] ) ;
304
- return wh || special ;
305
- } )
345
+ Object . values ( this . xcvrs ) . map ( ( x ) => x . isRelayingAvailable ( destination ) )
306
346
) ;
307
347
308
348
return enabled . filter ( ( x ) => x ) . length > 0 ;
@@ -387,7 +427,7 @@ export class EvmNtt<N extends Network, C extends EvmChains>
387
427
388
428
ixs . push ( {
389
429
index : 0 ,
390
- payload : this . xcvrs [ 0 ] ! . encodeFlags ( { skipRelay : ! options . automatic } ) ,
430
+ payload : ( this . xcvrs [ "wormhole" ] ! as EvmNttWormholeTranceiver < N , C > ) . encodeFlags ( { skipRelay : ! options . automatic } ) ,
391
431
} ) ;
392
432
393
433
return ixs ;
@@ -448,14 +488,14 @@ export class EvmNtt<N extends Network, C extends EvmChains>
448
488
}
449
489
450
490
async * setWormholeTransceiverPeer ( peer : ChainAddress < C > ) {
451
- yield * this . setTransceiverPeer ( 0 , peer ) ;
491
+ yield * this . setTransceiverPeer ( "wormhole" , peer ) ;
452
492
}
453
493
454
- async * setTransceiverPeer ( ix : number , peer : ChainAddress < C > ) {
455
- if ( ix >= this . xcvrs . length ) {
456
- throw new Error ( " Transceiver not found" ) ;
494
+ async * setTransceiverPeer ( type : string , peer : ChainAddress < C > ) {
495
+ if ( ! this . xcvrs [ type ] ) {
496
+ throw new Error ( ` Transceiver not found ( ${ type } )` ) ;
457
497
}
458
- yield * this . xcvrs [ ix ] ! . setPeer ( peer ) ;
498
+ yield * this . xcvrs [ type ] ! . setPeer ( peer ) ;
459
499
}
460
500
461
501
async * transfer (
@@ -506,22 +546,15 @@ export class EvmNtt<N extends Network, C extends EvmChains>
506
546
yield this . createUnsignedTx ( addFrom ( txReq , senderAddress ) , "Ntt.transfer" ) ;
507
547
}
508
548
509
- // TODO: should this be some map of idx to transceiver?
510
- async * redeem ( attestations : Ntt . Attestation [ ] ) {
511
- if ( attestations . length !== this . xcvrs . length )
512
- throw new Error (
513
- "Not enough attestations for the registered Transceivers"
514
- ) ;
515
-
516
- for ( const idx in this . xcvrs ) {
517
- const xcvr = this . xcvrs [ idx ] ! ;
518
- const attestation = attestations [ idx ] ;
549
+ async * redeem ( attestations : { [ type : string ] : Ntt . Attestation } ) {
550
+ for ( const [ transceiverType , transceiver ] of Object . entries ( this . xcvrs ) ) {
551
+ const attestation = attestations [ transceiverType ] ;
519
552
if ( attestation ?. payloadName !== "WormholeTransfer" ) {
520
553
// TODO: support standard relayer attestations
521
554
// which must be submitted to the delivery provider
522
555
throw new Error ( "Invalid attestation type for redeem" ) ;
523
556
}
524
- yield * xcvr . receive ( attestation ) ;
557
+ yield * transceiver . receive ( attestation ) ;
525
558
}
526
559
}
527
560
@@ -605,21 +638,22 @@ export class EvmNtt<N extends Network, C extends EvmChains>
605
638
const local : Partial < Ntt . Contracts > = {
606
639
manager : this . managerAddress ,
607
640
token : this . tokenAddress ,
608
- transceiver : {
609
- ...( this . xcvrs . length > 0 && { wormhole : this . xcvrs [ 0 ] ! . address } ) ,
610
- } ,
641
+ transceiver : Object . fromEntries ( Object . entries ( this . xcvrs ) . map ( ( [ type , xcvr ] ) => [ type , { address : xcvr . getAddress ( ) . address . toString ( ) } ] ) ) ,
611
642
// TODO: what about the quoter?
612
643
} ;
613
644
614
645
const remote : Partial < Ntt . Contracts > = {
615
646
manager : this . managerAddress ,
616
647
token : await this . manager . token ( ) ,
617
648
transceiver : {
618
- wormhole : ( await this . manager . getTransceivers ( ) ) [ 0 ] ! , // TODO: make this more generic
649
+ wormhole : {
650
+ address : ( await this . manager . getTransceivers ( ) ) [ 0 ] ! , // TODO: make this more generic
651
+ }
619
652
} ,
620
653
} ;
621
654
622
655
const deleteMatching = ( a : any , b : any ) => {
656
+ if ( ! b || ! a ) return ;
623
657
for ( const k in a ) {
624
658
if ( typeof a [ k ] === "object" ) {
625
659
deleteMatching ( a [ k ] , b [ k ] ) ;
0 commit comments