Μεταφορά Tokens
Πώς να μεταφέρετε Tokens
Οι μεταφορές token μετακινούν tokens μεταξύ token accounts του ίδιου mint
χρησιμοποιώντας την εντολή
TransferChecked
.
- Και οι δύο token accounts πρέπει να περιέχουν τον ίδιο τύπο token (mint)
- Μόνο ο ιδιοκτήτης του λογαριασμού προέλευσης ή ο εξουσιοδοτημένος αντιπρόσωπος μπορεί να εγκρίνει μεταφορές
Το Token Program και το Token Extension Program μοιράζονται παρόμοιες υλοποιήσεις για την επίτευξη της ίδιας λειτουργικότητας.
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,getMintToInstruction,getTransferInstruction,fetchToken} 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 payer (sender) and recipientconst feePayer = await generateKeyPairSigner();const recipient = await generateKeyPairSigner();console.log("Fee Payer/Sender Address:", feePayer.address.toString());console.log("Recipient Address:", recipient.address.toString());// 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();console.log("Mint Address:", mint.address.toString());// 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});// Derive the ATAs for sender and recipientconst [senderAssociatedTokenAddress] = await findAssociatedTokenPda({mint: mint.address,owner: feePayer.address,tokenProgram: TOKEN_PROGRAM_ADDRESS});const [recipientAssociatedTokenAddress] = await findAssociatedTokenPda({mint: mint.address,owner: recipient.address,tokenProgram: TOKEN_PROGRAM_ADDRESS});console.log("Sender Associated Token Account Address:",senderAssociatedTokenAddress.toString());console.log("Recipient Associated Token Account Address:",recipientAssociatedTokenAddress.toString());// Create instruction for sender's ATAconst createSenderAtaInstruction =await getCreateAssociatedTokenInstructionAsync({payer: feePayer,mint: mint.address,owner: feePayer.address});// Create instruction for recipient's ATAconst createRecipientAtaInstruction =await getCreateAssociatedTokenInstructionAsync({payer: feePayer,mint: mint.address,owner: recipient.address});// Create instruction to mint tokens to senderconst mintToInstruction = getMintToInstruction({mint: mint.address,token: senderAssociatedTokenAddress,mintAuthority: feePayer.address,amount: 100n});// Combine all instructions in orderconst instructions = [createAccountInstruction, // Create mint accountinitializeMintInstruction, // Initialize mintcreateSenderAtaInstruction, // Create sender's ATAcreateRecipientAtaInstruction, // Create recipient's ATAmintToInstruction // Mint tokens to sender];// 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("Transaction Signature:", transactionSignature);console.log("Successfully minted 1.0 tokens");// Get a fresh blockhash for the transfer transactionconst { value: transferBlockhash } = await rpc.getLatestBlockhash().send();// Create instruction to transfer tokensconst transferInstruction = getTransferInstruction({source: senderAssociatedTokenAddress,destination: recipientAssociatedTokenAddress,authority: feePayer.address,amount: 50n // 0.50 tokens with 2 decimals});// Create transaction message for token transferconst transferTxMessage = pipe(createTransactionMessage({ version: 0 }),(tx) => setTransactionMessageFeePayerSigner(feePayer, tx),(tx) => setTransactionMessageLifetimeUsingBlockhash(transferBlockhash, tx),(tx) => appendTransactionMessageInstructions([transferInstruction], tx));// Sign transaction message with all required signersconst signedTransferTx =await signTransactionMessageWithSigners(transferTxMessage);// Send and confirm transactionawait sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransferTx,{ commitment: "confirmed" });// Get transaction signatureconst transactionSignature2 = getSignatureFromTransaction(signedTransferTx);console.log("Transaction Signature:", transactionSignature2);console.log("Successfully transferred 0.5 tokens");const senderTokenAccount = await fetchToken(rpc, senderAssociatedTokenAddress, {commitment: "confirmed"});const recipientTokenAccount = await fetchToken(rpc,recipientAssociatedTokenAddress,{commitment: "confirmed"});const senderBalance = senderTokenAccount.data.amount;const recipientBalance = recipientTokenAccount.data.amount;console.log("=== Final Balances ===");console.log("Sender balance:", Number(senderBalance) / 100, "tokens");console.log("Recipient balance:", Number(recipientBalance) / 100, "tokens");
Console
Click to execute the code.
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, mint_to, transfer_checked},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();// Generate a second keypair for the token recipientlet recipient = 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;}}// Airdrop 1 SOL to recipient for rent exemptionlet recipient_airdrop_signature = client.request_airdrop(&recipient.pubkey(), 1_000_000_000).await?;client.confirm_transaction(&recipient_airdrop_signature).await?;loop {let confirmed = client.confirm_transaction(&recipient_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)?;// Calculate the associated token account address for fee_payerlet source_token_address = get_associated_token_address_with_program_id(&fee_payer.pubkey(), // owner&mint.pubkey(), // mint&token_program_id(), // program_id);// Instruction to create associated token account for fee_payerlet create_source_ata_instruction = create_associated_token_account(&fee_payer.pubkey(), // funding address&fee_payer.pubkey(), // wallet address&mint.pubkey(), // mint address&token_program_id(), // program id);// Calculate the associated token account address for recipientlet destination_token_address = get_associated_token_address_with_program_id(&recipient.pubkey(), // owner&mint.pubkey(), // mint&token_program_id(), // program_id);// Instruction to create associated token account for recipientlet create_destination_ata_instruction = create_associated_token_account(&fee_payer.pubkey(), // funding address&recipient.pubkey(), // wallet address&mint.pubkey(), // mint address&token_program_id(), // program id);// Amount of tokens to mint (100 tokens with 2 decimal places)let amount = 100_00;// Create mint_to instruction to mint tokens to the source token accountlet mint_to_instruction = mint_to(&token_program_id(),&mint.pubkey(), // mint&source_token_address, // destination&fee_payer.pubkey(), // authority&[&fee_payer.pubkey()], // signeramount, // amount)?;// Create transaction and add instructionslet transaction = Transaction::new_signed_with_payer(&[create_account_instruction,initialize_mint_instruction,create_source_ata_instruction,create_destination_ata_instruction,mint_to_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!("Source Token Account Address: {}", source_token_address);println!("Destination Token Account Address: {}",destination_token_address);println!("Setup Transaction Signature: {}", transaction_signature);println!("Minted {} tokens to the source token account", amount);// Get the latest blockhash for the transfer transactionlet latestBlockhash = client.get_latest_blockhash().await?;// Amount of tokens to transfer (0.50 tokens with 2 decimals)let transfer_amount = 50;// Create transfer_checked instruction to send tokens from source to destinationlet transfer_instruction = transfer_checked(&token_program_id(), // program id&source_token_address, // source&mint.pubkey(), // mint&destination_token_address,// destination&fee_payer.pubkey(), // owner of source&[&fee_payer.pubkey()], // signerstransfer_amount, // amount2, // decimals)?;// Create transaction for transferring tokenslet transaction = Transaction::new_signed_with_payer(&[transfer_instruction],Some(&fee_payer.pubkey()),&[&fee_payer],latestBlockhash,);// Send and confirm transactionlet transaction_signature = client.send_and_confirm_transaction(&transaction).await?;println!("Successfully transferred 0.50 tokens from sender to recipient");println!("Transaction Signature: {}", transaction_signature);// Get token account balances to verify the transferlet source_token_account = client.get_token_account(&source_token_address).await?;let destination_token_account = client.get_token_account(&destination_token_address).await?;if let Some(source_account) = source_token_account {println!("Source Token Account Balance: {} tokens",source_account.token_amount.amount);}if let Some(destination_account) = destination_token_account {println!("Destination Token Account Balance: {} tokens",destination_account.token_amount.amount);}Ok(())}
Console
Click to execute the code.
Is this page helpful?