Creare un Token Account

Che Cos'è un Token Account

Un token account memorizza i token per un mint e un proprietario del token account su Solana.

Token Account Type
/// Account data.
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Account {
/// The mint associated with this account
pub mint: Pubkey,
/// The owner of this account.
pub owner: Pubkey,
/// The amount of tokens this account holds.
pub amount: u64,
/// If `delegate` is `Some` then `delegated_amount` represents
/// the amount authorized by the delegate
pub delegate: COption<Pubkey>,
/// The account's state
pub state: AccountState,
/// If `is_native.is_some`, this is a native token, and the value logs the
/// rent-exempt reserve. An Account is required to be rent-exempt, so
/// the value is used by the Processor to ensure that wrapped SOL
/// accounts do not drop below this threshold.
pub is_native: COption<u64>,
/// The amount delegated
pub delegated_amount: u64,
/// Optional authority to close the account.
pub close_authority: COption<Pubkey>,
}

Qui, owner indica l'autorità che può trasferire, bruciare o delegare token dal token account. Il proprietario del programma dell'account rimane comunque il Token Program o il Token Extensions Program.

Ogni token account è legato esattamente a un mint, il che significa che il token account può contenere unità di un solo token, il token identificato dal campo mint del token account.

Che Cos'è un Associated Token Account

Un associated token account (ATA) è il token account predefinito per un wallet e un mint. Il Associated Token Program deriva l'indirizzo ATA dall'indirizzo del wallet, dall'indirizzo del token program e dall'indirizzo del mint.

Solo i token account creati dall'Associated Token Program sono chiamati associated token account.

L'Associated Token Program è un modo per creare un token account a un indirizzo standard e deterministico. L'account risultante è comunque un token account di proprietà del Token Program o del Token Extensions Program, non dell'Associated Token Program.

L'Associated Token Program deriva l'indirizzo ATA come mostrato in address.rs:

Associated Token Account Address Derivation
pub fn get_associated_token_address_and_bump_seed_internal(
wallet_address: &Pubkey,
token_mint_address: &Pubkey,
program_id: &Pubkey,
token_program_id: &Pubkey,
) -> (Pubkey, u8) {
Pubkey::find_program_address(
&[
&wallet_address.to_bytes(), // Owner's public key
&token_program_id.to_bytes(), // Token Program or Token Extension Program
&token_mint_address.to_bytes(), // Token mint address
],
program_id, // Associated Token Program ID
)
}

Per qualsiasi combinazione di wallet, token program e mint, esiste esattamente un indirizzo ATA. L'Associated Token Program crea un token account standard a quell'indirizzo, e l'account risultante utilizza comunque il tipo Account definito dal Token Program o dal Token Extensions Program.

Come creare un Associated Token Account

La creazione di un associated token account utilizza l'istruzione Create o CreateIdempotent del Associated Token Program. Il programma Associated Token Program deriva l'indirizzo ATA, crea l'account all'indirizzo ATA e inizializza l'account come token account di proprietà del Token Program o del Token Extension Program.

Consigliato

Per la maggior parte delle applicazioni, si consiglia di creare token account tramite il Associated Token Program anziché crearli invocando direttamente le istruzioni del System Program e del Token Program. Un associated token account utilizza un indirizzo deterministico derivato dal proprietario, dal token program e dal mint, rendendo più semplice per wallet e applicazioni individuare l'account token predefinito per un determinato mint.

Riferimento al codice sorgente

ElementoDescrizioneSorgente
CreateCrea un associated token account all'indirizzo ATA derivato.Sorgente
CreateIdempotentCrea l'associated token account, ma ha comunque esito positivo se l'ATA esiste già per lo stesso proprietario e mint.Sorgente
process_create_associated_token_accountDeriva l'indirizzo ATA e utilizza create_pda_account più CPI al token program selezionato per inizializzare il token account. Quando il programma selezionato è il Token Extension Program, il processore ATA inizializza anche l'estensione immutable owner.Sorgente
create_pda_accountFunzione di supporto utilizzata da process_create_associated_token_account per creare l'account PDA tramite CPI al System Program.Sorgente

Typescript

Gli esempi Kit riportati di seguito mostrano l'approccio consigliato utilizzando @solana/kit. Gli esempi legacy che utilizzano @solana/web3.js sono inclusi a titolo di riferimento.

Kit

