[token-js] : JS binding for CreateIdempotent instruction (#3558)

* JS binding for CreateIdempotent instruction

* revert

* newline

* Removed Idempotent flag and extracted Idempotent logic to its own set of functions

* Conventions
This commit is contained in:
mwrites 2022-10-06 22:56:32 +08:00 committed by GitHub
parent c84f65c5ff
commit f61af23932
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 113 additions and 2 deletions

View File

@ -0,0 +1,46 @@
import type { ConfirmOptions, Connection, PublicKey, Signer } from '@solana/web3.js';
import { sendAndConfirmTransaction, Transaction } from '@solana/web3.js';
import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID } from '../constants.js';
import { createAssociatedTokenAccountIdempotentInstruction } from '../instructions/associatedTokenAccount.js';
import { getAssociatedTokenAddress } from '../state/mint.js';
/**
* Create and initialize a new associated token account
* The instruction will succeed even if the associated token account already exists
*
* @param connection Connection to use
* @param payer Payer of the transaction and initialization fees
* @param mint Mint for the account
* @param owner Owner of the new account
* @param confirmOptions Options for confirming the transaction
* @param programId SPL Token program account
* @param associatedTokenProgramId SPL Associated Token program account
*
* @return Address of the new or existing associated token account
*/
export async function createAssociatedTokenAccountIdempotent(
connection: Connection,
payer: Signer,
mint: PublicKey,
owner: PublicKey,
confirmOptions?: ConfirmOptions,
programId = TOKEN_PROGRAM_ID,
associatedTokenProgramId = ASSOCIATED_TOKEN_PROGRAM_ID
): Promise<PublicKey> {
const associatedToken = await getAssociatedTokenAddress(mint, owner, false, programId, associatedTokenProgramId);
const transaction = new Transaction().add(
createAssociatedTokenAccountIdempotentInstruction(
payer.publicKey,
associatedToken,
owner,
mint,
programId,
associatedTokenProgramId
)
);
await sendAndConfirmTransaction(connection, transaction, [payer], confirmOptions);
return associatedToken;
}

View File

@ -6,6 +6,7 @@ export * from './burnChecked.js';
export * from './closeAccount.js';
export * from './createAccount.js';
export * from './createAssociatedTokenAccount.js';
export * from './createAssociatedTokenAccountIdempotent.js';
export * from './createMint.js';
export * from './createMultisig.js';
export * from './createNativeMint.js';

View File

@ -3,7 +3,7 @@ import { SystemProgram, TransactionInstruction } from '@solana/web3.js';
import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID } from '../constants.js';
/**
* Construct an AssociatedTokenAccount instruction
* Construct a CreateAssociatedTokenAccount instruction
*
* @param payer Payer of the initialization fees
* @param associatedToken New associated token account
@ -21,6 +21,57 @@ export function createAssociatedTokenAccountInstruction(
mint: PublicKey,
programId = TOKEN_PROGRAM_ID,
associatedTokenProgramId = ASSOCIATED_TOKEN_PROGRAM_ID
): TransactionInstruction {
return buildAssociatedTokenAccountInstruction(
payer,
associatedToken,
owner,
mint,
Buffer.alloc(0),
programId,
associatedTokenProgramId
);
}
/**
* Construct a CreateAssociatedTokenAccountIdempotent instruction
*
* @param payer Payer of the initialization fees
* @param associatedToken New associated token account
* @param owner Owner of the new account
* @param mint Token mint account
* @param programId SPL Token program account
* @param associatedTokenProgramId SPL Associated Token program account
*
* @return Instruction to add to a transaction
*/
export function createAssociatedTokenAccountIdempotentInstruction(
payer: PublicKey,
associatedToken: PublicKey,
owner: PublicKey,
mint: PublicKey,
programId = TOKEN_PROGRAM_ID,
associatedTokenProgramId = ASSOCIATED_TOKEN_PROGRAM_ID
): TransactionInstruction {
return buildAssociatedTokenAccountInstruction(
payer,
associatedToken,
owner,
mint,
Buffer.from([1]),
programId,
associatedTokenProgramId
);
}
function buildAssociatedTokenAccountInstruction(
payer: PublicKey,
associatedToken: PublicKey,
owner: PublicKey,
mint: PublicKey,
instructionData: Buffer,
programId = TOKEN_PROGRAM_ID,
associatedTokenProgramId = ASSOCIATED_TOKEN_PROGRAM_ID
): TransactionInstruction {
const keys = [
{ pubkey: payer, isSigner: true, isWritable: true },
@ -34,6 +85,6 @@ export function createAssociatedTokenAccountInstruction(
return new TransactionInstruction({
keys,
programId: associatedTokenProgramId,
data: Buffer.alloc(0),
data: instructionData,
});
}

View File

@ -10,6 +10,7 @@ import {
createMint,
getMint,
createAccount,
createAssociatedTokenAccountIdempotent,
getAccount,
getAssociatedTokenAddress,
} from '../../src';
@ -142,5 +143,17 @@ describe('createAccount', () => {
TEST_PROGRAM_ID
)
).to.be.rejected;
// when creating again but with idempotent mode, TX should not throw error
return expect(
createAssociatedTokenAccountIdempotent(
connection,
payer,
mint,
owner.publicKey,
undefined,
TEST_PROGRAM_ID
)
).to.be.fulfilled;
});
});