Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Comprehensive Solana development skill covering @solana/kit v5, Anchor programs, LiteSVM testing, and security patterns.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/kit/programs/token.md
1---2title: SPL Token Program3description: Kit-compatible @solana-program/token client for mint creation, transfers, ATAs, delegation, burning, and instruction plans.4---56# SPL Token Program78Solana's standard token program. Defines Mints (token config + supply) and Token Accounts (per-owner balances). For tokens that need extensions, use [Token-2022](token-2022.md) instead.910If using plugin clients, prefer `client.use(tokenProgram())` for a fluent API that auto-derives ATAs and defaults the payer. The low-level instructions below are for manual `pipe()` transaction building. See [overview.md](../overview.md) and [plugins.md](../plugins.md).1112Program address: `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`1314```ts15import { TOKEN_PROGRAM_ADDRESS } from '@solana-program/token';16```1718## Account Types1920### Mint (82 bytes)2122```ts23import { fetchMint, fetchMaybeMint, getMintSize } from '@solana-program/token';2425const mint = await fetchMint(rpc, mintAddress);26// mint.data.decimals, mint.data.supply, mint.data.mintAuthority, mint.data.freezeAuthority27```2829### Token Account (165 bytes)3031```ts32import { fetchToken, fetchMaybeToken, getTokenSize } from '@solana-program/token';3334const token = await fetchToken(rpc, tokenAddress);35// token.data.mint, token.data.owner, token.data.amount36```3738### Multisig3940```ts41import { fetchMultisig } from '@solana-program/token';4243const multisig = await fetchMultisig(rpc, multisigAddress);44// multisig.data.m, multisig.data.n, multisig.data.signers45```4647## PDA: Associated Token Account4849One deterministic token account per owner per mint. Derived from owner + mint + token program — no on-chain lookup needed. Always prefer ATAs for user-facing flows.5051```ts52import { findAssociatedTokenPda, TOKEN_PROGRAM_ADDRESS } from '@solana-program/token';5354const [ata] = await findAssociatedTokenPda({55owner: walletAddress,56mint: mintAddress,57tokenProgram: TOKEN_PROGRAM_ADDRESS,58});59```6061## Key Instructions6263### Initialize Mint6465```ts66import { getInitializeMintInstruction } from '@solana-program/token';6768const ix = getInitializeMintInstruction({69mint: mintKeypair.address,70decimals: 9,71mintAuthority: authority.address,72freezeAuthority: authority.address, // optional73});74```7576### Transfer7778Prefer `getTransferCheckedInstruction` — validates mint and decimals on-chain, preventing wrong-token transfers.7980```ts81import { getTransferInstruction, getTransferCheckedInstruction } from '@solana-program/token';8283// Simple transfer84const ix = getTransferInstruction({85source: sourceTokenAccount,86destination: destTokenAccount,87authority: owner,88amount: 1_000_000n,89});9091// Checked transfer (validates decimals)92const ix = getTransferCheckedInstruction({93source: sourceTokenAccount,94mint: mintAddress,95destination: destTokenAccount,96authority: owner,97amount: 1_000_000n,98decimals: 9,99});100```101102### Mint To103104```ts105import { getMintToInstruction, getMintToCheckedInstruction } from '@solana-program/token';106107const ix = getMintToInstruction({108mint: mintAddress,109token: destinationTokenAccount,110mintAuthority: authority,111amount: 1_000_000_000n,112});113```114115### Approve Delegate116117```ts118import { getApproveInstruction } from '@solana-program/token';119120const ix = getApproveInstruction({121source: tokenAccount,122delegate: delegateAddress,123owner: owner,124amount: 500_000n,125});126```127128### Burn129130```ts131import { getBurnInstruction } from '@solana-program/token';132133const ix = getBurnInstruction({134account: tokenAccount,135mint: mintAddress,136authority: owner,137amount: 100_000n,138});139```140141## Instruction Plans142143Handle multi-step operations (e.g., create ATA if needed). Auto-check preconditions and only include necessary instructions — use for user-facing flows.144145### Create Mint146147```ts148import { getCreateMintInstructionPlan } from '@solana-program/token';149import { executeInstructionPlan } from '@solana/instruction-plans';150151const plan = getCreateMintInstructionPlan({152mint: mintKeypair,153decimals: 9,154mintAuthority: authority.address,155payer,156rpc,157});158159await executeInstructionPlan(rpc, plan, { payer });160```161162### Mint to ATA (Creates ATA if needed)163164```ts165import { getMintToATAInstructionPlan } from '@solana-program/token';166167const plan = getMintToATAInstructionPlan({168mint: mintAddress,169mintAuthority: authority,170owner: recipientAddress,171amount: 1_000_000_000n,172payer,173rpc,174});175176await executeInstructionPlan(rpc, plan, { payer });177```178179## Complete Pattern: Create Token + Mint180181```ts182import {183pipe, createTransactionMessage, setTransactionMessageFeePayerSigner,184setTransactionMessageLifetimeUsingBlockhash, appendTransactionMessageInstructions,185signTransactionMessageWithSigners, sendAndConfirmTransactionFactory,186assertIsTransactionWithBlockhashLifetime, generateKeyPairSigner, lamports,187} from '@solana/kit';188import {189getInitializeMintInstruction, getMintToInstruction,190getMintSize, TOKEN_PROGRAM_ADDRESS, findAssociatedTokenPda,191getCreateAssociatedTokenInstruction,192} from '@solana-program/token';193import { getCreateAccountInstruction } from '@solana-program/system';194195// 1. Generate mint keypair196const mintKeypair = await generateKeyPairSigner();197198// 2. Get rent199const mintRent = await rpc.getMinimumBalanceForRentExemption(BigInt(getMintSize())).send();200201// 3. Derive ATA202const [ata] = await findAssociatedTokenPda({203owner: recipient.address,204mint: mintKeypair.address,205tokenProgram: TOKEN_PROGRAM_ADDRESS,206});207208const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();209210const message = pipe(211createTransactionMessage({ version: 0 }),212m => setTransactionMessageFeePayerSigner(payer, m),213m => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, m),214m => appendTransactionMessageInstructions([215// Create mint account216getCreateAccountInstruction({217payer,218newAccount: mintKeypair,219lamports: lamports(mintRent),220space: getMintSize(),221programAddress: TOKEN_PROGRAM_ADDRESS,222}),223// Initialize mint224getInitializeMintInstruction({225mint: mintKeypair.address,226decimals: 9,227mintAuthority: payer.address,228}),229// Create ATA230getCreateAssociatedTokenInstruction({231payer,232ata,233owner: recipient.address,234mint: mintKeypair.address,235}),236// Mint tokens237getMintToInstruction({238mint: mintKeypair.address,239token: ata,240mintAuthority: payer,241amount: 1_000_000_000n,242}),243], m),244);245246const sendAndConfirm = sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions });247const signed = await signTransactionMessageWithSigners(message);248assertIsTransactionWithBlockhashLifetime(signed);249await sendAndConfirm(signed, { commitment: 'confirmed' });250```251