Token Hesabı Oluşturma
Token Hesabı Nedir?
Token account, Solana'nın Token Programlarında belirli bir token'ın (mint) bir kişinin sahipliği hakkında bilgi depolayan bir hesap türüdür. Her token account tek bir mint ile ilişkilendirilir ve token bakiyesi ve sahibi gibi 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 Extension
Program
Token hesabı için aynı temel uygulamayı paylaşır.
Belirli bir mint için token tutmak için, kullanıcıların önce bir token account oluşturması gerekir. Her token account şunları takip eder:
- Belirli bir mint (token hesabının tuttuğu token türü)
- Bir sahip (hesaptan token aktarma yetkisine sahip olan otorite)
İşte Solana üzerindeki USD Coin (USDC) kullanarak bir örnek:
- USD Coin mint adresi:
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
- Circle (USD Coin ihraççısı)
3emsAVdmGKERbHjmGfQ6oZ1e35dkf5iYcS6U4CPKFVaa
adresinde bir token account'a sahiptir - Bu token account sadece USD Coin token (mint) birimlerini tutar
- Circle,
7VHUFJHWu2CuExkJcJrzhQPJ2oygupTWkL2A2For4BmE
adresinde sahip yetkisine sahiptir ve bu tokenleri transfer edebilir
Bu token account'ın detaylarını Solana Explorer üzerinde görüntüleyebilirsiniz.
"Sahip" terimi iki farklı bağlamda kullanılır:
-
Token account "sahibi" - Bu, token account'ın verilerinde Token Programı tarafından tanımlanan Account türünün "owner" alanı olarak saklanan bir adrestir. Sahip, hesaptan token transfer edebilir, yakabilir veya devredebilir. Bu adres, bazen program sahibinden ayırt etmek için token account'ın "yetkisi" olarak da adlandırılır.
-
Program "owner" - Bu, Solana'daki hesap verilerinin sahibi olan programı ifade eder. Token hesapları için bu, her zaman ya Token Program ya da Token Extension Program'dır ve temel Solana Account tipinin "owner" alanında belirtilir.
Token hesaplarıyla çalışırken, "owner" genellikle hesabın sahibi olan programı değil, tokenleri harcama yetkisine sahip olan otoriteyi ifade eder.
Associated Token Account nedir?
Associated token account, Associated Token Program tarafından oluşturulan Program Derived Address (PDA) olan bir adrese sahip token hesabıdır. Associated token account'u, bir kullanıcının belirli bir token'ın (mint) birimlerini tutmak için kullandığı varsayılan token hesabı olarak düşünebilirsiniz.
"Associated token accounts" terimi yalnızca Associated Token Program'ın oluşturduğu token hesapları için geçerlidir.
Associated token account'lar, herhangi bir mint için bir kullanıcının token hesabını belirleyici bir şekilde bulmanın yolunu sağlar. Türetmenin uygulamasını burada inceleyebilirsiniz.
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)}
Bu belirleyici türetme, herhangi bir cüzdan adresi ve token mint kombinasyonu için tam olarak bir associated token account adresi olduğunu garanti eder. Bu yaklaşım, herhangi bir token mint için bir kullanıcının token hesabını bulma işlemini basitleştirir ve token hesap adreslerini ayrıca takip etme ihtiyacını ortadan kaldırır.
Associated Token Program, belirleyici adreslerle (PDA'lar) token hesapları
oluşturan bir yardımcı program olarak işlev görür. Associated token account
oluştururken, Associated Token Program, Token Program veya Token Extension
Program'a bir CPI (Cross-Program Invocation) yapar. Token programı, token
programında tanımlanan aynı Account
tip yapısına sahip olan oluşturulan
hesabın sahibidir. Associated Token Program hiçbir durum tutmaz - sadece
belirleyici bir adreste (PDA olan) token hesapları oluşturmak için
standartlaştırılmış bir yol sunar.
Token Account Nasıl Oluşturulur
Token Account oluşturmak için
InitializeAccount
talimatını çağırın. Bu talimatın uygulamalarını
burada
bulabilirsiniz.
Token account oluşturmak için işlem iki talimat gerektirir:
- Token account için alan oluşturmak ve ayırmak için System Program'ı çağırın ve sahipliği Token Program'a aktarın.
- Token account verilerini başlatmak için Token Program'ı çağırı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_2022_PROGRAM_ADDRESS} from "@solana-program/token-2022";// Create Connection, local validator in this exampleconst rpc = createSolanaRpc("http://127.0.0.1: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 2022 program)// Invokes the system programconst createAccountInstruction = getCreateAccountInstruction({payer: feePayer,newAccount: mint,lamports: rent,space,programAddress: TOKEN_2022_PROGRAM_ADDRESS});// Instruction to initialize mint account data// Invokes the token 2022 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 2022 program)// Invokes the system programconst createTokenAccountInstruction = getCreateAccountInstruction({payer: feePayer,newAccount: tokenAccount,lamports: tokenAccountRent,space: tokenAccountSpace,programAddress: TOKEN_2022_PROGRAM_ADDRESS});// Instruction to initialize token account data// Invokes the token 2022 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 tokenAccountTxSignature =getSignatureFromTransaction(signedTokenAccountTx);console.log("Token Account Address:", tokenAccount.address);console.log("Transaction Signature:", tokenAccountTxSignature);
Rust
use anyhow::Result;use solana_client::rpc_client::RpcClient;use solana_sdk::{commitment_config::CommitmentConfig,program_pack::Pack,signature::{Keypair, Signer},system_instruction::create_account,transaction::Transaction,};use spl_token_2022::{id as token_2022_program_id,instruction::{initialize_account, initialize_mint},state::{Account, Mint},};fn main() -> Result<()> {// Create connection to local validatorlet client = RpcClient::new_with_commitment(String::from("http://127.0.0.1:8899"),CommitmentConfig::confirmed(),);let recent_blockhash = client.get_latest_blockhash()?;// 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)?;client.confirm_transaction(&airdrop_signature)?;loop {let confirmed = client.confirm_transaction(&airdrop_signature)?;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)?;// Instruction to create new account for mint (token 2022 program)let create_account_instruction = create_account(&fee_payer.pubkey(), // payer&mint.pubkey(), // new account (mint)mint_rent, // lamportsmint_space as u64, // space&token_2022_program_id(), // program id);// Instruction to initialize mint account datalet initialize_mint_instruction = initialize_mint(&token_2022_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],recent_blockhash,);// Send and confirm transactionlet transaction_signature = client.send_and_confirm_transaction(&transaction)?;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)?;// Instruction to create new account for token account (token 2022 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_2022_program_id(), // program id);// Instruction to initialize token account datalet initialize_token_account_instruction = initialize_account(&token_2022_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],recent_blockhash,);// Send and confirm transactionlet transaction_signature = client.send_and_confirm_transaction(&transaction)?;println!("Token Account Address: {}", token_account.pubkey());println!("Transaction Signature: {}", transaction_signature);Ok(())}
Associated Token Account Nasıl Oluşturulur
Associated Token Account oluşturmak için
Create
talimatını çağırın. Bu talimatın uygulamalarını
burada
bulabilirsiniz.
Associated token account oluşturmak için talimat, token account oluşturmak için System Program'ı ve token account verilerini başlatmak için Token Program'ı otomatik olarak çağırır. Bu, Cross Program Invocation (CPI) aracılığıyla gerçekleşir.
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_2022_PROGRAM_ADDRESS,findAssociatedTokenPda} from "@solana-program/token-2022";// Create Connection, local validator in this exampleconst rpc = createSolanaRpc("http://127.0.0.1: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 2022 program)// Invokes the system programconst createAccountInstruction = getCreateAccountInstruction({payer: feePayer,newAccount: mint,lamports: rent,space,programAddress: TOKEN_2022_PROGRAM_ADDRESS});// Instruction to initialize mint account data// Invokes the token 2022 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_2022_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::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_2022::{id as token_2022_program_id, instruction::initialize_mint, state::Mint};fn main() -> Result<()> {// Create connection to local validatorlet client = RpcClient::new_with_commitment(String::from("http://127.0.0.1:8899"),CommitmentConfig::confirmed(),);let recent_blockhash = client.get_latest_blockhash()?;// 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)?;client.confirm_transaction(&airdrop_signature)?;loop {let confirmed = client.confirm_transaction(&airdrop_signature)?;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)?;// Instruction to create new account for mint (token 2022 program)let create_account_instruction = create_account(&fee_payer.pubkey(), // payer&mint.pubkey(), // new account (mint)mint_rent, // lamportsmint_space as u64, // space&token_2022_program_id(), // program id);// Instruction to initialize mint account datalet initialize_mint_instruction = initialize_mint(&token_2022_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],recent_blockhash,);// Send and confirm transactionlet transaction_signature = client.send_and_confirm_transaction(&transaction)?;println!("Mint Address: {}", mint.pubkey());println!("Transaction Signature: {}", transaction_signature);// Get the latest blockhash for the next transactionlet recent_blockhash = client.get_latest_blockhash()?;// 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_2022_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&mint.pubkey(), // mint address&token_2022_program_id(), // program id);// Create transaction and add instructionlet transaction = Transaction::new_signed_with_payer(&[create_ata_instruction],Some(&fee_payer.pubkey()),&[&fee_payer],recent_blockhash,);// Send and confirm transactionlet transaction_signature = client.send_and_confirm_transaction(&transaction)?;println!("Associated Token Account Address: {}",associated_token_account);println!("Transaction Signature: {}", transaction_signature);Ok(())}
Is this page helpful?