Что делает перевод токенов?
Перевод токенов перемещает токены из одного аккаунта токенов в другой аккаунт токенов для одного и того же минта.
Переводы не изменяют общее предложение минта. Переводы только обновляют балансы между аккаунтами токенов.
Как переводить токены
Для перевода токенов используется инструкция Transfer или
TransferChecked программы Token Program.
В примерах ниже используется TransferChecked, которая требует от
вызывающей стороны предоставить минт и количество десятичных знаков, чтобы
инструкция могла проверить ожидаемый минт и точность токена перед перемещением
токенов между аккаунтами.
В Token Extensions Program инструкция Transfer устарела и заменена на
TransferChecked или TransferCheckedWithFee.
Владелец исходного аккаунта или утвержденный делегат подписывает перевод. В Token Extensions Program постоянный делегат минта также может авторизовать перевод, если у минта включено расширение постоянного делегата.
Ссылки на исходный код
| Элемент | Описание | Token Program | Token Extensions Program |
|---|---|---|---|
Account | Состояние аккаунта токенов хранит балансы, обновляемые при переводе. | Источник | Источник |
Transfer | Инструкция перевода, которая перемещает токены между аккаунтами токенов без требования от вызывающей стороны предоставлять минт или десятичные знаки. В Token Extensions Program используйте вместо неё TransferChecked. | Источник | Источник |
TransferChecked | Инструкция перевода, которая требует от вызывающей стороны предоставить минт и десятичные знаки и проверяет эти значения перед перемещением токенов между аккаунтами токенов одного и того же минта. | Источник | Источник |
process_transfer | Общая логика обработчика для переводов токенов. | Источник | Источник |
Typescript
Приведенные ниже примеры с использованием Kit демонстрируют рекомендуемый
подход с применением @solana/kit. Устаревшие примеры с использованием
@solana/web3.js приведены для справки.
Kit
import { generateKeyPairSigner } from "@solana/kit";import { createLocalClient } from "@solana/kit-client-rpc";import {findAssociatedTokenPda,tokenProgram,TOKEN_PROGRAM_ADDRESS} from "@solana-program/token";const client = await createLocalClient().use(tokenProgram());const mint = await generateKeyPairSigner();const recipient = await generateKeyPairSigner();const result = await client.token.instructions.transferToATA({mint: mint.address, // Mint for the token being transferred.authority: client.payer, // Owner or delegate approving the transfer.recipient: recipient.address, // Account that owns the destination token account.amount: 25n, // Token amount in base units.decimals: 2 // Decimals defined on the mint account.}).sendTransaction();const [sourceTokenAccount] = await findAssociatedTokenPda({mint: mint.address,owner: client.payer.address,tokenProgram: TOKEN_PROGRAM_ADDRESS});const [destinationTokenAccount] = await findAssociatedTokenPda({mint: mint.address,owner: recipient.address,tokenProgram: TOKEN_PROGRAM_ADDRESS});const [sourceTokenAccountData, destinationTokenAccountData] =await client.token.accounts.token.fetchAll([sourceTokenAccount,destinationTokenAccount]);console.log("Mint Address:", mint.address);console.log("\nSource Token Account Address:", sourceTokenAccount);console.log("Source Token Account:", sourceTokenAccountData.data);console.log("\nDestination Token Account Address:", destinationTokenAccount);console.log("Destination Token Account:", destinationTokenAccountData.data);console.log("\nTransaction Signature:", result.context.signature);
Web3.js
import { Connection, Keypair, LAMPORTS_PER_SOL } from "@solana/web3.js";import {createAssociatedTokenAccount,createMint,getAccount,mintToChecked,TOKEN_PROGRAM_ID,transferChecked} from "@solana/spl-token";const result = await transferChecked(connection, // Connection to the local validator.feePayer, // Account paying transaction fees.feePayerATA, // Token account sending the tokens.mintPubkey, // Mint for the token being transferred.recipientATA, // Token account receiving the tokens.feePayer, // Owner or delegate approving the transfer.25, // Token amount in base units.2, // Decimals defined on the mint account.[], // Additional multisig signers.{commitment: "confirmed" // Confirmation options for the transaction.},TOKEN_PROGRAM_ID // Token program to invoke.);const senderTokenAccount = await getAccount(connection,feePayerATA,"confirmed",TOKEN_PROGRAM_ID);const recipientTokenAccount = await getAccount(connection,recipientATA,"confirmed",TOKEN_PROGRAM_ID);console.log("Mint Address:", mintPubkey.toBase58());console.log("\nSource Token Account Address:", feePayerATA.toBase58());console.log("Source Token Account:", senderTokenAccount);console.log("\nDestination Token Account Address:", recipientATA.toBase58());console.log("Destination Token Account:", recipientTokenAccount);console.log("\nTransaction Signature:", result);
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, mint_to_checked, transfer_checked},state::{Account, Mint},};#[tokio::main]async fn main() -> Result<()> {let client = RpcClient::new_with_commitment(String::from("http://localhost:8899"),CommitmentConfig::confirmed(),);let recipient = Keypair::new();let transfer_amount = 25;let transaction = Transaction::new_signed_with_payer(&[transfer_checked(&token_program_id(), // Token program to invoke.&source_token_address, // Token account sending the tokens.&mint.pubkey(), // Mint for the token being transferred.&destination_token_address, // Token account receiving the tokens.&fee_payer.pubkey(), // Owner or delegate approving the transfer.&[], // Additional multisig signers.transfer_amount, // Token amount in base units.decimals, // Decimals defined on the mint account.)?,],Some(&fee_payer.pubkey()),&[&fee_payer],latest_blockhash,);let transaction_signature = client.send_and_confirm_transaction(&transaction).await?;let source_token_account = client.get_account(&source_token_address).await?;let source_token_data = Account::unpack(&source_token_account.data)?;let destination_token_account = client.get_account(&destination_token_address).await?;let destination_token_data = Account::unpack(&destination_token_account.data)?;println!("Mint Address: {}", mint.pubkey());println!("\nSource Token Account Address: {}", source_token_address);println!("Source Token Account: {:#?}", source_token_data);println!("\nDestination Token Account Address: {}",destination_token_address);println!("Destination Token Account: {:#?}", destination_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,mint_to_checked,MintToCheckedParams,transfer_checked,TransferCheckedParams,)from spl.token.constants import MINT_LEN, TOKEN_PROGRAM_IDDECIMALS = 2AMOUNT_TO_MINT = 100AMOUNT_TO_TRANSFER = 25async def main():rpc = AsyncClient("http://localhost:8899")receiver = Keypair()async with rpc:transfer_tokens_instruction = transfer_checked(TransferCheckedParams(program_id=TOKEN_PROGRAM_ID, # Token program to invoke.source=source_token_account, # Token account sending the tokens.mint=mint.pubkey(), # Mint for the token being transferred.dest=destination_token_account, # Token account receiving the tokens.owner=fee_payer.pubkey(), # Account that owns the source token account.amount=AMOUNT_TO_TRANSFER, # Token amount in base units.decimals=DECIMALS, # Decimals defined on the mint account.))latest_blockhash = await rpc.get_latest_blockhash()transaction = Transaction([fee_payer],Message([transfer_tokens_instruction], fee_payer.pubkey()),latest_blockhash.value.blockhash,)result = await rpc.send_transaction(transaction)source_token_account_info = await token.get_account_info(source_token_account)destination_token_account_info = await token.get_account_info(destination_token_account)source_account = {key: str(value) if isinstance(value, Pubkey) else valuefor key, value in source_token_account_info._asdict().items()}destination_account = {key: str(value) if isinstance(value, Pubkey) else valuefor key, value in destination_token_account_info._asdict().items()}print("Mint Address:", mint.pubkey())print("\nSource Token Account Address:", source_token_account)print("Source Token Account:")print(json.dumps(source_account, indent=2))print("\nDestination Token Account Address:", destination_token_account)print("Destination Token Account:")print(json.dumps(destination_account, indent=2))print("\nTransaction Signature:", result.value)if __name__ == "__main__":asyncio.run(main())
Is this page helpful?