From f733892d78c7e35e16c522e463d2c1ba4f73cc7e Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Tue, 8 Oct 2024 10:01:30 +0100 Subject: [PATCH] Add `getInitializeInstructionsForMintExtensions` helper (#10) --- ...InitializeInstructionsForMintExtensions.ts | 44 +++++++++++++++++ clients/js/src/index.ts | 1 + clients/js/test/_setup.ts | 15 +++++- .../updateConfidentialTransferMint.test.ts | 47 +++++++------------ .../initializeDefaultAccountState.test.ts | 33 +++++-------- .../updateDefaultAccountState.test.ts | 39 +++++---------- .../transferCheckedWithFee.test.ts | 47 ++++++------------- 7 files changed, 115 insertions(+), 111 deletions(-) create mode 100644 clients/js/src/getInitializeInstructionsForMintExtensions.ts diff --git a/clients/js/src/getInitializeInstructionsForMintExtensions.ts b/clients/js/src/getInitializeInstructionsForMintExtensions.ts new file mode 100644 index 0000000..a85c9ef --- /dev/null +++ b/clients/js/src/getInitializeInstructionsForMintExtensions.ts @@ -0,0 +1,44 @@ +import { Address, IInstruction } from '@solana/web3.js'; +import { + ExtensionArgs, + getInitializeConfidentialTransferMintInstruction, + getInitializeDefaultAccountStateInstruction, + getInitializeTransferFeeConfigInstruction, +} from './generated'; + +export function getInitializeInstructionsForMintExtensions( + mint: Address, + extensions: ExtensionArgs[] +): IInstruction[] { + return extensions.flatMap((extension) => { + switch (extension.__kind) { + case 'ConfidentialTransferMint': + return [ + getInitializeConfidentialTransferMintInstruction({ + mint, + ...extension, + }), + ]; + case 'DefaultAccountState': + return [ + getInitializeDefaultAccountStateInstruction({ + mint, + state: extension.state, + }), + ]; + case 'TransferFeeConfig': + return [ + getInitializeTransferFeeConfigInstruction({ + mint, + transferFeeConfigAuthority: extension.transferFeeConfigAuthority, + withdrawWithheldAuthority: extension.withdrawWithheldAuthority, + transferFeeBasisPoints: + extension.newerTransferFee.transferFeeBasisPoints, + maximumFee: extension.newerTransferFee.maximumFee, + }), + ]; + default: + return []; + } + }); +} diff --git a/clients/js/src/index.ts b/clients/js/src/index.ts index d14487d..50c28b6 100644 --- a/clients/js/src/index.ts +++ b/clients/js/src/index.ts @@ -1,4 +1,5 @@ export * from './generated'; +export * from './getInitializeInstructionsForMintExtensions'; export * from './getTokenSize'; export * from './getMintSize'; diff --git a/clients/js/test/_setup.ts b/clients/js/test/_setup.ts index 809ee6c..b97189f 100644 --- a/clients/js/test/_setup.ts +++ b/clients/js/test/_setup.ts @@ -28,6 +28,7 @@ import { ExtensionArgs, TOKEN_2022_PROGRAM_ADDRESS, getInitializeAccountInstruction, + getInitializeInstructionsForMintExtensions, getInitializeMintInstruction, getMintSize, getMintToInstruction, @@ -163,8 +164,18 @@ export const createMint = async ( input: Omit[0], 'mint'> ): Promise
=> { const mint = await generateKeyPairSigner(); - const instructions = await getCreateMintInstructions({ ...input, mint }); - await sendAndConfirmInstructions(input.client, input.payer, instructions); + const [createAccount, initMint] = await getCreateMintInstructions({ + ...input, + mint, + }); + await sendAndConfirmInstructions(input.client, input.payer, [ + createAccount, + ...getInitializeInstructionsForMintExtensions( + mint.address, + input.extensions ?? [] + ), + initMint, + ]); return mint.address; }; diff --git a/clients/js/test/extensions/confidentialTransfer/updateConfidentialTransferMint.test.ts b/clients/js/test/extensions/confidentialTransfer/updateConfidentialTransferMint.test.ts index 36ce8f1..84f500a 100644 --- a/clients/js/test/extensions/confidentialTransfer/updateConfidentialTransferMint.test.ts +++ b/clients/js/test/extensions/confidentialTransfer/updateConfidentialTransferMint.test.ts @@ -10,54 +10,43 @@ import { Mint, extension, fetchMint, - getInitializeConfidentialTransferMintInstruction, getUpdateConfidentialTransferMintInstruction, } from '../../../src'; import { createDefaultSolanaClient, + createMint, generateKeyPairSignerWithSol, - getCreateMintInstructions, sendAndConfirmInstructions, } from '../../_setup'; test('it updates a mint account with confidential transfer', async (t) => { // Given some signer accounts. const client = createDefaultSolanaClient(); - const [authority, confidentialTransferAuthority, mint] = await Promise.all([ + const [authority, confidentialTransferAuthority] = await Promise.all([ generateKeyPairSignerWithSol(client), generateKeyPairSigner(), - generateKeyPairSigner(), ]); // And a mint account initialized with a confidential transfer extension. - const confidentialTransferExtension = extension('ConfidentialTransferMint', { - authority: some(confidentialTransferAuthority.address), - autoApproveNewAccounts: true, - auditorElgamalPubkey: some( - address('BTNEPmmWuj7Sg4Fo5i1FC5eiV2Aj4jiv9boarvE5XeaX') - ), + const mint = await createMint({ + authority: authority.address, + client, + extensions: [ + extension('ConfidentialTransferMint', { + authority: some(confidentialTransferAuthority.address), + autoApproveNewAccounts: true, + auditorElgamalPubkey: some( + address('BTNEPmmWuj7Sg4Fo5i1FC5eiV2Aj4jiv9boarvE5XeaX') + ), + }), + ], + payer: authority, }); - const [createMintInstruction, initMintInstruction] = - await getCreateMintInstructions({ - authority: authority.address, - client, - extensions: [confidentialTransferExtension], - mint, - payer: authority, - }); - await sendAndConfirmInstructions(client, authority, [ - createMintInstruction, - getInitializeConfidentialTransferMintInstruction({ - mint: mint.address, - ...confidentialTransferExtension, - }), - initMintInstruction, - ]); // When we update the mint account with new confidential transfer configs. await sendAndConfirmInstructions(client, authority, [ getUpdateConfidentialTransferMintInstruction({ - mint: mint.address, + mint, authority: confidentialTransferAuthority, autoApproveNewAccounts: false, auditorElgamalPubkey: none(), @@ -65,9 +54,9 @@ test('it updates a mint account with confidential transfer', async (t) => { ]); // Then we expect the mint account to have the following updated data. - const mintAccount = await fetchMint(client.rpc, mint.address); + const mintAccount = await fetchMint(client.rpc, mint); t.like(mintAccount, >{ - address: mint.address, + address: mint, data: { mintAuthority: some(authority.address), extensions: some([ diff --git a/clients/js/test/extensions/defaultAccountState/initializeDefaultAccountState.test.ts b/clients/js/test/extensions/defaultAccountState/initializeDefaultAccountState.test.ts index 829b3dd..a79d3bd 100644 --- a/clients/js/test/extensions/defaultAccountState/initializeDefaultAccountState.test.ts +++ b/clients/js/test/extensions/defaultAccountState/initializeDefaultAccountState.test.ts @@ -10,6 +10,7 @@ import { } from '../../../src'; import { createDefaultSolanaClient, + createMint, createToken, generateKeyPairSignerWithSol, getCreateMintInstructions, @@ -64,38 +65,26 @@ test('it initializes a mint account with a default account state extension', asy test('it initializes a token account with the default state defined on the mint account', async (t) => { // Given some signer accounts. const client = createDefaultSolanaClient(); - const [authority, freezeAuthority, mint] = await Promise.all([ + const [authority, freezeAuthority] = await Promise.all([ generateKeyPairSignerWithSol(client), generateKeyPairSigner(), - generateKeyPairSigner(), ]); // And a mint account initialized with a default account state extension. - const defaultAccountStateExtension = extension('DefaultAccountState', { - state: AccountState.Frozen, + const mint = await createMint({ + authority: authority.address, + client, + extensions: [ + extension('DefaultAccountState', { state: AccountState.Frozen }), + ], + freezeAuthority: freezeAuthority.address, + payer: authority, }); - const [createMintInstruction, initMintInstruction] = - await getCreateMintInstructions({ - authority: authority.address, - client, - extensions: [defaultAccountStateExtension], - freezeAuthority: freezeAuthority.address, - mint, - payer: authority, - }); - await sendAndConfirmInstructions(client, authority, [ - createMintInstruction, - getInitializeDefaultAccountStateInstruction({ - mint: mint.address, - state: defaultAccountStateExtension.state, - }), - initMintInstruction, - ]); // When we create a new token account for the mint. const token = await createToken({ client, - mint: mint.address, + mint, owner: address('HHS1XymmkBpYAkg3XTbZLxgHa5n11PAWUCWdiVtRmzzS'), payer: authority, }); diff --git a/clients/js/test/extensions/defaultAccountState/updateDefaultAccountState.test.ts b/clients/js/test/extensions/defaultAccountState/updateDefaultAccountState.test.ts index 9ebd835..1190d5d 100644 --- a/clients/js/test/extensions/defaultAccountState/updateDefaultAccountState.test.ts +++ b/clients/js/test/extensions/defaultAccountState/updateDefaultAccountState.test.ts @@ -5,60 +5,47 @@ import { Mint, extension, fetchMint, - getInitializeDefaultAccountStateInstruction, getUpdateDefaultAccountStateInstruction, } from '../../../src'; import { createDefaultSolanaClient, + createMint, generateKeyPairSignerWithSol, - getCreateMintInstructions, sendAndConfirmInstructions, } from '../../_setup'; test('it updates the default state account on a mint account', async (t) => { // Given some signer accounts. const client = createDefaultSolanaClient(); - const [authority, freezeAuthority, mint] = await Promise.all([ + const [authority, freezeAuthority] = await Promise.all([ generateKeyPairSignerWithSol(client), generateKeyPairSigner(), - generateKeyPairSigner(), ]); // And a mint account initialized with a default account state extension. - const defaultAccountStateExtension = extension('DefaultAccountState', { - state: AccountState.Frozen, + const mint = await createMint({ + authority: authority.address, + client, + extensions: [ + extension('DefaultAccountState', { state: AccountState.Frozen }), + ], + freezeAuthority: freezeAuthority.address, + payer: authority, }); - const [createMintInstruction, initMintInstruction] = - await getCreateMintInstructions({ - authority: authority.address, - client, - extensions: [defaultAccountStateExtension], - freezeAuthority: freezeAuthority.address, - mint, - payer: authority, - }); - await sendAndConfirmInstructions(client, authority, [ - createMintInstruction, - getInitializeDefaultAccountStateInstruction({ - mint: mint.address, - state: defaultAccountStateExtension.state, - }), - initMintInstruction, - ]); // When we update the default account state on the mint account. await sendAndConfirmInstructions(client, authority, [ getUpdateDefaultAccountStateInstruction({ - mint: mint.address, + mint, freezeAuthority, state: AccountState.Initialized, }), ]); // Then we expect the mint account to have the following updated data. - const mintAccount = await fetchMint(client.rpc, mint.address); + const mintAccount = await fetchMint(client.rpc, mint); t.like(mintAccount, >{ - address: mint.address, + address: mint, data: { extensions: some([ extension('DefaultAccountState', { state: AccountState.Initialized }), diff --git a/clients/js/test/extensions/transferFree/transferCheckedWithFee.test.ts b/clients/js/test/extensions/transferFree/transferCheckedWithFee.test.ts index 58ce2a5..9bd19cf 100644 --- a/clients/js/test/extensions/transferFree/transferCheckedWithFee.test.ts +++ b/clients/js/test/extensions/transferFree/transferCheckedWithFee.test.ts @@ -4,14 +4,13 @@ import { Token, extension, fetchToken, - getInitializeTransferFeeConfigInstruction, getMintToInstruction, getTransferCheckedWithFeeInstruction, } from '../../../src'; import { createDefaultSolanaClient, + createMint, generateKeyPairSignerWithSol, - getCreateMintInstructions, getCreateTokenInstructions, sendAndConfirmInstructions, } from '../../_setup'; @@ -19,13 +18,12 @@ import { test('it transfers tokens with pre-configured fees', async (t) => { // Given some signer accounts. const client = createDefaultSolanaClient(); - const [authority, mint, ownerA, tokenA, ownerB, tokenB] = await Promise.all([ + const [authority, ownerA, tokenA, ownerB, tokenB] = await Promise.all([ generateKeyPairSignerWithSol(client), generateKeyPairSigner(), generateKeyPairSigner(), generateKeyPairSigner(), generateKeyPairSigner(), - generateKeyPairSigner(), ]); // And a mint account initialized with transfer fee configurations. @@ -46,28 +44,13 @@ test('it transfers tokens with pre-configured fees', async (t) => { // Used for transitioning configs. Starts by being the same as newerTransferFee. olderTransferFee: transferFees, }); - const [createMintInstruction, initMintInstruction] = - await getCreateMintInstructions({ - authority: authority.address, - client, - decimals: 2, - extensions: [transferFeeConfigExtension], - mint, - payer: authority, - }); - await sendAndConfirmInstructions(client, authority, [ - createMintInstruction, - getInitializeTransferFeeConfigInstruction({ - mint: mint.address, - transferFeeConfigAuthority: - transferFeeConfigExtension.transferFeeConfigAuthority, - withdrawWithheldAuthority: - transferFeeConfigExtension.withdrawWithheldAuthority, - transferFeeBasisPoints: transferFees.transferFeeBasisPoints, - maximumFee: transferFees.maximumFee, - }), - initMintInstruction, - ]); + const mint = await createMint({ + authority: authority.address, + client, + decimals: 2, + extensions: [transferFeeConfigExtension], + payer: authority, + }); // And two token accounts with 10.00 and 0.00 tokens respectively. const transferFeeAmount = extension('TransferFeeAmount', { @@ -77,7 +60,7 @@ test('it transfers tokens with pre-configured fees', async (t) => { getCreateTokenInstructions({ client, extensions: [transferFeeAmount], - mint: mint.address, + mint, owner: ownerA.address, payer: authority, token: tokenA, @@ -85,7 +68,7 @@ test('it transfers tokens with pre-configured fees', async (t) => { getCreateTokenInstructions({ client, extensions: [transferFeeAmount], - mint: mint.address, + mint, owner: ownerB.address, payer: authority, token: tokenB, @@ -94,7 +77,7 @@ test('it transfers tokens with pre-configured fees', async (t) => { await sendAndConfirmInstructions(client, authority, [ ...createTokensInstructions.flat(), getMintToInstruction({ - mint: mint.address, + mint, token: tokenA.address, mintAuthority: authority, amount: 1000n, @@ -105,7 +88,7 @@ test('it transfers tokens with pre-configured fees', async (t) => { await sendAndConfirmInstructions(client, authority, [ getTransferCheckedWithFeeInstruction({ source: tokenA.address, - mint: mint.address, + mint, destination: tokenB.address, authority: ownerA, amount: 200n, @@ -119,7 +102,7 @@ test('it transfers tokens with pre-configured fees', async (t) => { t.like(tokenAccountA, >{ address: tokenA.address, data: { - mint: mint.address, + mint, owner: ownerA.address, amount: 800n, extensions: some([ @@ -133,7 +116,7 @@ test('it transfers tokens with pre-configured fees', async (t) => { t.like(tokenAccountB, >{ address: tokenB.address, data: { - mint: mint.address, + mint, owner: ownerB.address, amount: 197n, extensions: some([