Μεταφορά 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 example
const rpc = createSolanaRpc("http://localhost:8899");
const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");
// Generate keypairs for fee payer (sender) and recipient
const 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 payer
await airdropFactory({ rpc, rpcSubscriptions })({
recipientAddress: feePayer.address,
lamports: lamports(1_000_000_000n),
commitment: "confirmed"
});
// Generate keypair to use as address of mint
const mint = await generateKeyPairSigner();
console.log("Mint Address:", mint.address.toString());
// Get default mint account size (in bytes), no extensions enabled
const space = BigInt(getMintSize());
// Get minimum balance for rent exemption
const rent = await rpc.getMinimumBalanceForRentExemption(space).send();
// Get latest blockhash to include in transaction
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
// Instruction to create new account for mint (token program)
// Invokes the system program
const createAccountInstruction = getCreateAccountInstruction({
payer: feePayer,
newAccount: mint,
lamports: rent,
space,
programAddress: TOKEN_PROGRAM_ADDRESS
});
// Instruction to initialize mint account data
// Invokes the token program
const initializeMintInstruction = getInitializeMintInstruction({
mint: mint.address,
decimals: 2,
mintAuthority: feePayer.address
});
// Derive the ATAs for sender and recipient
const [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 ATA
const createSenderAtaInstruction =
await getCreateAssociatedTokenInstructionAsync({
payer: feePayer,
mint: mint.address,
owner: feePayer.address
});
// Create instruction for recipient's ATA
const createRecipientAtaInstruction =
await getCreateAssociatedTokenInstructionAsync({
payer: feePayer,
mint: mint.address,
owner: recipient.address
});
// Create instruction to mint tokens to sender
const mintToInstruction = getMintToInstruction({
mint: mint.address,
token: senderAssociatedTokenAddress,
mintAuthority: feePayer.address,
amount: 100n
});
// Combine all instructions in order
const instructions = [
createAccountInstruction, // Create mint account
initializeMintInstruction, // Initialize mint
createSenderAtaInstruction, // Create sender's ATA
createRecipientAtaInstruction, // Create recipient's ATA
mintToInstruction // Mint tokens to sender
];
// Create transaction message
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(feePayer, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
(tx) => appendTransactionMessageInstructions(instructions, tx)
);
// Sign transaction message with all required signers
const signedTransaction =
await signTransactionMessageWithSigners(transactionMessage);
// Send and confirm transaction
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(
signedTransaction,
{ commitment: "confirmed" }
);
// Get transaction signature
const transactionSignature = getSignatureFromTransaction(signedTransaction);
console.log("Transaction Signature:", transactionSignature);
console.log("Successfully minted 1.0 tokens");
// Get a fresh blockhash for the transfer transaction
const { value: transferBlockhash } = await rpc.getLatestBlockhash().send();
// Create instruction to transfer tokens
const transferInstruction = getTransferInstruction({
source: senderAssociatedTokenAddress,
destination: recipientAssociatedTokenAddress,
authority: feePayer.address,
amount: 50n // 0.50 tokens with 2 decimals
});
// Create transaction message for token transfer
const transferTxMessage = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(feePayer, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(transferBlockhash, tx),
(tx) => appendTransactionMessageInstructions([transferInstruction], tx)
);
// Sign transaction message with all required signers
const signedTransferTx =
await signTransactionMessageWithSigners(transferTxMessage);
// Send and confirm transaction
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(
signedTransferTx,
{ commitment: "confirmed" }
);
// Get transaction signature
const 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 validator
let 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 payer
let fee_payer = Keypair::new();
// Generate a second keypair for the token recipient
let recipient = Keypair::new();
// Airdrop 1 SOL to fee payer
let 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 exemption
let 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 mint
let mint = Keypair::new();
// Get default mint account size (in bytes), no extensions enabled
let 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, // lamports
mint_space as u64, // space
&token_program_id(), // program id
);
// Instruction to initialize mint account data
let initialize_mint_instruction = initialize_mint(
&token_program_id(),
&mint.pubkey(), // mint
&fee_payer.pubkey(), // mint authority
Some(&fee_payer.pubkey()), // freeze authority
2, // decimals
)?;
// Calculate the associated token account address for fee_payer
let 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_payer
let 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 recipient
let 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 recipient
let 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 account
let mint_to_instruction = mint_to(
&token_program_id(),
&mint.pubkey(), // mint
&source_token_address, // destination
&fee_payer.pubkey(), // authority
&[&fee_payer.pubkey()], // signer
amount, // amount
)?;
// Create transaction and add instructions
let 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 transaction
let 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 transaction
let 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 destination
let 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()], // signers
transfer_amount, // amount
2, // decimals
)?;
// Create transaction for transferring tokens
let transaction = Transaction::new_signed_with_payer(
&[transfer_instruction],
Some(&fee_payer.pubkey()),
&[&fee_payer],
latestBlockhash,
);
// Send and confirm transaction
let 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 transfer
let 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?

Πίνακας Περιεχομένων

Επεξεργασία Σελίδας