1
1
import {
2
2
Chain ,
3
3
Network ,
4
+ encoding ,
4
5
nativeChainIds ,
5
6
toChainId ,
6
7
} from "@wormhole-foundation/sdk-base" ;
@@ -9,10 +10,12 @@ import {
9
10
ChainAddress ,
10
11
ChainsConfig ,
11
12
Contracts ,
13
+ canonicalAddress ,
12
14
serialize ,
15
+ toUniversal ,
13
16
universalAddress ,
14
17
} from "@wormhole-foundation/sdk-definitions" ;
15
- import type { EvmChains , EvmPlatformType } from "@wormhole-foundation/sdk-evm" ;
18
+ import type { AnyEvmAddress , EvmChains , EvmPlatformType } from "@wormhole-foundation/sdk-evm" ;
16
19
import {
17
20
EvmAddress ,
18
21
EvmPlatform ,
@@ -36,8 +39,7 @@ import {
36
39
} from "./bindings.js" ;
37
40
38
41
export class EvmNttWormholeTranceiver < N extends Network , C extends EvmChains >
39
- implements NttTransceiver < N , C , WormholeNttTransceiver . VAA >
40
- {
42
+ implements NttTransceiver < N , C , WormholeNttTransceiver . VAA > {
41
43
transceiver : NttTransceiverBindings . NttTransceiver ;
42
44
constructor (
43
45
readonly manager : EvmNtt < N , C > ,
@@ -50,17 +52,59 @@ export class EvmNttWormholeTranceiver<N extends Network, C extends EvmChains>
50
52
) ;
51
53
}
52
54
55
+ getAddress ( ) : ChainAddress < C > {
56
+ return { chain : this . manager . chain , address : toUniversal ( this . manager . chain , this . address ) } ;
57
+ }
58
+
53
59
encodeFlags ( flags : { skipRelay : boolean } ) : Uint8Array {
54
60
return new Uint8Array ( [ flags . skipRelay ? 1 : 0 ] ) ;
55
61
}
56
62
57
- async * setPeer ( peer : ChainAddress < C > ) {
63
+ async * setPeer < P extends Chain > ( peer : ChainAddress < P > ) : AsyncGenerator < EvmUnsignedTransaction < N , C > > {
58
64
const tx = await this . transceiver . setWormholePeer . populateTransaction (
59
65
toChainId ( peer . chain ) ,
60
66
universalAddress ( peer )
61
67
) ;
62
68
yield this . manager . createUnsignedTx ( tx , "WormholeTransceiver.registerPeer" ) ;
63
69
}
70
+
71
+ async getPauser ( ) : Promise < AccountAddress < C > | null > {
72
+ const pauser = await this . transceiver . pauser ( ) ;
73
+ return new EvmAddress ( pauser ) as AccountAddress < C > ;
74
+ }
75
+
76
+ async * setPauser ( pauser : AccountAddress < C > ) {
77
+ const canonicalPauser = canonicalAddress ( { chain : this . manager . chain , address : pauser } ) ;
78
+ const tx = await this . transceiver . transferPauserCapability . populateTransaction ( canonicalPauser ) ;
79
+ yield this . manager . createUnsignedTx ( tx , "WormholeTransceiver.setPauser" ) ;
80
+ }
81
+
82
+ async getPeer < C extends Chain > ( chain : C ) : Promise < ChainAddress < C > | null > {
83
+ const peer = await this . transceiver . getWormholePeer ( toChainId ( chain ) ) ;
84
+ const peerAddress = encoding . hex . decode ( peer ) ;
85
+ const zeroAddress = new Uint8Array ( 32 ) ;
86
+ if ( encoding . bytes . equals ( zeroAddress , peerAddress ) ) {
87
+ return null ;
88
+ }
89
+
90
+ return {
91
+ chain : chain ,
92
+ address : toUniversal ( chain , peerAddress ) ,
93
+ } ;
94
+ }
95
+
96
+ async isEvmChain ( chain : Chain ) : Promise < boolean > {
97
+ return await this . transceiver . isWormholeEvmChain ( toChainId ( chain ) ) ;
98
+ }
99
+
100
+ async * setIsEvmChain ( chain : Chain , isEvm : boolean ) {
101
+ const tx = await this . transceiver . setIsWormholeEvmChain . populateTransaction (
102
+ toChainId ( chain ) ,
103
+ isEvm
104
+ ) ;
105
+ yield this . manager . createUnsignedTx ( tx , "WormholeTransceiver.setIsEvmChain" ) ;
106
+ }
107
+
64
108
async * receive ( attestation : WormholeNttTransceiver . VAA ) {
65
109
const tx = await this . transceiver . receiveMessage . populateTransaction (
66
110
serialize ( attestation )
@@ -77,6 +121,17 @@ export class EvmNttWormholeTranceiver<N extends Network, C extends EvmChains>
77
121
) ;
78
122
}
79
123
124
+ async * setIsWormholeRelayingEnabled ( destChain : Chain , enabled : boolean ) {
125
+ const tx = await this . transceiver . setIsWormholeRelayingEnabled . populateTransaction (
126
+ toChainId ( destChain ) ,
127
+ enabled
128
+ ) ;
129
+ yield this . manager . createUnsignedTx (
130
+ tx ,
131
+ "WormholeTransceiver.setWormholeRelayingEnabled"
132
+ ) ;
133
+ }
134
+
80
135
async isSpecialRelayingEnabled ( destChain : Chain ) : Promise < boolean > {
81
136
return await this . transceiver . isSpecialRelayingEnabled (
82
137
toChainId ( destChain )
@@ -85,8 +140,7 @@ export class EvmNttWormholeTranceiver<N extends Network, C extends EvmChains>
85
140
}
86
141
87
142
export class EvmNtt < N extends Network , C extends EvmChains >
88
- implements Ntt < N , C >
89
- {
143
+ implements Ntt < N , C > {
90
144
tokenAddress : string ;
91
145
readonly chainId : bigint ;
92
146
manager : NttManagerBindings . NttManager ;
@@ -117,14 +171,66 @@ export class EvmNtt<N extends Network, C extends EvmChains>
117
171
this . provider
118
172
) ;
119
173
120
- this . xcvrs = [
121
- // Enable more Transceivers here
122
- new EvmNttWormholeTranceiver (
123
- this ,
124
- contracts . ntt . transceiver . wormhole ! ,
125
- abiBindings !
126
- ) ,
127
- ] ;
174
+ if ( contracts . ntt . transceiver . wormhole != null ) {
175
+ this . xcvrs = [
176
+ // Enable more Transceivers here
177
+ new EvmNttWormholeTranceiver (
178
+ this ,
179
+ contracts . ntt . transceiver . wormhole ,
180
+ abiBindings !
181
+ ) ,
182
+ ] ;
183
+ } else {
184
+ this . xcvrs = [ ] ;
185
+ }
186
+ }
187
+
188
+ async getTransceiver ( ix : number ) : Promise < NttTransceiver < N , C , any > | null > {
189
+ // TODO: should we make an RPC call here, or just trust that the xcvrs are set up correctly?
190
+ return this . xcvrs [ ix ] || null ;
191
+ }
192
+
193
+ async getMode ( ) : Promise < Ntt . Mode > {
194
+ const mode : bigint = await this . manager . getMode ( ) ;
195
+ return mode === 0n ? "locking" : "burning" ;
196
+ }
197
+
198
+ async isPaused ( ) : Promise < boolean > {
199
+ return await this . manager . isPaused ( ) ;
200
+ }
201
+
202
+ async * pause ( ) {
203
+ const tx = await this . manager . pause . populateTransaction ( )
204
+ yield this . createUnsignedTx ( tx , "Ntt.pause" ) ;
205
+ }
206
+
207
+ async * unpause ( ) {
208
+ const tx = await this . manager . unpause . populateTransaction ( )
209
+ yield this . createUnsignedTx ( tx , "Ntt.unpause" ) ;
210
+ }
211
+
212
+ async getOwner ( ) : Promise < AccountAddress < C > > {
213
+ return new EvmAddress ( await this . manager . owner ( ) ) as AccountAddress < C > ;
214
+ }
215
+
216
+ async getPauser ( ) : Promise < AccountAddress < C > | null > {
217
+ return new EvmAddress ( await this . manager . pauser ( ) ) as AccountAddress < C > ;
218
+ }
219
+
220
+ async * setOwner ( owner : AnyEvmAddress ) {
221
+ const canonicalOwner = new EvmAddress ( owner ) . toString ( ) ;
222
+ const tx = await this . manager . transferOwnership . populateTransaction ( canonicalOwner ) ;
223
+ yield this . createUnsignedTx ( tx , "Ntt.setOwner" ) ;
224
+ }
225
+
226
+ async * setPauser ( pauser : AnyEvmAddress ) {
227
+ const canonicalPauser = new EvmAddress ( pauser ) . toString ( ) ;
228
+ const tx = await this . manager . transferPauserCapability . populateTransaction ( canonicalPauser ) ;
229
+ yield this . createUnsignedTx ( tx , "Ntt.setPauser" ) ;
230
+ }
231
+
232
+ async getThreshold ( ) : Promise < number > {
233
+ return Number ( await this . manager . getThreshold ( ) ) ;
128
234
}
129
235
130
236
async isRelayingAvailable ( destination : Chain ) : Promise < boolean > {
@@ -187,6 +293,21 @@ export class EvmNtt<N extends Network, C extends EvmChains>
187
293
) ;
188
294
}
189
295
296
+ async getPeer < C extends Chain > ( chain : C ) : Promise < Ntt . Peer < C > | null > {
297
+ const peer = await this . manager . getPeer ( toChainId ( chain ) ) ;
298
+ const peerAddress = encoding . hex . decode ( peer . peerAddress ) ;
299
+ const zeroAddress = new Uint8Array ( 32 ) ;
300
+ if ( encoding . bytes . equals ( zeroAddress , peerAddress ) ) {
301
+ return null ;
302
+ }
303
+
304
+ return {
305
+ address : { chain : chain , address : toUniversal ( chain , peerAddress ) } ,
306
+ tokenDecimals : Number ( peer . tokenDecimals ) ,
307
+ inboundLimit : await this . getInboundLimit ( chain ) ,
308
+ } ;
309
+ }
310
+
190
311
static async fromRpc < N extends Network > (
191
312
provider : Provider ,
192
313
config : ChainsConfig < N , EvmPlatformType >
@@ -342,10 +463,39 @@ export class EvmNtt<N extends Network, C extends EvmChains>
342
463
return await this . manager . getCurrentOutboundCapacity ( ) ;
343
464
}
344
465
466
+ async getOutboundLimit ( ) : Promise < bigint > {
467
+ const encoded : EncodedTrimmedAmount = ( await this . manager . getOutboundLimitParams ( ) ) . limit ;
468
+ const trimmedAmount : TrimmedAmount = decodeTrimmedAmount ( encoded ) ;
469
+ const tokenDecimals = await this . getTokenDecimals ( ) ;
470
+
471
+ return untrim ( trimmedAmount , tokenDecimals ) ;
472
+ }
473
+
474
+ async * setOutboundLimit ( limit : bigint ) {
475
+ const tx = await this . manager . setOutboundLimit . populateTransaction ( limit ) ;
476
+ yield this . createUnsignedTx ( tx , "Ntt.setOutboundLimit" ) ;
477
+ }
478
+
345
479
async getCurrentInboundCapacity ( fromChain : Chain ) : Promise < bigint > {
346
480
return await this . manager . getCurrentInboundCapacity ( toChainId ( fromChain ) ) ;
347
481
}
348
482
483
+ async getInboundLimit ( fromChain : Chain ) : Promise < bigint > {
484
+ const encoded : EncodedTrimmedAmount = ( await this . manager . getInboundLimitParams ( toChainId ( fromChain ) ) ) . limit ;
485
+ const trimmedAmount : TrimmedAmount = decodeTrimmedAmount ( encoded ) ;
486
+ const tokenDecimals = await this . getTokenDecimals ( ) ;
487
+
488
+ return untrim ( trimmedAmount , tokenDecimals ) ;
489
+ }
490
+
491
+ async * setInboundLimit ( fromChain : Chain , limit : bigint ) {
492
+ const tx = await this . manager . setInboundLimit . populateTransaction (
493
+ limit ,
494
+ toChainId ( fromChain )
495
+ ) ;
496
+ yield this . createUnsignedTx ( tx , "Ntt.setInboundLimit" ) ;
497
+ }
498
+
349
499
async getRateLimitDuration ( ) : Promise < bigint > {
350
500
return await this . manager . rateLimitDuration ( ) ;
351
501
}
@@ -381,6 +531,40 @@ export class EvmNtt<N extends Network, C extends EvmChains>
381
531
yield this . createUnsignedTx ( tx , "Ntt.completeInboundQueuedTransfer" ) ;
382
532
}
383
533
534
+ async verifyAddresses ( ) : Promise < Partial < Ntt . Contracts > | null > {
535
+ const local : Partial < Ntt . Contracts > = {
536
+ manager : this . managerAddress ,
537
+ token : this . tokenAddress ,
538
+ transceiver : {
539
+ wormhole : this . xcvrs [ 0 ] ?. address ,
540
+ } ,
541
+ // TODO: what about the quoter?
542
+ } ;
543
+
544
+ const remote : Partial < Ntt . Contracts > = {
545
+ manager : this . managerAddress ,
546
+ token : await this . manager . token ( ) ,
547
+ transceiver : {
548
+ wormhole : ( await this . manager . getTransceivers ( ) ) [ 0 ] ! // TODO: make this more generic
549
+ } ,
550
+ } ;
551
+
552
+ const deleteMatching = ( a : any , b : any ) => {
553
+ for ( const k in a ) {
554
+ if ( typeof a [ k ] === "object" ) {
555
+ deleteMatching ( a [ k ] , b [ k ] ) ;
556
+ if ( Object . keys ( a [ k ] ) . length === 0 ) delete a [ k ] ;
557
+ } else if ( a [ k ] === b [ k ] ) {
558
+ delete a [ k ] ;
559
+ }
560
+ }
561
+ }
562
+
563
+ deleteMatching ( remote , local ) ;
564
+
565
+ return Object . keys ( remote ) . length > 0 ? remote : null ;
566
+ }
567
+
384
568
createUnsignedTx (
385
569
txReq : TransactionRequest ,
386
570
description : string ,
@@ -395,3 +579,36 @@ export class EvmNtt<N extends Network, C extends EvmChains>
395
579
) ;
396
580
}
397
581
}
582
+
583
+ type EncodedTrimmedAmount = bigint ; // uint72
584
+
585
+ type TrimmedAmount = {
586
+ amount : bigint ;
587
+ decimals : number ;
588
+ } ;
589
+
590
+ function decodeTrimmedAmount ( encoded : EncodedTrimmedAmount ) : TrimmedAmount {
591
+ const decimals = Number ( encoded & 0xffn ) ;
592
+ const amount = encoded >> 8n ;
593
+ return {
594
+ amount,
595
+ decimals,
596
+ } ;
597
+ }
598
+
599
+ function untrim ( trimmed : TrimmedAmount , toDecimals : number ) : bigint {
600
+ const { amount, decimals : fromDecimals } = trimmed ;
601
+ return scale ( amount , fromDecimals , toDecimals ) ;
602
+ }
603
+
604
+ function scale ( amount : bigint , fromDecimals : number , toDecimals : number ) : bigint {
605
+ if ( fromDecimals == toDecimals ) {
606
+ return amount ;
607
+ }
608
+
609
+ if ( fromDecimals > toDecimals ) {
610
+ return amount / ( 10n ** BigInt ( fromDecimals - toDecimals ) ) ;
611
+ } else {
612
+ return amount * ( 10n ** BigInt ( toDecimals - fromDecimals ) ) ;
613
+ }
614
+ }
0 commit comments