Typescript
使用 Web3.js 的 SPL 代币

使用 Web3.js 的 SPL 代币

The Token Program

在 Solana 上,所有与代币相关的操作都由 SPL Token ProgramToken2022 Program 处理:这是 Solana 的原生代币框架,定义了所有代币的创建、管理和转移方式。

这是一个统一的程序,处理网络中的所有代币操作,确保一致性和互操作性。

在 Solana 上为所有代币提供一个统一的接口,简化了实现过程,可以在所有 dApp(去中心化应用)和集成(如钱包等)中复用。

让我们从使用 Web3.js 安装所需的包以与 SPL Token Program 一起工作开始:

npm i @solana/spl-token

Mint and Token Accounts

在底层,创建一个 MintToken 账户是相当“复杂”的。需要不同的指令、不同的输入和账户;在实际初始化之前,账户需要达到免租金状态,等等。

Mint Account

如果没有任何抽象,创建一个 Mint 账户看起来会是这样的:

import {
    Keypair,
    sendAndConfirmTransaction,
    SystemProgram,
    Transaction,
} from "@solana/web3.js";
 
import {
    createInitializeMint2Instruction,
    MINT_SIZE,
    getMinimumBalanceForRentExemptMint,
    TOKEN_PROGRAM_ID,
} from "@solana/spl-token";
 
const mint = Keypair.generate();
 
const mintRent = await getMinimumBalanceForRentExemptMint(connection);
 
const createAccountInstruction = SystemProgram.createAccount({
    fromPubkey: feePayer.publicKey,
    newAccountPubkey: mint.publicKey,
    space: MINT_SIZE,
    lamports: mintRent,
    programId: TOKEN_PROGRAM_ID
});
 
const initializeMintInstruction = createInitializeMint2Instruction(
    mint.publicKey, // mint pubkey
    6, // decimals
    feePayer.publicKey, // mint authority
    null, // freeze authority
    TOKEN_PROGRAM_ID
);
 
const transaction = new Transaction().add(
    createAccountInstruction,
    initializeMintInstruction,
);
 
const signature = await sendAndConfirmTransaction(connection, transaction, [keypair, mint]);
 
console.log(`Mint created! Check out your TX here: https://explorer.solana.com/tx/${signature}?cluster=devnet`);

幸运的是,@solana/spl-token 包提供了一些抽象。因此,我们可以通过一个简单的 createMint() 函数来创建一个 Mint 账户,如下所示:

const mint = await createMint(
    connection, // connection
    keypair, // payer
    keypair.publicKey, // mint authority
    null, // freeze authority
    6 // decimals
);

Token Account

同样地,创建 Token 账户如果没有任何抽象会是这样的:

import {
    Keypair,
    sendAndConfirmTransaction,
    SystemProgram,
    Transaction,
} from "@solana/web3.js";
 
import {
    createInitializeAccount3Instruction,
    ACCOUNT_SIZE,
    getMinimumBalanceForRentExemptAccount,
    TOKEN_PROGRAM_ID,
} from "@solana/spl-token";
 
const token = Keypair.generate();
 
const tokenRent = await getMinimumBalanceForRentExemptAccount(connection);
 
const createAccountInstruction = SystemProgram.createAccount({
    fromPubkey: feePayer.publicKey,
    newAccountPubkey: token.publicKey,
    space: ACCOUNT_SIZE,
    lamports: tokenRent,
    programId: TOKEN_PROGRAM_ID
});
 
const initializeTokenInstruction = createInitializeAccount3Instruction(
    token.publicKey, // token pubkey
    mint.publicKey, // mint pubkey
    feePayer.publicKey, // owner pubkey
    TOKEN_PROGRAM_ID
);
 
const transaction = new Transaction().add(
    createAccountInstruction,
    initializeTokenInstruction,
);
 
const signature = await sendAndConfirmTransaction(connection, transaction, [keypair, token]);
 
console.log(`Token created! Check out your TX here: https://explorer.solana.com/tx/${signature}?cluster=devnet`);

但与 Mint 账户一样,@solana/spl-token 包提供了一些抽象来创建 Token 账户。我们可以使用 createAccount() 函数,如下所示:

const token = await createAccount(
    connection, // connection
    keypair, // payer
    mint.publicKey, // mint pubkey
    keypair.publicKey, // owner pubkey
);

Associated Token Account

对于 Associated Token 账户也是如此,但抽象与账户的创建无关,而主要与地址的派生有关,就像 MintToken 账户一样。

以下是如何在没有任何抽象的情况下创建一个 Associated Token 账户:

import {
    sendAndConfirmTransaction,
    Transaction,
} from "@solana/web3.js";
 
import {
    TOKEN_PROGRAM_ID
    createAssociatedTokenAccountIdempotentInstruction,
    getAssociatedTokenAddress,
} from "@solana/spl-token";
 
const associatedTokenAccount = await getAssociatedTokenAddress(
    mint.publicKey, // mint pubkey
    keypair.publicKey, // owner pubkey
    false, // allow owner off-curve
    TOKEN_PROGRAM_ID
);
 
// Create ATA creation instructions for all accounts
const createAtaInstruction = createAssociatedTokenAccountIdempotentInstruction(
    keypair.publicKey, // payer
    associatedTokenAccount, // associated token account address
    keypair.publicKey, // owner
    mint.publicKey, // mint
    TOKEN_PROGRAM_ID
);
 
const transaction = new Transaction().add(
    createAtaInstruction,
);
 
const signature = await sendAndConfirmTransaction(connection, transaction, [keypair]);
 
console.log(`Associated Token created! Check out your TX here: https://explorer.solana.com/tx/${signature}?cluster=devnet`);

以下是带有抽象的实现方式:

const ata = await getOrCreateAssociatedTokenAccount(
    connection, // connection
    keypair, // payer
    mint, // mint pubkey
    keypair.publicKey // owner pubkey
);

如您所见,该函数被称为 getOrCreateAssociatedTokenAccount()。这是因为可能 Associated Token 账户已经被创建过了,我们不希望因此导致交易失败。所以它的作用是创建或直接返回 ATA 的地址。

Blueshift © 2025Commit: fd080b2