Token Hesabı Oluşturma
Token Hesabı Nedir?
Bir token hesabı, belirli bir tokenin bakiyesini saklar. Her token hesabı tam olarak bir mint ile ilişkilendirilir ve token bakiyenizi ve ek detayları takip eder.
/// 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>,}
Kaynak kodunda, geliştiricilerin Token hesabını Account
türü olarak
adlandırdığını unutmayın. Hem Token
Program
hem de Token Extensions
Program
Token hesabı için aynı temel uygulamayı paylaşır.
Tokenleri tutmak için, o belirli mint için bir token hesabına ihtiyacınız vardır. Her token hesabı şunları takip eder:
- Mint: Tuttuğu belirli token türü
- Sahip: Bu hesaptan tokenleri transfer edebilen yetkili
Örnek: USD Coin (USDC)
- Mint adresi:
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
- Circle'ın token hesabı:
3emsAVdmGKERbHjmGfQ6oZ1e35dkf5iYcS6U4CPKFVaa
- Bu hesap sadece USDC tokenleri tutar
- Circle, token hesabı sahibi yetkisi aracılığıyla tokeni kontrol eder:
7VHUFJHWu2CuExkJcJrzhQPJ2oygupTWkL2A2For4BmE
Bu token hesabının detaylarını Solana Explorer üzerinde görüntüleyebilirsiniz.
"Sahip" Terminolojisini Anlamak
"Sahip" terimi iki farklı bağlamda kullanılabilir:
-
Token Hesabı Sahibi: Tokenleri transfer edebilen, yakabilen veya devredebilen yetkili. Bu, token hesabının verilerinde saklanır.
-
Program Sahibi: Hesabın sahibi olan program (token hesapları için her zaman Token Program veya Token Extensions Program).
Token hesaplarıyla çalışırken, "sahip" genellikle hesabın sahibi olan programa değil, tokenleri transfer edebilen yetkiliyi ifade eder.
Associated Token Account Nedir?
Associated token account (ATA), bir cüzdanın belirli bir tokeni tutması için varsayılan token hesabıdır. Associated Token Program tarafından oluşturulan deterministik bir adres (PDA) kullanır.
Yalnızca Associated Token Program tarafından oluşturulan token hesapları "associated token accounts" olarak adlandırılır.
ATA'lar belirleyici adresler kullanır, bu da herhangi bir cüzdanın belirli bir mint için token hesabını bulmanızı kolaylaştırır. Türetme uygulamasını burada görebilirsiniz.
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)}
Herhangi bir cüzdan ve token kombinasyonu için tam olarak bir ATA adresi vardır. Bu, token hesap adreslerini manuel olarak takip etme ihtiyacını ortadan kaldırır—her zaman doğru adresi türetebilirsiniz.
Associated Token Program Nasıl Çalışır
Associated Token Program şunları yapan bir yardımcıdır:
- Belirleyici adreslerde (PDA'lar) token hesapları oluşturur
- Token Program'a Cross-Program Invocation (CPI) yapar
- Kendisi herhangi bir durum bilgisi tutmaz
Oluşturulan token hesapları Token Program tarafından sahiplenilir ve standart
Account
yapısını kullanır.
Token Hesabı Nasıl Oluşturulur
Token hesabı oluşturmak için
InitializeAccount
talimatı gereklidir.
Uygulamayı burada görebilirsiniz.
Token hesabı oluşturmak için iki talimata ihtiyacınız vardır:
- System Program: Token hesabı için ayrılmış alanı olan bir hesap oluşturun ve sahipliği Token Program'a aktarın
- Token Program: Token hesap verilerini başlatın
Typescript
import {airdropFactory,appendTransactionMessageInstructions,createSolanaRpc,createSolanaRpcSubscriptions,createTransactionMessage,generateKeyPairSigner,getSignatureFromTransaction,lamports,pipe,sendAndConfirmTransactionFactory,setTransactionMessageFeePayerSigner,setTransactionMessageLifetimeUsingBlockhash,signTransactionMessageWithSigners} from "@solana/kit";import { getCreateAccountInstruction } from "@solana-program/system";import {getInitializeAccount2Instruction,getInitializeMintInstruction,getMintSize,getTokenSize,TOKEN_PROGRAM_ADDRESS} from "@solana-program/token";// Create Connection, local validator in this exampleconst rpc = createSolanaRpc("http://localhost:8899");const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");// Get latest blockhash to include in transactionconst { value: latestBlockhash } = await rpc.getLatestBlockhash().send();// Generate keypairs for fee payerconst feePayer = await generateKeyPairSigner();// Fund fee payerawait airdropFactory({ rpc, rpcSubscriptions })({recipientAddress: feePayer.address,lamports: lamports(1_000_000_000n),commitment: "confirmed"});// Generate keypair to use as address of mintconst mint = await generateKeyPairSigner();// Get default mint account size (in bytes), no extensions enabledconst space = BigInt(getMintSize());// Get minimum balance for rent exemptionconst rent = await rpc.getMinimumBalanceForRentExemption(space).send();// Instruction to create new account for mint (token program)// Invokes the system programconst createAccountInstruction = getCreateAccountInstruction({payer: feePayer,newAccount: mint,lamports: rent,space,programAddress: TOKEN_PROGRAM_ADDRESS});// Instruction to initialize mint account data// Invokes the token programconst initializeMintInstruction = getInitializeMintInstruction({mint: mint.address,decimals: 2,mintAuthority: feePayer.address});const instructions = [createAccountInstruction, initializeMintInstruction];// Create transaction messageconst transactionMessage = pipe(createTransactionMessage({ version: 0 }), // Create transaction message(tx) => setTransactionMessageFeePayerSigner(feePayer, tx), // Set fee payer(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), // Set transaction blockhash(tx) => appendTransactionMessageInstructions(instructions, tx) // Append instructions);// Sign transaction message with required signers (fee payer and mint keypair)const signedTransaction =await signTransactionMessageWithSigners(transactionMessage);// Send and confirm transactionawait sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransaction,{ commitment: "confirmed" });// Get transaction signatureconst transactionSignature = getSignatureFromTransaction(signedTransaction);console.log("Mint Address:", mint.address);console.log("Transaction Signature:", transactionSignature);// Generate keypair to use as address of token accountconst tokenAccount = await generateKeyPairSigner();// Get token account size (in bytes)const tokenAccountSpace = BigInt(getTokenSize());// Get minimum balance for rent exemptionconst tokenAccountRent = await rpc.getMinimumBalanceForRentExemption(tokenAccountSpace).send();// Instruction to create new account for token account (token program)// Invokes the system programconst createTokenAccountInstruction = getCreateAccountInstruction({payer: feePayer,newAccount: tokenAccount,lamports: tokenAccountRent,space: tokenAccountSpace,programAddress: TOKEN_PROGRAM_ADDRESS});// Instruction to initialize token account data// Invokes the token programconst initializeTokenAccountInstruction = getInitializeAccount2Instruction({account: tokenAccount.address,mint: mint.address,owner: feePayer.address});const instructions2 = [createTokenAccountInstruction,initializeTokenAccountInstruction];// Create transaction message for token account creationconst tokenAccountMessage = pipe(createTransactionMessage({ version: 0 }), // Create transaction message(tx) => setTransactionMessageFeePayerSigner(feePayer, tx), // Set fee payer(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), // Set transaction blockhash(tx) => appendTransactionMessageInstructions(instructions2, tx) // Append instructions);// Sign transaction message with required signers (fee payer and token account keypair)const signedTokenAccountTx =await signTransactionMessageWithSigners(tokenAccountMessage);// Send and confirm transactionawait sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTokenAccountTx,{ commitment: "confirmed" });// Get transaction signatureconst transactionSignature2 = getSignatureFromTransaction(signedTokenAccountTx);console.log("Token Account Address:", tokenAccount.address);console.log("Transaction Signature:", transactionSignature2);
Rust
use anyhow::Result;use solana_client::nonblocking::rpc_client::RpcClient;use solana_sdk::{commitment_config::CommitmentConfig,program_pack::Pack,signature::{Keypair, Signer},system_instruction::create_account,transaction::Transaction,};use spl_token::{id as token_program_id,instruction::{initialize_account, initialize_mint},state::{Account, Mint},};#[tokio::main]async fn main() -> Result<()> {// Create connection to local validatorlet client = RpcClient::new_with_commitment(String::from("http://localhost:8899"),CommitmentConfig::confirmed(),);let latestBlockhash = client.get_latest_blockhash().await?;// Generate a new keypair for the fee payerlet fee_payer = Keypair::new();// Airdrop 1 SOL to fee payerlet airdrop_signature = client.request_airdrop(&fee_payer.pubkey(), 1_000_000_000).await?;client.confirm_transaction(&airdrop_signature).await?;loop {let confirmed = client.confirm_transaction(&airdrop_signature).await?;if confirmed {break;}}// Generate keypair to use as address of mintlet mint = Keypair::new();// Get default mint account size (in bytes), no extensions enabledlet mint_space = Mint::LEN;let mint_rent = client.get_minimum_balance_for_rent_exemption(mint_space).await?;// Instruction to create new account for mint (token program)let create_account_instruction = create_account(&fee_payer.pubkey(), // payer&mint.pubkey(), // new account (mint)mint_rent, // lamportsmint_space as u64, // space&token_program_id(), // program id);// Instruction to initialize mint account datalet initialize_mint_instruction = initialize_mint(&token_program_id(),&mint.pubkey(), // mint&fee_payer.pubkey(), // mint authoritySome(&fee_payer.pubkey()), // freeze authority2, // decimals)?;// Create transaction and add instructionslet transaction = Transaction::new_signed_with_payer(&[create_account_instruction, initialize_mint_instruction],Some(&fee_payer.pubkey()),&[&fee_payer, &mint],latestBlockhash,);// Send and confirm transactionlet transaction_signature = client.send_and_confirm_transaction(&transaction).await?;println!("Mint Address: {}", mint.pubkey());println!("Transaction Signature: {}", transaction_signature);// Generate keypair to use as address of token accountlet token_account = Keypair::new();// Get token account size (in bytes)let token_account_space = Account::LEN;let token_account_rent = client.get_minimum_balance_for_rent_exemption(token_account_space).await?;// Instruction to create new account for token account (token program)let create_token_account_instruction = create_account(&fee_payer.pubkey(), // payer&token_account.pubkey(), // new account (token account)token_account_rent, // lamportstoken_account_space as u64, // space&token_program_id(), // program id);// Instruction to initialize token account datalet initialize_token_account_instruction = initialize_account(&token_program_id(),&token_account.pubkey(), // account&mint.pubkey(), // mint&fee_payer.pubkey(), // owner)?;// Create transaction and add instructionslet transaction = Transaction::new_signed_with_payer(&[create_token_account_instruction,initialize_token_account_instruction,],Some(&fee_payer.pubkey()),&[&fee_payer, &token_account],latestBlockhash,);// Send and confirm transactionlet transaction_signature = client.send_and_confirm_transaction(&transaction).await?;println!("Token Account Address: {}", token_account.pubkey());println!("Transaction Signature: {}", transaction_signature);Ok(())}
Associated Token Account Nasıl Oluşturulur
Associated Token Account (ATA) oluşturmak için ---INLINE-CODE-PLACEHOLDER-85c08564ca556b926744bf94497c4af2--- talimatı gereklidir. Buradaki uygulamaya bakın.
Bu tek talimat, Cross Program Invocation (CPI) aracılığıyla token hesabını oluşturmayı ve başlatmayı otomatik olarak yönetir.
Typescript
import {airdropFactory,appendTransactionMessageInstructions,createSolanaRpc,createSolanaRpcSubscriptions,createTransactionMessage,generateKeyPairSigner,getSignatureFromTransaction,lamports,pipe,sendAndConfirmTransactionFactory,setTransactionMessageFeePayerSigner,setTransactionMessageLifetimeUsingBlockhash,signTransactionMessageWithSigners} from "@solana/kit";import { getCreateAccountInstruction } from "@solana-program/system";import {getCreateAssociatedTokenInstructionAsync,getInitializeMintInstruction,getMintSize,TOKEN_PROGRAM_ADDRESS,findAssociatedTokenPda} from "@solana-program/token";// Create Connection, local validator in this exampleconst rpc = createSolanaRpc("http://localhost:8899");const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");// Generate keypairs for fee payerconst feePayer = await generateKeyPairSigner();// Fund fee payerawait airdropFactory({ rpc, rpcSubscriptions })({recipientAddress: feePayer.address,lamports: lamports(1_000_000_000n),commitment: "confirmed"});// Generate keypair to use as address of mintconst mint = await generateKeyPairSigner();// Get default mint account size (in bytes), no extensions enabledconst space = BigInt(getMintSize());// Get minimum balance for rent exemptionconst rent = await rpc.getMinimumBalanceForRentExemption(space).send();// Get latest blockhash to include in transactionconst { value: latestBlockhash } = await rpc.getLatestBlockhash().send();// Instruction to create new account for mint (token program)// Invokes the system programconst createAccountInstruction = getCreateAccountInstruction({payer: feePayer,newAccount: mint,lamports: rent,space,programAddress: TOKEN_PROGRAM_ADDRESS});// Instruction to initialize mint account data// Invokes the token programconst initializeMintInstruction = getInitializeMintInstruction({mint: mint.address,decimals: 2,mintAuthority: feePayer.address});const instructions = [createAccountInstruction, initializeMintInstruction];// Create transaction messageconst transactionMessage = pipe(createTransactionMessage({ version: 0 }),(tx) => setTransactionMessageFeePayerSigner(feePayer, tx),(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),(tx) => appendTransactionMessageInstructions(instructions, tx));// Sign transaction message with all required signersconst signedTransaction =await signTransactionMessageWithSigners(transactionMessage);// Send and confirm transactionawait sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransaction,{ commitment: "confirmed" });// Get transaction signatureconst transactionSignature = getSignatureFromTransaction(signedTransaction);console.log("Mint Address:", mint.address.toString());console.log("Transaction Signature:", transactionSignature);// Use findAssociatedTokenPda to derive the ATA addressconst [associatedTokenAddress] = await findAssociatedTokenPda({mint: mint.address,owner: feePayer.address,tokenProgram: TOKEN_PROGRAM_ADDRESS});console.log("Associated Token Account Address:",associatedTokenAddress.toString());// Get a fresh blockhash for the second transactionconst { value: latestBlockhash2 } = await rpc.getLatestBlockhash().send();// Create instruction to create the associated token accountconst createAtaInstruction = await getCreateAssociatedTokenInstructionAsync({payer: feePayer,mint: mint.address,owner: feePayer.address});// Create transaction messageconst transactionMessage2 = pipe(createTransactionMessage({ version: 0 }),(tx) => setTransactionMessageFeePayerSigner(feePayer, tx),(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash2, tx),(tx) => appendTransactionMessageInstructions([createAtaInstruction], tx));// Sign transaction message with all required signersconst signedTransaction2 =await signTransactionMessageWithSigners(transactionMessage2);// Send and confirm transactionawait sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransaction2,{ commitment: "confirmed" });// Get transaction signatureconst transactionSignature2 = getSignatureFromTransaction(signedTransaction2);console.log("Transaction Signature:", transactionSignature2);
Rust
use anyhow::Result;use solana_client::nonblocking::rpc_client::RpcClient;use solana_sdk::{commitment_config::CommitmentConfig,program_pack::Pack,signature::{Keypair, Signer},system_instruction::create_account,transaction::Transaction,};use spl_associated_token_account::{get_associated_token_address_with_program_id, instruction::create_associated_token_account,};use spl_token::{id as token_program_id, instruction::initialize_mint, state::Mint};#[tokio::main]async fn main() -> Result<()> {// Create connection to local validatorlet client = RpcClient::new_with_commitment(String::from("http://localhost:8899"),CommitmentConfig::confirmed(),);let latestBlockhash = client.get_latest_blockhash().await?;// Generate a new keypair for the fee payerlet fee_payer = Keypair::new();// Airdrop 1 SOL to fee payerlet airdrop_signature = client.request_airdrop(&fee_payer.pubkey(), 1_000_000_000).await?;client.confirm_transaction(&airdrop_signature).await?;loop {let confirmed = client.confirm_transaction(&airdrop_signature).await?;if confirmed {break;}}// Generate keypair to use as address of mintlet mint = Keypair::new();// Get default mint account size (in bytes), no extensions enabledlet mint_space = Mint::LEN;let mint_rent = client.get_minimum_balance_for_rent_exemption(mint_space).await?;// Instruction to create new account for mint (token program)let create_account_instruction = create_account(&fee_payer.pubkey(), // payer&mint.pubkey(), // new account (mint)mint_rent, // lamportsmint_space as u64, // space&token_program_id(), // program id);// Instruction to initialize mint account datalet initialize_mint_instruction = initialize_mint(&token_program_id(),&mint.pubkey(), // mint&fee_payer.pubkey(), // mint authoritySome(&fee_payer.pubkey()), // freeze authority2, // decimals)?;// Create transaction and add instructionslet transaction = Transaction::new_signed_with_payer(&[create_account_instruction, initialize_mint_instruction],Some(&fee_payer.pubkey()),&[&fee_payer, &mint],latestBlockhash,);// Send and confirm transactionlet transaction_signature = client.send_and_confirm_transaction(&transaction).await?;println!("Mint Address: {}", mint.pubkey());println!("Transaction Signature: {}", transaction_signature);// Get the latest blockhash for the next transactionlet latestBlockhash = client.get_latest_blockhash().await?;// Derive the associated token account address for fee_payerlet associated_token_account = get_associated_token_address_with_program_id(&fee_payer.pubkey(), // owner&mint.pubkey(), // mint&token_program_id(), // program_id);// Instruction to create associated token accountlet create_ata_instruction = create_associated_token_account(&fee_payer.pubkey(), // funding address&fee_payer.pubkey(), // wallet address (owner)&mint.pubkey(), // mint address&token_program_id(), // program id);// Create transaction for associated token account creationlet transaction = Transaction::new_signed_with_payer(&[create_ata_instruction],Some(&fee_payer.pubkey()),&[&fee_payer],latestBlockhash,);// Send and confirm transactionlet transaction_signature = client.send_and_confirm_transaction(&transaction).await?;println!("Associated Token Account Address: {}",associated_token_account.to_string());println!("Transaction Signature: {}", transaction_signature);Ok(())}
Python
#!/usr/bin/env python3import asynciofrom solana.rpc.async_api import AsyncClientfrom solders.keypair import Keypairfrom solders.pubkey import Pubkeyfrom solders.transaction import VersionedTransactionfrom solders.message import MessageV0from spl.token.instructions import create_associated_token_account, get_associated_token_addressfrom spl.token.constants import TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_IDasync def main():rpc = AsyncClient("http://localhost:8899")payer = Keypair()owner = Keypair()# Example mint address (USDC on devnet)mint_address = Pubkey.from_string("4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU")# Get associated token account addressassociated_token_account = get_associated_token_address(owner.pubkey(), mint_address)async with rpc:# Get latest blockhashrecent_blockhash = await rpc.get_latest_blockhash()# Create associated token account instructioncreate_token_account_instruction = create_associated_token_account(payer=payer.pubkey(),owner=owner.pubkey(),mint=mint_address,token_program_id=TOKEN_PROGRAM_ID)# Create messagemessage = MessageV0.try_compile(payer=payer.pubkey(),instructions=[create_token_account_instruction],address_lookup_table_accounts=[],recent_blockhash=recent_blockhash.value.blockhash)# Create transactiontransaction = VersionedTransaction(message, [payer])print(f"Payer: {payer.pubkey()}")print(f"Owner: {owner.pubkey()}")print(f"Associated Token Account: {associated_token_account}")print(f"Mint: {mint_address}")print(f"Associated token account created successfully")if __name__ == "__main__":asyncio.run(main())
Is this page helpful?