import { generateKeyPairSigner } from "@solana/kit";
import { createLocalClient } from "@solana/kit-client-rpc";
import {
associatedTokenProgram,
findAssociatedTokenPda,
tokenProgram,
TOKEN_PROGRAM_ADDRESS
} from "@solana-program/token";
const client = await createLocalClient()
.use(tokenProgram())
.use(associatedTokenProgram());
const result = await client.associatedToken.instructions
.createAssociatedToken({
payer: client.payer, // Account funding account creation.
mint: mint.address, // Mint for the token this account holds.
owner: client.payer.address // Account that owns the token account.
})
.sendTransaction();
const [associatedTokenAddress] = await findAssociatedTokenPda({
mint: mint.address,
owner: client.payer.address,
tokenProgram: TOKEN_PROGRAM_ADDRESS
});
const tokenAccountData = await client.token.accounts.token.fetch(
associatedTokenAddress
);
console.log("Mint Address:", mint.address);
console.log("\nAssociated Token Account Address:", associatedTokenAddress);
console.log("Associated Token Account:", tokenAccountData.data);
console.log("\nTransaction Signature:", result.context.signature);
Console
Click to execute the code.

Web3.js

import { Connection, Keypair, LAMPORTS_PER_SOL } from "@solana/web3.js";
import {
createAssociatedTokenAccount,
createMint,
getAccount,
TOKEN_PROGRAM_ID
} from "@solana/spl-token";
const associatedTokenAccount = await createAssociatedTokenAccount(
connection, // Connection to the local validator.
feePayer, // Account funding account creation.
mintPubkey, // Mint for the token this account holds.
feePayer.publicKey, // Account that owns the token account.
{
commitment: "confirmed" // Confirmation options for the transaction.
},
TOKEN_PROGRAM_ID // Token program to invoke.
);
const tokenAccountData = await getAccount(
connection,
associatedTokenAccount,
"confirmed",
TOKEN_PROGRAM_ID
);
console.log("Mint Address:", mintPubkey.toBase58());
console.log(
"\nAssociated Token Account Address:",
associatedTokenAccount.toBase58()
);
console.log("Associated Token Account:", tokenAccountData);
Console
Click to execute the code.

Rust

Rust
use anyhow::Result;
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_commitment_config::CommitmentConfig;
use solana_sdk::{
program_pack::Pack,
signature::{Keypair, Signer},
transaction::Transaction,
};
use solana_system_interface::instruction::create_account;
use spl_associated_token_account_interface::{
address::get_associated_token_address, instruction::create_associated_token_account,
};
use spl_token_interface::{
id as token_program_id,
instruction::initialize_mint,
state::{Account, Mint},
};
#[tokio::main]
async fn main() -> Result<()> {
let client = RpcClient::new_with_commitment(
String::from("http://localhost:8899"),
CommitmentConfig::confirmed(),
);
let transaction = Transaction::new_signed_with_payer(
&[
create_associated_token_account(
&fee_payer.pubkey(), // Account funding account creation.
&fee_payer.pubkey(), // Account that owns the token account.
&mint.pubkey(), // Mint for the token this account holds.
&token_program_id(), // Token program that owns the account.
),
],
Some(&fee_payer.pubkey()),
&[&fee_payer],
latest_blockhash,
);
let transaction_signature = client.send_and_confirm_transaction(&transaction).await?;
let associated_token_account = get_associated_token_address(&fee_payer.pubkey(), &mint.pubkey());
let token_account = client.get_account(&associated_token_account).await?;
let token_data = Account::unpack(&token_account.data)?;
println!("Mint Address: {}", mint.pubkey());
println!(
"\nAssociated Token Account Address: {}",
associated_token_account
);
println!("Associated Token Account: {:#?}", token_data);
println!("\nTransaction Signature: {}", transaction_signature);
Ok(())
}
Console
Click to execute the code.

Python

Python
#!/usr/bin/env python3
import asyncio
import json
from solana.rpc.async_api import AsyncClient
from solders.keypair import Keypair
from solders.message import Message
from solders.pubkey import Pubkey
from solders.system_program import create_account, CreateAccountParams
from solders.transaction import Transaction
from spl.token.async_client import AsyncToken
from spl.token.instructions import (
create_associated_token_account,
get_associated_token_address,
initialize_mint,
InitializeMintParams,
)
from spl.token.constants import MINT_LEN, TOKEN_PROGRAM_ID
async def main():
rpc = AsyncClient("http://localhost:8899")
fee_payer = Keypair()
owner = Keypair()
async with rpc:
create_associated_token_account_instruction = create_associated_token_account(
payer=fee_payer.pubkey(), # Account funding account creation.
owner=owner.pubkey(), # Account that owns the token account.
mint=mint.pubkey(), # Mint for the token this account holds.
token_program_id=TOKEN_PROGRAM_ID, # Token program that owns the new token account.
)
latest_blockhash = await rpc.get_latest_blockhash()
transaction = Transaction(
[fee_payer],
Message([create_associated_token_account_instruction], fee_payer.pubkey()),
latest_blockhash.value.blockhash,
)
result = await rpc.send_transaction(transaction)
token_account_info = await token.get_account_info(associated_token_account)
token_account = {
key: str(value) if isinstance(value, Pubkey) else value
for key, value in token_account_info._asdict().items()
}
print("Mint Address:", mint.pubkey())
print("\nToken Account Address:", associated_token_account)
print("Token Account:")
print(json.dumps(token_account, indent=2))
print("\nTransaction Signature:", result.value)
if __name__ == "__main__":
asyncio.run(main())
Console
Click to execute the code.

