Skip to content

Commit fbda72a

Browse files
committed
solana: Add token authority transfer test cases
1 parent ad25ae1 commit fbda72a

File tree

1 file changed

+327
-5
lines changed

1 file changed

+327
-5
lines changed

solana/tests/anchor.test.ts

+327-5
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ describe("example-native-token-transfers", () => {
130130
let sender: AccountAddress<"Solana">;
131131
let multisig: anchor.web3.PublicKey;
132132
let tokenAddress: string;
133+
let multisigTokenAuthority: anchor.web3.PublicKey;
133134

134135
beforeAll(async () => {
135136
try {
@@ -226,7 +227,7 @@ describe("example-native-token-transfers", () => {
226227
describe("Burning", () => {
227228
beforeAll(async () => {
228229
try {
229-
multisig = await spl.createMultisig(
230+
multisigTokenAuthority = await spl.createMultisig(
230231
connection,
231232
payer,
232233
[owner.publicKey, ntt.pdas.tokenAuthority()],
@@ -241,7 +242,7 @@ describe("example-native-token-transfers", () => {
241242
mint.publicKey,
242243
owner,
243244
spl.AuthorityType.MintTokens,
244-
multisig,
245+
multisigTokenAuthority,
245246
[],
246247
undefined,
247248
TOKEN_PROGRAM
@@ -252,7 +253,7 @@ describe("example-native-token-transfers", () => {
252253
mint: mint.publicKey,
253254
outboundLimit: 1000000n,
254255
mode: "burning",
255-
multisig,
256+
multisig: multisigTokenAuthority,
256257
});
257258
await signSendWait(ctx, initTxs, signer);
258259

@@ -357,6 +358,327 @@ describe("example-native-token-transfers", () => {
357358
expect(balance.value.amount).toBe("9900000");
358359
});
359360

361+
describe("Can transfer mint authority to-and-from NTT manager", () => {
362+
const newAuthority = anchor.web3.Keypair.generate();
363+
let newMultisigAuthority: anchor.web3.PublicKey;
364+
365+
beforeAll(async () => {
366+
newMultisigAuthority = await spl.createMultisig(
367+
connection,
368+
payer,
369+
[owner.publicKey, newAuthority.publicKey],
370+
2,
371+
anchor.web3.Keypair.generate(),
372+
undefined,
373+
TOKEN_PROGRAM
374+
);
375+
});
376+
377+
it("Fails when contract is not paused", async () => {
378+
try {
379+
const transaction = new anchor.web3.Transaction().add(
380+
await NTT.createSetTokenAuthorityOneStepUncheckedInstruction(
381+
ntt.program,
382+
await ntt.getConfig(),
383+
{
384+
owner: new SolanaAddress(await ntt.getOwner()).unwrap(),
385+
newAuthority: newAuthority.publicKey,
386+
multisigTokenAuthority,
387+
}
388+
)
389+
);
390+
transaction.feePayer = payer.publicKey;
391+
const { blockhash } = await connection.getLatestBlockhash();
392+
transaction.recentBlockhash = blockhash;
393+
await anchor.web3.sendAndConfirmTransaction(connection, transaction, [
394+
payer,
395+
]);
396+
// tx should fail so this expect should never be hit
397+
expect(false).toBeTruthy();
398+
} catch (e) {
399+
expect(e).toBeInstanceOf(anchor.web3.SendTransactionError);
400+
const parsedError = anchor.AnchorError.parse(
401+
(e as anchor.web3.SendTransactionError).logs ?? []
402+
);
403+
expect(parsedError?.error.errorCode).toEqual({
404+
code: "NotPaused",
405+
number: 6024,
406+
});
407+
} finally {
408+
const mintInfo = await spl.getMint(
409+
connection,
410+
mint.publicKey,
411+
undefined,
412+
TOKEN_PROGRAM
413+
);
414+
expect(mintInfo.mintAuthority).toEqual(multisigTokenAuthority);
415+
}
416+
});
417+
418+
test("Multisig(owner, TA) -> newAuthority", async () => {
419+
// retry after pausing contract
420+
const pauseTxs = await ntt.pause(new SolanaAddress(payer.publicKey));
421+
await signSendWait(ctx, pauseTxs, signer);
422+
423+
const transaction = new anchor.web3.Transaction().add(
424+
await NTT.createSetTokenAuthorityOneStepUncheckedInstruction(
425+
ntt.program,
426+
await ntt.getConfig(),
427+
{
428+
owner: new SolanaAddress(await ntt.getOwner()).unwrap(),
429+
newAuthority: newAuthority.publicKey,
430+
multisigTokenAuthority,
431+
}
432+
)
433+
);
434+
transaction.feePayer = payer.publicKey;
435+
const { blockhash } = await connection.getLatestBlockhash();
436+
transaction.recentBlockhash = blockhash;
437+
await anchor.web3.sendAndConfirmTransaction(connection, transaction, [
438+
payer,
439+
]);
440+
441+
const mintInfo = await spl.getMint(
442+
connection,
443+
mint.publicKey,
444+
undefined,
445+
TOKEN_PROGRAM
446+
);
447+
expect(mintInfo.mintAuthority).toEqual(newAuthority.publicKey);
448+
});
449+
450+
test("newAuthority -> TA", async () => {
451+
const transaction = new anchor.web3.Transaction().add(
452+
await NTT.createAcceptTokenAuthorityInstruction(
453+
ntt.program,
454+
await ntt.getConfig(),
455+
{
456+
currentAuthority: newAuthority.publicKey,
457+
}
458+
)
459+
);
460+
transaction.feePayer = payer.publicKey;
461+
const { blockhash } = await connection.getLatestBlockhash();
462+
transaction.recentBlockhash = blockhash;
463+
await anchor.web3.sendAndConfirmTransaction(connection, transaction, [
464+
payer,
465+
newAuthority,
466+
]);
467+
468+
const mintInfo = await spl.getMint(
469+
connection,
470+
mint.publicKey,
471+
undefined,
472+
TOKEN_PROGRAM
473+
);
474+
expect(mintInfo.mintAuthority).toEqual(ntt.pdas.tokenAuthority());
475+
});
476+
477+
test("TA -> Multisig(owner, newAuthority)", async () => {
478+
// set token authority: TA -> newMultisigAuthority
479+
const setTransaction = new anchor.web3.Transaction().add(
480+
await NTT.createSetTokenAuthorityInstruction(
481+
ntt.program,
482+
await ntt.getConfig(),
483+
{
484+
rentPayer: new SolanaAddress(await ntt.getOwner()).unwrap(),
485+
owner: new SolanaAddress(await ntt.getOwner()).unwrap(),
486+
newAuthority: newMultisigAuthority,
487+
}
488+
)
489+
);
490+
setTransaction.feePayer = payer.publicKey;
491+
const { blockhash } = await connection.getLatestBlockhash();
492+
setTransaction.recentBlockhash = blockhash;
493+
await anchor.web3.sendAndConfirmTransaction(
494+
connection,
495+
setTransaction,
496+
[payer]
497+
);
498+
499+
// claim token authority: newMultisigAuthority <- TA
500+
const claimTransaction = new anchor.web3.Transaction().add(
501+
await NTT.createClaimTokenAuthorityToMultisigInstruction(
502+
ntt.program,
503+
await ntt.getConfig(),
504+
{
505+
rentPayer: new SolanaAddress(await ntt.getOwner()).unwrap(),
506+
newMultisigAuthority,
507+
additionalSigners: [newAuthority.publicKey, owner.publicKey],
508+
}
509+
)
510+
);
511+
claimTransaction.feePayer = payer.publicKey;
512+
claimTransaction.recentBlockhash = blockhash;
513+
await anchor.web3.sendAndConfirmTransaction(
514+
connection,
515+
claimTransaction,
516+
[payer, newAuthority, owner]
517+
);
518+
519+
const mintInfo = await spl.getMint(
520+
connection,
521+
mint.publicKey,
522+
undefined,
523+
TOKEN_PROGRAM
524+
);
525+
expect(mintInfo.mintAuthority).toEqual(newMultisigAuthority);
526+
});
527+
528+
test("Multisig(owner, newAuthority) -> Multisig(owner, TA)", async () => {
529+
const transaction = new anchor.web3.Transaction().add(
530+
await NTT.createAcceptTokenAuthorityFromMultisigInstruction(
531+
ntt.program,
532+
await ntt.getConfig(),
533+
{
534+
currentMultisigAuthority: newMultisigAuthority,
535+
additionalSigners: [newAuthority.publicKey, owner.publicKey],
536+
multisigTokenAuthority,
537+
}
538+
)
539+
);
540+
transaction.feePayer = payer.publicKey;
541+
const { blockhash } = await connection.getLatestBlockhash();
542+
transaction.recentBlockhash = blockhash;
543+
await anchor.web3.sendAndConfirmTransaction(connection, transaction, [
544+
payer,
545+
newAuthority,
546+
owner,
547+
]);
548+
549+
const mintInfo = await spl.getMint(
550+
connection,
551+
mint.publicKey,
552+
undefined,
553+
TOKEN_PROGRAM
554+
);
555+
expect(mintInfo.mintAuthority).toEqual(multisigTokenAuthority);
556+
});
557+
558+
it("Fails on claim after revert", async () => {
559+
try {
560+
// fund newAuthority for it to be rent payer
561+
const signature = await connection.requestAirdrop(
562+
newAuthority.publicKey,
563+
anchor.web3.LAMPORTS_PER_SOL
564+
);
565+
const { blockhash, lastValidBlockHeight } =
566+
await connection.getLatestBlockhash();
567+
await connection.confirmTransaction({
568+
blockhash,
569+
lastValidBlockHeight,
570+
signature,
571+
});
572+
let newAuthorityBalance = (
573+
await connection.getAccountInfo(newAuthority.publicKey)
574+
)?.lamports;
575+
expect(newAuthorityBalance).toBe(anchor.web3.LAMPORTS_PER_SOL);
576+
577+
// set token authority: multisigTokenAuthority -> newAuthority
578+
const setTransaction = new anchor.web3.Transaction().add(
579+
await NTT.createSetTokenAuthorityInstruction(
580+
ntt.program,
581+
await ntt.getConfig(),
582+
{
583+
rentPayer: newAuthority.publicKey,
584+
owner: new SolanaAddress(await ntt.getOwner()).unwrap(),
585+
newAuthority: newAuthority.publicKey,
586+
multisigTokenAuthority,
587+
}
588+
)
589+
);
590+
setTransaction.feePayer = payer.publicKey;
591+
setTransaction.recentBlockhash = blockhash;
592+
await anchor.web3.sendAndConfirmTransaction(
593+
connection,
594+
setTransaction,
595+
[payer, newAuthority]
596+
);
597+
newAuthorityBalance = (
598+
await connection.getAccountInfo(newAuthority.publicKey)
599+
)?.lamports;
600+
const pendingTokenAuthorityRentExemptAmount =
601+
await connection.getMinimumBalanceForRentExemption(
602+
ntt.program.account.pendingTokenAuthority.size
603+
);
604+
expect(newAuthorityBalance).toBe(
605+
anchor.web3.LAMPORTS_PER_SOL - pendingTokenAuthorityRentExemptAmount
606+
);
607+
608+
// revert token authority: multisigTokenAuthority
609+
const revertTransaction = new anchor.web3.Transaction().add(
610+
await NTT.createRevertTokenAuthorityInstruction(
611+
ntt.program,
612+
await ntt.getConfig(),
613+
{
614+
rentPayer: newAuthority.publicKey,
615+
owner: new SolanaAddress(await ntt.getOwner()).unwrap(),
616+
multisigTokenAuthority,
617+
}
618+
)
619+
);
620+
revertTransaction.feePayer = payer.publicKey;
621+
revertTransaction.recentBlockhash = blockhash;
622+
await anchor.web3.sendAndConfirmTransaction(
623+
connection,
624+
revertTransaction,
625+
[payer]
626+
);
627+
newAuthorityBalance = (
628+
await connection.getAccountInfo(newAuthority.publicKey)
629+
)?.lamports;
630+
expect(newAuthorityBalance).toBe(anchor.web3.LAMPORTS_PER_SOL);
631+
632+
// claim token authority: newAuthority <- multisigTokenAuthority
633+
const claimTransaction = new anchor.web3.Transaction().add(
634+
await NTT.createClaimTokenAuthorityInstruction(
635+
ntt.program,
636+
await ntt.getConfig(),
637+
{
638+
rentPayer: newAuthority.publicKey,
639+
newAuthority: newAuthority.publicKey,
640+
multisigTokenAuthority,
641+
}
642+
)
643+
);
644+
claimTransaction.feePayer = payer.publicKey;
645+
claimTransaction.recentBlockhash = blockhash;
646+
await anchor.web3.sendAndConfirmTransaction(
647+
connection,
648+
claimTransaction,
649+
[payer, newAuthority]
650+
);
651+
// tx should fail so this expect should never be hit
652+
expect(false).toBeTruthy();
653+
} catch (e) {
654+
expect(e).toBeInstanceOf(anchor.web3.SendTransactionError);
655+
const parsedError = anchor.AnchorError.parse(
656+
(e as anchor.web3.SendTransactionError).logs ?? []
657+
);
658+
expect(parsedError?.error.errorCode).toEqual({
659+
code: "AccountNotInitialized",
660+
number: 3012,
661+
});
662+
} finally {
663+
const mintInfo = await spl.getMint(
664+
connection,
665+
mint.publicKey,
666+
undefined,
667+
TOKEN_PROGRAM
668+
);
669+
expect(mintInfo.mintAuthority).toEqual(multisigTokenAuthority);
670+
}
671+
});
672+
673+
afterAll(async () => {
674+
// unpause
675+
const unpauseTxs = await ntt.unpause(
676+
new SolanaAddress(payer.publicKey)
677+
);
678+
await signSendWait(ctx, unpauseTxs, signer);
679+
});
680+
});
681+
360682
it("Can receive tokens", async () => {
361683
const emitter = new testing.mocks.MockEmitter(
362684
remoteXcvr.address as UniversalAddress,
@@ -396,7 +718,7 @@ describe("example-native-token-transfers", () => {
396718
const published = emitter.publishMessage(0, serialized, 200);
397719
const rawVaa = guardians.addSignatures(published, [0]);
398720
const vaa = deserialize("Ntt:WormholeTransfer", serialize(rawVaa));
399-
const redeemTxs = ntt.redeem([vaa], sender, multisig);
721+
const redeemTxs = ntt.redeem([vaa], sender, multisigTokenAuthority);
400722
try {
401723
await signSendWait(ctx, redeemTxs, signer);
402724
} catch (e) {
@@ -423,7 +745,7 @@ describe("example-native-token-transfers", () => {
423745
payer,
424746
mint.publicKey,
425747
dest.address,
426-
multisig,
748+
multisigTokenAuthority,
427749
1,
428750
[owner],
429751
undefined,

0 commit comments

Comments
 (0)