@@ -54,7 +54,8 @@ import {
54
54
ReservedFastFillSequence ,
55
55
RouterEndpoint ,
56
56
} from "./state" ;
57
- import { ChainId , toChainId , isChainId } from "@wormhole-foundation/sdk-base" ;
57
+ import { ChainId , toChainId , isChainId , Chain } from "@wormhole-foundation/sdk-base" ;
58
+ import { programDerivedAddresses } from "./pdas" ;
58
59
59
60
export const PROGRAM_IDS = [
60
61
"MatchingEngine11111111111111111111111111111" ,
@@ -218,12 +219,16 @@ export type ReserveFastFillSequenceCompositeOpts = {
218
219
export class MatchingEngineProgram {
219
220
private _programId : ProgramId ;
220
221
private _mint : PublicKey ;
222
+ private _custodian ?: Custodian ;
223
+
224
+ pdas : ReturnType < typeof programDerivedAddresses > ;
221
225
222
226
program : Program < MatchingEngine > ;
223
227
224
228
constructor ( connection : Connection , programId : ProgramId , mint : PublicKey ) {
225
229
this . _programId = programId ;
226
230
this . _mint = mint ;
231
+ this . pdas = programDerivedAddresses ( new PublicKey ( programId ) , mint ) ;
227
232
this . program = new Program (
228
233
{ ...( IDL as any ) , address : this . _programId } ,
229
234
{
@@ -346,21 +351,16 @@ export class MatchingEngineProgram {
346
351
return this . program . addEventListener ( "fastFillRedeemed" , callback ) ;
347
352
}
348
353
349
- eventAuthorityAddress ( ) : PublicKey {
350
- return PublicKey . findProgramAddressSync ( [ Buffer . from ( "__event_authority" ) ] , this . ID ) [ 0 ] ;
351
- }
352
-
353
- custodianAddress ( ) : PublicKey {
354
- return Custodian . address ( this . ID ) ;
354
+ /** Get the cached Custodian if it exists, otherwise fetch the latest and cache it */
355
+ async getCustodian ( skipCache ?: boolean ) : Promise < Custodian > {
356
+ if ( this . _custodian === undefined || skipCache )
357
+ this . _custodian = await this . fetchCustodian ( ) ;
358
+ return this . _custodian ! ;
355
359
}
356
360
357
- async fetchCustodian ( input ?: { address : PublicKey } ) : Promise < Custodian > {
358
- const addr = input === undefined ? this . custodianAddress ( ) : input . address ;
359
- return this . program . account . custodian . fetch ( addr ) ;
360
- }
361
-
362
- auctionConfigAddress ( id : number ) : PublicKey {
363
- return AuctionConfig . address ( this . ID , id ) ;
361
+ /** Fetch the latest custodian data */
362
+ async fetchCustodian ( ) : Promise < Custodian > {
363
+ return this . program . account . custodian . fetch ( this . custodianAddress ( ) ) ;
364
364
}
365
365
366
366
async fetchAuctionConfig ( input : number | { address : PublicKey } ) : Promise < AuctionConfig > {
@@ -370,20 +370,12 @@ export class MatchingEngineProgram {
370
370
371
371
async fetchAuctionParameters ( id ?: number ) : Promise < AuctionParameters > {
372
372
if ( id === undefined ) {
373
- const { auctionConfigId } = await this . fetchCustodian ( ) ;
373
+ const { auctionConfigId } = await this . getCustodian ( ) ;
374
374
id = auctionConfigId ;
375
375
}
376
376
return this . fetchAuctionConfig ( id ) . then ( ( config ) => config . parameters ) ;
377
377
}
378
378
379
- cctpMintRecipientAddress ( ) : PublicKey {
380
- return splToken . getAssociatedTokenAddressSync ( this . mint , this . custodianAddress ( ) , true ) ;
381
- }
382
-
383
- routerEndpointAddress ( chain : ChainId ) : PublicKey {
384
- return RouterEndpoint . address ( this . ID , chain ) ;
385
- }
386
-
387
379
async fetchRouterEndpoint ( input : ChainId | { address : PublicKey } ) : Promise < RouterEndpoint > {
388
380
const addr =
389
381
typeof input == "object" && "address" in input
@@ -397,39 +389,18 @@ export class MatchingEngineProgram {
397
389
return info ;
398
390
}
399
391
400
- auctionAddress ( vaaHash : VaaHash ) : PublicKey {
401
- return Auction . address ( this . ID , vaaHash ) ;
402
- }
403
-
404
392
async fetchAuction ( input : VaaHash | { address : PublicKey } ) : Promise < Auction > {
405
393
const addr = "address" in input ? input . address : this . auctionAddress ( input ) ;
406
394
// @ts -ignore This is BS. This is correct.
407
395
return this . program . account . auction . fetch ( addr ) ;
408
396
}
409
397
410
- async proposalAddress ( proposalId ?: Uint64 ) : Promise < PublicKey > {
411
- if ( proposalId === undefined ) {
412
- const { nextProposalId } = await this . fetchCustodian ( ) ;
413
- proposalId = nextProposalId ;
414
- }
415
-
416
- return Proposal . address ( this . ID , proposalId ) ;
417
- }
418
-
419
398
async fetchProposal ( input ?: { address : PublicKey } ) : Promise < Proposal > {
420
399
const addr = input === undefined ? await this . proposalAddress ( ) : input . address ;
421
400
// @ts -ignore This is BS. This is correct.
422
401
return this . program . account . proposal . fetch ( addr ) ;
423
402
}
424
403
425
- coreMessageAddress ( auction : PublicKey ) : PublicKey {
426
- return coreMessageAddress ( this . ID , auction ) ;
427
- }
428
-
429
- cctpMessageAddress ( auction : PublicKey ) : PublicKey {
430
- return cctpMessageAddress ( this . ID , auction ) ;
431
- }
432
-
433
404
async reclaimCctpMessageIx (
434
405
accounts : {
435
406
payer : PublicKey ;
@@ -440,48 +411,20 @@ export class MatchingEngineProgram {
440
411
return reclaimCctpMessageIx ( this . messageTransmitterProgram ( ) , accounts , cctpAttestation ) ;
441
412
}
442
413
443
- preparedOrderResponseAddress ( fastVaaHash : VaaHash ) : PublicKey {
444
- return PreparedOrderResponse . address ( this . ID , fastVaaHash ) ;
445
- }
446
-
447
414
async fetchPreparedOrderResponse (
448
415
input : VaaHash | { address : PublicKey } ,
449
416
) : Promise < PreparedOrderResponse > {
450
417
const addr = "address" in input ? input . address : this . preparedOrderResponseAddress ( input ) ;
451
418
return this . program . account . preparedOrderResponse . fetch ( addr ) ;
452
419
}
453
420
454
- preparedCustodyTokenAddress ( preparedOrderResponse : PublicKey ) : PublicKey {
455
- return PublicKey . findProgramAddressSync (
456
- [ Buffer . from ( "prepared-custody" ) , preparedOrderResponse . toBuffer ( ) ] ,
457
- this . ID ,
458
- ) [ 0 ] ;
459
- }
460
-
461
- auctionCustodyTokenAddress ( auction : PublicKey ) : PublicKey {
462
- return PublicKey . findProgramAddressSync (
463
- [ Buffer . from ( "auction-custody" ) , auction . toBuffer ( ) ] ,
464
- this . ID ,
465
- ) [ 0 ] ;
466
- }
467
-
468
421
async fetchAuctionCustodyTokenBalance ( auction : PublicKey ) : Promise < bigint > {
469
422
return splToken
470
423
. getAccount ( this . program . provider . connection , this . auctionCustodyTokenAddress ( auction ) )
471
424
. then ( ( token ) => token . amount )
472
425
. catch ( ( _ ) => 0n ) ;
473
426
}
474
427
475
- localCustodyTokenAddress ( sourceChain : ChainId ) : PublicKey {
476
- const encodedSourceChain = Buffer . alloc ( 2 ) ;
477
- encodedSourceChain . writeUInt16BE ( sourceChain ) ;
478
-
479
- return PublicKey . findProgramAddressSync (
480
- [ Buffer . from ( "local-custody" ) , encodedSourceChain ] ,
481
- this . ID ,
482
- ) [ 0 ] ;
483
- }
484
-
485
428
async fetchLocalCustodyTokenBalance ( sourceChain : ChainId ) : Promise < bigint > {
486
429
return splToken
487
430
. getAccount (
@@ -492,32 +435,20 @@ export class MatchingEngineProgram {
492
435
. catch ( ( _ ) => 0n ) ;
493
436
}
494
437
495
- fastFillAddress ( sourceChain : ChainId , orderSender : Array < number > , sequence : Uint64 ) : PublicKey {
496
- return FastFill . address ( this . ID , sourceChain , orderSender , sequence ) ;
497
- }
498
-
499
438
fetchFastFill (
500
439
input : [ ChainId , Array < number > , Uint64 ] | { address : PublicKey } ,
501
440
) : Promise < FastFill > {
502
441
const addr = "address" in input ? input . address : this . fastFillAddress ( ...input ) ;
503
442
return this . program . account . fastFill . fetch ( addr ) ;
504
443
}
505
444
506
- fastFillSequencerAddress ( sourceChain : ChainId , sender : Array < number > ) : PublicKey {
507
- return FastFillSequencer . address ( this . ID , sourceChain , sender ) ;
508
- }
509
-
510
445
fetchFastFillSequencer (
511
446
input : [ ChainId , Array < number > ] | { address : PublicKey } ,
512
447
) : Promise < FastFillSequencer > {
513
448
const addr = "address" in input ? input . address : this . fastFillSequencerAddress ( ...input ) ;
514
449
return this . program . account . fastFillSequencer . fetch ( addr ) ;
515
450
}
516
451
517
- reservedFastFillSequenceAddress ( fastVaaHash : VaaHash ) : PublicKey {
518
- return ReservedFastFillSequence . address ( this . ID , fastVaaHash ) ;
519
- }
520
-
521
452
fetchReservedFastFillSequence (
522
453
input : VaaHash | { address : PublicKey } ,
523
454
) : Promise < ReservedFastFillSequence > {
@@ -526,19 +457,6 @@ export class MatchingEngineProgram {
526
457
return this . program . account . reservedFastFillSequence . fetch ( addr ) ;
527
458
}
528
459
529
- transferAuthorityAddress ( auction : PublicKey , offerPrice : Uint64 ) : PublicKey {
530
- const encodedOfferPrice = Buffer . alloc ( 8 ) ;
531
- writeUint64BE ( encodedOfferPrice , offerPrice ) ;
532
- return PublicKey . findProgramAddressSync (
533
- [ Buffer . from ( "transfer-authority" ) , auction . toBuffer ( ) , encodedOfferPrice ] ,
534
- this . ID ,
535
- ) [ 0 ] ;
536
- }
537
-
538
- auctionHistoryAddress ( id : Uint64 ) : PublicKey {
539
- return AuctionHistory . address ( this . ID , id ) ;
540
- }
541
-
542
460
// Anchor is having trouble deserializing the account data here. Manually deserializing
543
461
// the auction history is a workaround, and necessary after changing the redeemer message
544
462
// length from a u32 to a u16.
@@ -1134,7 +1052,7 @@ export class MatchingEngineProgram {
1134
1052
proposal ??= await this . proposalAddress ( opts . proposalId ) ;
1135
1053
1136
1054
if ( auctionConfig === undefined ) {
1137
- const { auctionConfigId } = await this . fetchCustodian ( ) ;
1055
+ const { auctionConfigId } = await this . getCustodian ( true ) ;
1138
1056
// Add 1 to the current auction config ID to get the next one.
1139
1057
auctionConfig = this . auctionConfigAddress ( auctionConfigId + 1 ) ;
1140
1058
}
@@ -1290,8 +1208,8 @@ export class MatchingEngineProgram {
1290
1208
async placeInitialOfferCctpIx (
1291
1209
accounts : {
1292
1210
payer : PublicKey ;
1293
- feePayer ?: PublicKey ;
1294
1211
fastVaa : PublicKey ;
1212
+ feePayer ?: PublicKey ;
1295
1213
offerToken ?: PublicKey ;
1296
1214
auction ?: PublicKey ;
1297
1215
auctionConfig ?: PublicKey ;
@@ -1306,10 +1224,9 @@ export class MatchingEngineProgram {
1306
1224
[ approveIx : TransactionInstruction , placeInitialOfferCctpIx : TransactionInstruction ]
1307
1225
> {
1308
1226
const { payer, feePayer, fastVaa } = accounts ;
1227
+ let { auction, auctionConfig, offerToken, fromRouterEndpoint, toRouterEndpoint } = accounts ;
1309
1228
1310
1229
const { offerPrice } = args ;
1311
-
1312
- let { auction, auctionConfig, offerToken, fromRouterEndpoint, toRouterEndpoint } = accounts ;
1313
1230
let { totalDeposit } = args ;
1314
1231
1315
1232
offerToken ??= await splToken . getAssociatedTokenAddress ( this . mint , payer ) ;
@@ -1329,7 +1246,7 @@ export class MatchingEngineProgram {
1329
1246
}
1330
1247
toRouterEndpoint ??= this . routerEndpointAddress ( toChainId ( fastMarketOrder . targetChain ) ) ;
1331
1248
1332
- const custodianData = await this . fetchCustodian ( ) ;
1249
+ const custodianData = await this . getCustodian ( ) ;
1333
1250
fetchedConfigId = custodianData . auctionConfigId ;
1334
1251
1335
1252
const notionalDeposit = await this . computeNotionalSecurityDeposit (
@@ -1342,7 +1259,7 @@ export class MatchingEngineProgram {
1342
1259
1343
1260
if ( auctionConfig === undefined ) {
1344
1261
if ( fetchedConfigId === null ) {
1345
- const custodianData = await this . fetchCustodian ( ) ;
1262
+ const custodianData = await this . getCustodian ( ) ;
1346
1263
fetchedConfigId = custodianData . auctionConfigId ;
1347
1264
}
1348
1265
auctionConfig = this . auctionConfigAddress ( fetchedConfigId ) ;
@@ -1740,7 +1657,7 @@ export class MatchingEngineProgram {
1740
1657
sequence ??= fastFillSeeds . sequence ;
1741
1658
}
1742
1659
1743
- const { feeRecipientToken } = await this . fetchCustodian ( ) ;
1660
+ const { feeRecipientToken } = await this . getCustodian ( ) ;
1744
1661
1745
1662
return this . program . methods
1746
1663
. settleAuctionNoneLocal ( )
@@ -1820,7 +1737,7 @@ export class MatchingEngineProgram {
1820
1737
tokenMessengerMinterProgram,
1821
1738
} = await this . burnAndPublishAccounts ( auction , { targetChain } ) ;
1822
1739
1823
- const { feeRecipientToken } = await this . fetchCustodian ( ) ;
1740
+ const { feeRecipientToken } = await this . getCustodian ( ) ;
1824
1741
1825
1742
return this . program . methods
1826
1743
. settleAuctionNoneCctp ( )
@@ -2558,6 +2475,46 @@ export class MatchingEngineProgram {
2558
2475
( uint64ToBigInt ( amountIn ) * BigInt ( securityDepositBps ) ) / FEE_PRECISION_MAX
2559
2476
) ;
2560
2477
}
2478
+
2479
+ async proposalAddress ( proposalId ?: Uint64 ) : Promise < PublicKey > {
2480
+ if ( proposalId === undefined ) {
2481
+ // Intentionally skip cache to get a fresh proposal ID.
2482
+ ( { nextProposalId : proposalId } = await this . getCustodian ( true ) ) ;
2483
+ }
2484
+
2485
+ return this . pdas . proposal ( proposalId ) ;
2486
+ }
2487
+
2488
+ // TODO: we should be able to eliminate these fns, replacing with the call to `.pdas` directly
2489
+ auctionConfigAddress = ( id : number ) : PublicKey => this . pdas . auctionConfig ( id ) ;
2490
+ cctpMintRecipientAddress = ( ) : PublicKey =>
2491
+ this . pdas . cctpMintRecipient ( this . custodianAddress ( ) ) ;
2492
+ routerEndpointAddress = ( chain : ChainId ) : PublicKey => this . pdas . routerEndpoint ( chain ) ;
2493
+ eventAuthorityAddress = ( ) : PublicKey => this . pdas . eventAuthority ( ) ;
2494
+ auctionAddress = ( vaaHash : VaaHash ) : PublicKey => this . pdas . auction ( vaaHash ) ;
2495
+ custodianAddress = ( ) : PublicKey => this . pdas . custodian ( ) ;
2496
+ fastFillAddress = (
2497
+ sourceChain : ChainId ,
2498
+ orderSender : Array < number > ,
2499
+ sequence : Uint64 ,
2500
+ ) : PublicKey => this . pdas . fastFill ( sourceChain , orderSender , sequence ) ;
2501
+ coreMessageAddress = ( auction : PublicKey ) : PublicKey => this . pdas . coreMessage ( auction ) ;
2502
+ cctpMessageAddress = ( auction : PublicKey ) : PublicKey => this . pdas . cctpMessage ( auction ) ;
2503
+ preparedOrderResponseAddress = ( fastVaaHash : VaaHash ) : PublicKey =>
2504
+ this . pdas . preparedOrderResponse ( fastVaaHash ) ;
2505
+ preparedCustodyTokenAddress = ( preparedOrderResponse : PublicKey ) : PublicKey =>
2506
+ this . pdas . preparedCustodyToken ( preparedOrderResponse ) ;
2507
+ auctionCustodyTokenAddress = ( auction : PublicKey ) : PublicKey =>
2508
+ this . pdas . auctionCustodyToken ( auction ) ;
2509
+ localCustodyTokenAddress = ( sourceChain : ChainId ) : PublicKey =>
2510
+ this . pdas . localCustodyToken ( sourceChain ) ;
2511
+ fastFillSequencerAddress = ( sourceChain : ChainId , sender : Array < number > ) : PublicKey =>
2512
+ this . pdas . fastFillSequencer ( sourceChain , sender ) ;
2513
+ reservedFastFillSequenceAddress = ( fastVaaHash : VaaHash ) : PublicKey =>
2514
+ this . pdas . reservedFastFillSequenceAddress ( fastVaaHash ) ;
2515
+ transferAuthorityAddress = ( auction : PublicKey , offerPrice : Uint64 ) : PublicKey =>
2516
+ this . pdas . transferAuthority ( auction , offerPrice ) ;
2517
+ auctionHistoryAddress = ( id : Uint64 ) : PublicKey => this . pdas . auctionHistory ( id ) ;
2561
2518
}
2562
2519
2563
2520
export function testnet ( ) : ProgramId {
0 commit comments