Skip to content

Commit fa4d19f

Browse files
committed
wip: transfer before burn/mint to trigger hooks
wip because with this the test tx size is 5 bytes larger (for transfer) than the limit. The way to mitigate is to introduce lookup tables. That mitigation will exist in the tests, but will also have to be done on real deployments (since the transfer hooks might add an arbitrary number of extra acconuts, so we should leave as much headroom as possible)
1 parent 52c5809 commit fa4d19f

File tree

9 files changed

+338
-181
lines changed

9 files changed

+338
-181
lines changed

sdk/solana/src/ntt.ts

+55-24
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Program } from "@coral-xyz/anchor";
2-
import { associatedAddress } from "@coral-xyz/anchor/dist/cjs/utils/token.js";
32
import * as splToken from "@solana/spl-token";
43
import {
54
createAssociatedTokenAccountInstruction,
@@ -9,6 +8,7 @@ import {
98
Connection,
109
Keypair,
1110
PublicKey,
11+
SystemProgram,
1212
Transaction,
1313
TransactionInstruction,
1414
TransactionMessage,
@@ -236,16 +236,11 @@ export class SolanaNtt<N extends Network, C extends SolanaChains>
236236
);
237237
}
238238

239-
const custodyAddress = associatedAddress({
240-
mint: args.mint,
241-
owner: this.pdas.tokenAuthority(),
242-
});
243-
244239
const tokenProgram = mintInfo.owner;
245240
const limit = new BN(args.outboundLimit.toString());
246241
const ix = await this.program.methods
247242
.initialize({ chainId, limit: limit, mode })
248-
.accounts({
243+
.accountsStrict({
249244
payer: args.payer.publicKey,
250245
deployer: args.owner.publicKey,
251246
programData: programDataAddress(this.program.programId),
@@ -254,8 +249,10 @@ export class SolanaNtt<N extends Network, C extends SolanaChains>
254249
rateLimit: this.pdas.outboxRateLimitAccount(),
255250
tokenProgram,
256251
tokenAuthority: this.pdas.tokenAuthority(),
257-
custody: custodyAddress,
252+
custody: await this.custodyAccountAddress(args.mint, tokenProgram),
258253
bpfLoaderUpgradeableProgram: BPF_LOADER_UPGRADEABLE_PROGRAM_ID,
254+
associatedTokenProgram: splToken.ASSOCIATED_TOKEN_PROGRAM_ID,
255+
systemProgram: SystemProgram.programId,
259256
})
260257
.instruction();
261258

@@ -278,14 +275,15 @@ export class SolanaNtt<N extends Network, C extends SolanaChains>
278275

279276
const ix = await this.program.methods
280277
.registerTransceiver()
281-
.accounts({
278+
.accountsStrict({
282279
payer: args.payer.publicKey,
283280
owner: args.owner.publicKey,
284281
config: this.pdas.configAccount(),
285282
transceiver: args.transceiver,
286283
registeredTransceiver: this.pdas.registeredTransceiver(
287284
args.transceiver
288285
),
286+
systemProgram: SystemProgram.programId,
289287
})
290288
.instruction();
291289

@@ -307,6 +305,7 @@ export class SolanaNtt<N extends Network, C extends SolanaChains>
307305
feeCollector: whAccs.wormholeFeeCollector,
308306
sequence: whAccs.wormholeSequence,
309307
program: this.core.address,
308+
systemProgram: SystemProgram.programId,
310309
},
311310
})
312311
.instruction();
@@ -337,11 +336,12 @@ export class SolanaNtt<N extends Network, C extends SolanaChains>
337336
chainId: { id: toChainId(peer.chain) },
338337
address: Array.from(peer.address.toUniversalAddress().toUint8Array()),
339338
})
340-
.accounts({
339+
.accountsStrict({
341340
payer: sender,
342341
owner: sender,
343342
config: this.pdas.configAccount(),
344343
peer: this.pdas.transceiverPeerAccount(peer.chain),
344+
systemProgram: SystemProgram.programId,
345345
})
346346
.instruction(),
347347
this.program.methods
@@ -390,12 +390,13 @@ export class SolanaNtt<N extends Network, C extends SolanaChains>
390390
limit: new BN(inboundLimit.toString()),
391391
tokenDecimals: tokenDecimals,
392392
})
393-
.accounts({
393+
.accountsStrict({
394394
payer: sender,
395395
owner: sender,
396396
config: this.pdas.configAccount(),
397397
peer: this.pdas.peerAccount(peer.chain),
398398
inboxRateLimit: this.pdas.inboxRateLimitAccount(peer.chain),
399+
systemProgram: SystemProgram.programId,
399400
})
400401
.instruction();
401402

@@ -671,7 +672,7 @@ export class SolanaNtt<N extends Network, C extends SolanaChains>
671672
),
672673
shouldQueue: args.transferArgs.shouldQueue,
673674
})
674-
.accounts({
675+
.accountsStrict({
675676
common: {
676677
payer: args.payer,
677678
config: { config: this.pdas.configAccount() },
@@ -680,10 +681,11 @@ export class SolanaNtt<N extends Network, C extends SolanaChains>
680681
tokenProgram: config.tokenProgram,
681682
outboxItem: args.outboxItem,
682683
outboxRateLimit: this.pdas.outboxRateLimitAccount(),
684+
systemProgram: SystemProgram.programId,
685+
custody: config.custody,
683686
},
684687
peer: this.pdas.peerAccount(recipientChain),
685688
inboxRateLimit: this.pdas.inboxRateLimitAccount(recipientChain),
686-
custody: config.custody,
687689
sessionAuthority: sessionAuthority,
688690
})
689691
.instruction();
@@ -712,21 +714,25 @@ export class SolanaNtt<N extends Network, C extends SolanaChains>
712714
),
713715
shouldQueue: args.transferArgs.shouldQueue,
714716
})
715-
.accounts({
717+
.accountsStrict({
716718
common: {
717719
payer: args.payer,
718720
config: { config: this.pdas.configAccount() },
719721
mint: config.mint,
720722
from: args.from,
721723
outboxItem: args.outboxItem,
722724
outboxRateLimit: this.pdas.outboxRateLimitAccount(),
725+
custody: config.custody,
726+
tokenProgram: config.tokenProgram,
727+
systemProgram: SystemProgram.programId,
723728
},
724729
peer: this.pdas.peerAccount(recipientChain),
725730
inboxRateLimit: this.pdas.inboxRateLimitAccount(recipientChain),
726731
sessionAuthority: this.pdas.sessionAuthority(
727732
args.fromAuthority,
728733
args.transferArgs
729734
),
735+
tokenAuthority: this.pdas.tokenAuthority(),
730736
})
731737
.instruction();
732738
}
@@ -757,6 +763,7 @@ export class SolanaNtt<N extends Network, C extends SolanaChains>
757763
feeCollector: whAccs.wormholeFeeCollector,
758764
sequence: whAccs.wormholeSequence,
759765
program: this.core.address,
766+
systemProgram: SystemProgram.programId,
760767
},
761768
})
762769
.instruction();
@@ -773,7 +780,7 @@ export class SolanaNtt<N extends Network, C extends SolanaChains>
773780
const emitterChain = wormholeNTT.emitterChain;
774781
return await this.program.methods
775782
.receiveWormholeMessage()
776-
.accounts({
783+
.accountsStrict({
777784
payer: payer,
778785
config: { config: this.pdas.configAccount() },
779786
peer: this.pdas.transceiverPeerAccount(emitterChain),
@@ -785,6 +792,7 @@ export class SolanaNtt<N extends Network, C extends SolanaChains>
785792
emitterChain,
786793
nttMessage.id
787794
),
795+
systemProgram: SystemProgram.programId,
788796
})
789797
.instruction();
790798
}
@@ -805,7 +813,7 @@ export class SolanaNtt<N extends Network, C extends SolanaChains>
805813