Come Creare un Token Account

La creazione di un token account richiede due istruzioni:

  1. L'istruzione CreateAccount del System Program crea un nuovo account esente da rent e assegna il Token Program come program owner del nuovo account.
  2. L'istruzione InitializeAccount, InitializeAccount2 o InitializeAccount3 del Token Program inizializza il nuovo account per un mint e un owner.

Includi l'istruzione CreateAccount e l'istruzione di inizializzazione del token account nella stessa transazione.

Durante l'inizializzazione del token account, il Token Program verifica che l'account non sia già inizializzato e sia esente da rent.

La sezione seguente mostra come creare un token account chiamando direttamente le istruzioni del System Program e del Token Program. Per la maggior parte delle applicazioni, utilizza invece l' Associated Token Program. Usa le chiamate dirette al System Program e al Token Program quando hai un motivo specifico per non utilizzare un associated token account o quando devi creare token account PDA personalizzati effettuando CPI alle istruzioni del System Program e del Token Program dal tuo programma Solana.

Riferimento al Codice Sorgente

ElementoDescrizioneToken ProgramToken Extensions Program
AccountI campi base del token account memorizzati in ogni token account.SorgenteSorgente
InitializeAccountUn'istruzione di inizializzazione del token account che richiede l'owner e l'account rent sysvar nella sua lista di account.SorgenteSorgente
InitializeAccount2Un'istruzione di inizializzazione del token account che passa l'owner negli instruction data invece che nella lista di account.SorgenteSorgente
InitializeAccount3Un'istruzione di inizializzazione del token account che passa l'owner negli instruction data e non richiede l'account rent sysvar.SorgenteSorgente
_process_initialize_accountLogica condivisa del processore per l'inizializzazione del token account.SorgenteSorgente
process_initialize_accountHandler pubblico per InitializeAccount.SorgenteSorgente
process_initialize_account2Handler pubblico per InitializeAccount2.SorgenteSorgente
process_initialize_account3Handler pubblico per InitializeAccount3.SorgenteSorgente

Typescript

Gli esempi Kit qui sotto mostrano l'approccio consigliato utilizzando @solana/kit. Gli esempi legacy che utilizzano @solana/web3.js sono inclusi per riferimento.

Kit

import { generateKeyPairSigner } from "@solana/kit";
import { createLocalClient } from "@solana/kit-client-rpc";
import { systemProgram } from "@solana-program/system";
import {
getTokenSize,
tokenProgram,
TOKEN_PROGRAM_ADDRESS
} from "@solana-program/token";
const client = await createLocalClient()
.use(systemProgram())
.use(tokenProgram());
const result = await client.sendTransaction([
client.system.instructions.createAccount({
newAccount: tokenAccount, // New token account to create.
lamports: rent, // Lamports funding the new account rent.
space, // Account size in bytes.
programAddress: TOKEN_PROGRAM_ADDRESS // Program that owns the new account.
}),
client.token.instructions.initializeAccount({
account: tokenAccount.address, // Token account to initialize.
mint: mint.address, // Mint for the token this account holds.
owner: client.payer.address // Account that owns the token account.
})
]);
const tokenAccountData = await client.token.accounts.token.fetch(
tokenAccount.address
);
console.log("Mint Address:", mint.address);
console.log("\nToken Account Address:", tokenAccount.address);
console.log("Token Account:", tokenAccountData.data);
console.log("\nTransaction Signature:", result.context.signature);
Console
Click to execute the code.

Web3.js

import { Connection, Keypair, LAMPORTS_PER_SOL } from "@solana/web3.js";
import {
createAccount,
createMint,
getAccount,
TOKEN_PROGRAM_ID
} from "@solana/spl-token";
const tokenAccount = await createAccount(
connection, // Connection to the local validator.
feePayer, // Account paying transaction fees.
mintPubkey, // Mint for the token this account holds.
feePayer.publicKey, // Account that owns the token account.
Keypair.generate(), // New token account to create.
{
commitment: "confirmed" // Confirmation options for the transaction.
},
TOKEN_PROGRAM_ID // Token program to invoke.
);
const tokenAccountData = await getAccount(
connection,
tokenAccount,
"confirmed",
TOKEN_PROGRAM_ID
);
console.log("Mint Address:", mintPubkey.toBase58());
console.log("\nToken Account Address:", tokenAccount.toBase58());
console.log("Token Account:", tokenAccountData);
Console
Click to execute the code.

