Wat is een tokenaccount
Een token account slaat tokens op voor één mint en één tokenaccount-eigenaar op Solana.
/// Account data.#[repr(C)]#[derive(Clone, Copy, Debug, Default, PartialEq)]pub struct Account {/// The mint associated with this accountpub 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 delegatepub delegate: COption<Pubkey>,/// The account's statepub 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 delegatedpub delegated_amount: u64,/// Optional authority to close the account.pub close_authority: COption<Pubkey>,}
Hier betekent owner de autoriteit die tokens van het token account kan
overdragen, verbranden of delegeren. De programma-eigenaar van het account is
nog steeds het Token Program of Token Extensions Program.
Elk token account is gekoppeld aan precies één mint, wat betekent dat het token
account alleen eenheden van één token kan bevatten, namelijk het token
geïdentificeerd door het mint-veld van het token account.
Wat is een associated token account
Een associated token account (ATA) is het standaard token account voor een wallet en mint. Het Associated Token Program leidt het ATA-adres af van het walletadres, het tokenprogramma-adres en het mint-adres.
Alleen tokenaccounts die door het Associated Token Program zijn aangemaakt, worden associated token accounts genoemd.
Het Associated Token Program is een manier om een token account aan te maken op een standaard, deterministisch adres. Het resulterende account is nog steeds een token account dat eigendom is van het Token Program of Token Extensions Program, niet van het Associated Token Program.
Het Associated Token Program leidt het ATA-adres af zoals weergegeven in address.rs:
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)}
Voor elke combinatie van wallet, tokenprogramma en mint bestaat er precies één
ATA-adres. Het Associated Token Program maakt een standaard token account aan op
dat adres, en het resulterende account gebruikt nog steeds het
Account-type gedefinieerd door het Token Program of Token Extensions
Program.
Hoe maak je een Associated Token Account aan
Het aanmaken van een associated token account maakt gebruik van de Create-
of CreateIdempotent-instructie van het Associated Token Program. Het
Associated Token Program leidt het ATA-adres af, maakt het account aan op het
ATA-adres en initialiseert het account als een token account dat eigendom is van
het Token Program of Token Extension Program.
Aanbevolen
Voor de meeste applicaties kun je het beste token accounts aanmaken via het Associated Token Program in plaats van ze direct aan te maken door System Program- en Token Program-instructies aan te roepen. Een associated token account gebruikt een deterministisch adres dat is afgeleid van de eigenaar, het token program en de mint, waardoor het standaard token account voor een bepaalde mint gemakkelijker te vinden is voor wallets en applicaties.
Bronverwijzing
| Item | Beschrijving | Bron |
|---|---|---|
Create | Maakt een associated token account aan op het afgeleide ATA-adres. | Bron |
CreateIdempotent | Maakt het associated token account aan, maar slaagt nog steeds als die ATA al bestaat voor dezelfde eigenaar en mint. | Bron |
process_create_associated_token_account | Leidt het ATA-adres af en gebruikt create_pda_account plus CPI's naar het geselecteerde token program om het token account te initialiseren. Wanneer het geselecteerde program het Token Extension Program is, initialiseert de ATA-processor ook de immutable owner-extensie. | Bron |
create_pda_account | Hulpfunctie die wordt gebruikt door process_create_associated_token_account om het PDA-account aan te maken via CPI naar het System Program. | Bron |
Typescript
De onderstaande Kit-voorbeelden tonen de aanbevolen aanpak met @solana/kit.
Legacy-voorbeelden met @solana/web3.js zijn ter referentie toegevoegd.
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);
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);
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(())}
Python
#!/usr/bin/env python3import asyncioimport jsonfrom solana.rpc.async_api import AsyncClientfrom solders.keypair import Keypairfrom solders.message import Messagefrom solders.pubkey import Pubkeyfrom solders.system_program import create_account, CreateAccountParamsfrom solders.transaction import Transactionfrom spl.token.async_client import AsyncTokenfrom spl.token.instructions import (create_associated_token_account,get_associated_token_address,initialize_mint,InitializeMintParams,)from spl.token.constants import MINT_LEN, TOKEN_PROGRAM_IDasync 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 valuefor 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())
Hoe maak je een Token Account aan
Het aanmaken van een token account vereist twee instructies:
- De
CreateAccount-instructie van het System Program maakt een nieuw rent-exempt account aan en wijst het Token Program toe als de programma-eigenaar van het nieuwe account. - De
InitializeAccount-,InitializeAccount2- ofInitializeAccount3-instructie van het Token Program initialiseert het nieuwe account voor een mint en eigenaar.
Neem de CreateAccount-instructie en de token
account-initialisatie-instructie op in dezelfde transactie.
Tijdens de initialisatie van het token account controleert het Token Program of het account niet al is geïnitialiseerd en rent-exempt is.
De sectie hieronder laat zien hoe je een token account aanmaakt door rechtstreeks de instructies van het System Program en Token Program aan te roepen. Voor de meeste toepassingen is het beter om het Associated Token Program te gebruiken. Gebruik directe aanroepen naar het System Program en Token Program wanneer je een specifieke reden hebt om geen associated token account te gebruiken of wanneer je aangepaste PDA token accounts moet maken door CPI's te doen naar de instructies van het System Program en Token Program vanuit je eigen Solana-programma.
Bronverwijzing
| Item | Beschrijving | Token Program | Token Extensions Program |
|---|---|---|---|
Account | De basis token account-velden die zijn opgeslagen in elk token account. | Bron | Bron |
InitializeAccount | Een token account-initialisatie-instructie die de eigenaar en rent sysvar account verwacht in zijn accountlijst. | Bron | Bron |
InitializeAccount2 | Een token account-initialisatie-instructie die de eigenaar in instruction data doorgeeft in plaats van in de accountlijst. | Bron | Bron |
InitializeAccount3 | Een token account-initialisatie-instructie die de eigenaar in instruction data doorgeeft en geen rent sysvar account vereist. | Bron | Bron |
_process_initialize_account | Gedeelde processorlogica voor token account-initialisatie. | Bron | Bron |
process_initialize_account | Publieke handler voor InitializeAccount. | Bron | Bron |
process_initialize_account2 | Publieke handler voor InitializeAccount2. | Bron | Bron |
process_initialize_account3 | Publieke handler voor InitializeAccount3. | Bron | Bron |
Typescript
De onderstaande Kit voorbeelden tonen de aanbevolen aanpak met @solana/kit.
Legacy voorbeelden met @solana/web3.js zijn ter referentie opgenomen.
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);
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);
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(())}
Python
#!/usr/bin/env python3import asyncioimport jsonfrom solana.rpc.async_api import AsyncClientfrom solders.keypair import Keypairfrom solders.message import Messagefrom solders.pubkey import Pubkeyfrom solders.system_program import create_account, CreateAccountParamsfrom solders.transaction import Transactionfrom spl.token.async_client import AsyncTokenfrom spl.token.instructions import (initialize_account,InitializeAccountParams,initialize_mint,InitializeMintParams,)from spl.token.constants import ACCOUNT_LEN, MINT_LEN, TOKEN_PROGRAM_IDasync 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)).valuecreate_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 valuefor 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())
Is this page helpful?