806814
return await this.program.methods
807815
.redeem({})
808-
.accounts({
816+
.accountsStrict({
809817
payer: payer,
810818
config: this.pdas.configAccount(),
811819
peer: nttManagerPeer,
@@ -818,6 +826,7 @@ export class SolanaNtt<N extends Network, C extends SolanaChains>
818826
inboxItem,
819827
inboxRateLimit,
820828
outboxRateLimit: this.pdas.outboxRateLimitAccount(),
829+
systemProgram: SystemProgram.programId,
821830
})
822831
.instruction();
823832
}
@@ -847,7 +856,7 @@ export class SolanaNtt<N extends Network, C extends SolanaChains>
847856
.releaseInboundMint({
848857
revertOnDelay: args.revertOnDelay,
849858
})
850-
.accounts({
859+
.accountsStrict({
851860
common: {
852861
payer: args.payer,
853862
config: { config: this.pdas.configAccount() },
@@ -858,6 +867,8 @@ export class SolanaNtt<N extends Network, C extends SolanaChains>
858867
),
859868
mint: config.mint,
860869
tokenAuthority: this.pdas.tokenAuthority(),
870+
custody: config.custody,
871+
tokenProgram: config.tokenProgram,
861872
},
862873
})
863874
.instruction();
@@ -888,7 +899,7 @@ export class SolanaNtt<N extends Network, C extends SolanaChains>
888899
.releaseInboundUnlock({
889900
revertOnDelay: args.revertOnDelay,
890901
})
891-
.accounts({
902+
.accountsStrict({
892903
common: {
893904
payer: args.payer,
894905
config: { config: this.pdas.configAccount() },
@@ -899,17 +910,37 @@ export class SolanaNtt<N extends Network, C extends SolanaChains>
899910
),
900911
mint: config.mint,
901912
tokenAuthority: this.pdas.tokenAuthority(),
913+
custody: config.custody,
914+
tokenProgram: config.tokenProgram,
902915
},
903-
custody: config.custody,
904916
})
905917
.instruction();
906918
}
907919

908-
async custodyAccountAddress(mint: PublicKey): Promise<PublicKey> {
909-
return associatedAddress({
910-
mint: mint,
911-
owner: this.pdas.tokenAuthority(),
912-
});
920+
/**
921+
* Returns the address of the custody account. If the config is available
922+
* (i.e. the program is initialised), the mint is derived from the config.
923+
* Otherwise, the mint must be provided.
924+
*/
925+
async custodyAccountAddress(
926+
configOrMint: NttBindings.Config | PublicKey,
927+
tokenProgram = splToken.TOKEN_PROGRAM_ID
928+
): Promise<PublicKey> {
929+
if (configOrMint instanceof PublicKey) {
930+
return splToken.getAssociatedTokenAddress(
931+
configOrMint,
932+
this.pdas.tokenAuthority(),
933+
true,
934+
tokenProgram
935+
);
936+
} else {
937+
return splToken.getAssociatedTokenAddress(
938+
configOrMint.mint,
939+
this.pdas.tokenAuthority(),
940+
true,
941+
configOrMint.tokenProgram
942+
);
943+
}
913944
}
914945

915946
createUnsignedTx(

solana/idl/json/example_native_token_transfers.json

+25-10
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@
139139
"isMut": true,
140140
"isSigner": false
141141
},
142+
{
143+
"name": "custody",
144+
"isMut": true,
145+
"isSigner": false
146+
},
142147
{
143148
"name": "systemProgram",
144149
"isMut": false,
@@ -160,6 +165,11 @@
160165
"name": "sessionAuthority",
161166
"isMut": false,
162167
"isSigner": false
168+
},
169+
{
170+
"name": "tokenAuthority",
171+
"isMut": false,
172+
"isSigner": false
163173
}
164174
],
165175
"args": [
@@ -220,6 +230,11 @@
220230
"isMut": true,
221231
"isSigner": false
222232
},
233+
{
234+
"name": "custody",
235+
"isMut": true,
236+
"isSigner": false
237+
},
223238
{
224239
"name": "systemProgram",
225240
"isMut": false,
@@ -241,11 +256,6 @@
241256
"name": "sessionAuthority",
242257
"isMut": false,
243258
"isSigner": false
244-
},
245-
{
246-
"name": "custody",
247-
"isMut": true,
248-
"isSigner": false
249259
}
250260
],
251261
"args": [
@@ -378,6 +388,11 @@
378388
"name": "tokenProgram",
379389
"isMut": false,
380390
"isSigner": false
391+
},
392+
{
393+
"name": "custody",
394+
"isMut": true,
395+
"isSigner": false
381396
}
382397
]
383398
}
@@ -436,13 +451,13 @@
436451
"name": "tokenProgram",
437452
"isMut": false,
438453
"isSigner": false
454+
},
455+
{
456+
"name": "custody",
457+
"isMut": true,
458+
"isSigner": false
439459
}
440460
]
441-
},
442-
{
443-
"name": "custody",
444-
"isMut": true,
445-
"isSigner": false
446461
}
447462
],
448463
"args": [

0 commit comments

Comments
 (0)