Rust

Rust
use anyhow::Result;
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_commitment_config::CommitmentConfig;
use solana_sdk::{
program_pack::Pack,
signature::{Keypair, Signer},
transaction::Transaction,
};
use solana_system_interface::instruction::create_account;
use spl_token_interface::{
id as token_program_id,
instruction::{initialize_account, initialize_mint},
state::{Account, Mint},
};
#[tokio::main]
async fn main() -> Result<()> {
let client = RpcClient::new_with_commitment(
String::from("http://localhost:8899"),
CommitmentConfig::confirmed(),
);
let token_account = Keypair::new();
let token_account_rent = client
.get_minimum_balance_for_rent_exemption(Account::LEN)
.await?;
let transaction = Transaction::new_signed_with_payer(
&[
create_account(
&fee_payer.pubkey(), // Account funding account creation.
&token_account.pubkey(), // New token account to create.
token_account_rent, // Lamports funding the new account rent.
Account::LEN as u64, // Account size in bytes.
&token_program_id(), // Program that owns the new account.
),
initialize_account(
&token_program_id(),
&token_account.pubkey(), // Token account to initialize.
&mint.pubkey(), // Mint for the token this account holds.
&fee_payer.pubkey(), // Account that owns the token account.
)?,
],
Some(&fee_payer.pubkey()),
&[&fee_payer, &token_account],
latest_blockhash,
);
let transaction_signature = client.send_and_confirm_transaction(&transaction).await?;
let token_account_data = client.get_account(&token_account.pubkey()).await?;
let token_data = Account::unpack(&token_account_data.data)?;
println!("Mint Address: {}", mint.pubkey());
println!("\nToken Account Address: {}", token_account.pubkey());
println!("Token Account: {:#?}", token_data);
println!("\nTransaction Signature: {}", transaction_signature);
Ok(())
}
Console
Click to execute the code.

Python

Python
#!/usr/bin/env python3
import asyncio
import json
from solana.rpc.async_api import AsyncClient
from solders.keypair import Keypair
from solders.message import Message
from solders.pubkey import Pubkey
from solders.system_program import create_account, CreateAccountParams
from solders.transaction import Transaction
from spl.token.async_client import AsyncToken
from spl.token.instructions import (
initialize_account,
InitializeAccountParams,
initialize_mint,
InitializeMintParams,
)
from spl.token.constants import ACCOUNT_LEN, MINT_LEN, TOKEN_PROGRAM_ID
async def main():
rpc = AsyncClient("http://localhost:8899")
async with rpc:
token_account = Keypair()
token_account_rent = (await rpc.get_minimum_balance_for_rent_exemption(ACCOUNT_LEN)).value
create_token_account_instructions = [
create_account(
CreateAccountParams(
from_pubkey=fee_payer.pubkey(), # Account funding account creation.
to_pubkey=token_account.pubkey(), # New token account to create.
lamports=token_account_rent, # Lamports funding the new account rent.
space=ACCOUNT_LEN, # Account size in bytes.
owner=TOKEN_PROGRAM_ID, # Program that owns the new token account.
)
),
initialize_account(
InitializeAccountParams(
program_id=TOKEN_PROGRAM_ID, # Token program to invoke.
account=token_account.pubkey(), # Token account to initialize.
mint=mint.pubkey(), # Mint for the token this account holds.
owner=fee_payer.pubkey(), # Account that owns the token account.
)
),
]
latest_blockhash = await rpc.get_latest_blockhash()
transaction = Transaction(
[fee_payer, token_account],
Message(create_token_account_instructions, fee_payer.pubkey()),
latest_blockhash.value.blockhash,
)
result = await rpc.send_transaction(transaction)
token_account_info = await token.get_account_info(token_account.pubkey())
token_account_data = {
key: str(value) if isinstance(value, Pubkey) else value
for key, value in token_account_info._asdict().items()
}
print("Mint Address:", mint.pubkey())
print("\nToken Account Address:", token_account.pubkey())
print("Token Account:")
print(json.dumps(token_account_data, indent=2))
print("\nTransaction Signature:", result.value)
if __name__ == "__main__":
asyncio.run(main())
Console
Click to execute the code.

Is this page helpful?

Indice dei contenuti

Modifica pagina

Gestito da

© 2026 Solana Foundation.
Tutti i diritti riservati.
Resta connesso