Token Hesabı Nedir
Token hesabı, Solana üzerinde bir basım ve bir token hesabı sahibi için tokenları saklar.
/// 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>,}
Burada owner, token hesabından token transfer etme, yakma veya devretme
yetkisine sahip otoriteyi ifade eder. Hesabın program sahibi hala Token Program
veya Token Extensions Program'dır.
Her token hesabı tam olarak bir basıma bağlıdır, yani token hesabı yalnızca bir
tokenın birimlerini tutabilir; bu token, token hesabının mint alanı
tarafından tanımlanan tokendır.
Associated Token Account Nedir
Associated token account (ATA), bir cüzdan ve basım için varsayılan token hesabıdır. Associated Token Program, ATA adresini cüzdan adresi, token program adresi ve basım adresinden türetir.
Yalnızca Associated Token Program tarafından oluşturulan token hesaplarına associated token account denir.
Associated Token Program, standart ve deterministik bir adreste token hesabı oluşturmanın bir yoludur. Ortaya çıkan hesap, Associated Token Program'a değil, Token Program veya Token Extensions Program'a ait bir token account olmaya devam eder.
Associated Token Program, ATA adresini address.rs dosyasında gösterildiği şekilde türetir:
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, token programı ve basım kombinasyonu için tam olarak bir
ATA adresi vardır. Associated Token Program bu adreste standart bir token
account oluşturur ve ortaya çıkan hesap hala Token Program veya Token Extensions
Program tarafından tanımlanan Account türünü kullanır.
İlişkili Token Hesabı Nasıl Oluşturulur
İlişkili bir token hesabı oluşturmak, Associated Token Program'ın Create
veya CreateIdempotent talimatını kullanır. Associated Token Program, ATA
adresini türetir, ATA adresinde hesabı oluşturur ve hesabı Token Program veya
Token Extensions Program'a ait bir token hesabı olarak başlatır.
Önerilen
Çoğu uygulama için, token hesaplarını doğrudan System Program ve Token Program talimatlarını çağırarak oluşturmak yerine Associated Token Program aracılığıyla oluşturun. İlişkili bir token hesabı, sahip, token programı ve mint'ten türetilen deterministik bir adres kullanır; bu da belirli bir mint için varsayılan token hesabının cüzdanlar ve uygulamalar tarafından bulunmasını kolaylaştırır.
Kaynak Referansı
| Öğe | Açıklama | Kaynak |
|---|---|---|
Create | Türetilen ATA adresinde ilişkili bir token hesabı oluşturur. | Kaynak |
CreateIdempotent | İlişkili token hesabını oluşturur, ancak aynı sahip ve mint için söz konusu ATA zaten mevcutsa yine de başarılı olur. | Kaynak |
process_create_associated_token_account | ATA adresini türetir ve token hesabını başlatmak için seçilen token programına create_pda_account artı CPI'ları kullanır. Seçilen program Token Extensions Program olduğunda, ATA işlemcisi ayrıca değiştirilemez sahip uzantısını da başlatır. | Kaynak |
create_pda_account | process_create_associated_token_account tarafından PDA hesabını System Program'a CPI ile oluşturmak için kullanılan yardımcı. | Kaynak |
Typescript
Aşağıdaki Kit örnekleri, @solana/kit kullanan önerilen yaklaşımı gösterir.
@solana/web3.js kullanan eski örnekler referans için eklenmiştir.
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())
Token Hesabı Nasıl Oluşturulur
Bir token hesabı oluşturmak için iki instruction gereklidir:
- System Program'ın
CreateAccountinstruction'ı, yeni bir rent-muaf hesap oluşturur ve Token Program'ı yeni hesabın program sahibi olarak atar. - Token Program'ın
InitializeAccount,InitializeAccount2veyaInitializeAccount3instruction'ı, yeni hesabı bir mint ve sahip için başlatır.
CreateAccount instruction'ını ve token hesabı başlatma instruction'ını
aynı transaction içinde ekleyin.
Token hesabı başlatma sırasında, Token Program hesabın henüz başlatılmamış olduğunu ve rent-muaf olduğunu kontrol eder.
Aşağıdaki bölüm, System Program ve Token Program instruction'larını doğrudan çağırarak bir token hesabının nasıl oluşturulacağını gösterir. Çoğu uygulama için bunun yerine Associated Token Program'ı kullanın. System Program ve Token Program'a doğrudan çağrıları yalnızca associated token account kullanmamak için belirli bir nedeniniz olduğunda veya kendi Solana programınızdan System Program ve Token Program instruction'larına CPI yaparak özel PDA token hesapları oluşturmanız gerektiğinde kullanın.
Kaynak Referansı
| Öğe | Açıklama | Token Program | Token Extensions Program |
|---|---|---|---|
Account | Her token hesabında saklanan temel token hesabı alanları. | Kaynak | Kaynak |
InitializeAccount | Hesaplar listesinde sahip ve rent sysvar hesabı bekleyen bir token hesabı başlatma instruction'ı. | Kaynak | Kaynak |
InitializeAccount2 | Sahibi hesaplar listesi yerine instruction data içinde ileten bir token hesabı başlatma instruction'ı. | Kaynak | Kaynak |
InitializeAccount3 | Sahibi instruction data içinde ileten ve rent sysvar hesabı gerektirmeyen bir token hesabı başlatma instruction'ı. | Kaynak | Kaynak |
_process_initialize_account | Token hesabı başlatma için paylaşılan işlemci mantığı. | Kaynak | Kaynak |
process_initialize_account | InitializeAccount için genel işleyici. | Kaynak | Kaynak |
process_initialize_account2 | InitializeAccount2 için genel işleyici. | Kaynak | Kaynak |
process_initialize_account3 | InitializeAccount3 için genel işleyici. | Kaynak | Kaynak |
Typescript
Aşağıdaki Kit örnekleri, @solana/kit kullanılarak önerilen yaklaşımı
göstermektedir. Referans olması amacıyla @solana/web3.js kullanan eski
örnekler de eklenmiştir.
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?