Memo-overdracht
Hoe de MemoTransferExtension in te schakelen
De
MemoTransferExtension
vereist dat alle inkomende token-overdrachten vergezeld gaan van een memo
wanneer deze is ingeschakeld op een token account. Deze extensie kan worden in-
of uitgeschakeld door de eigenaar van het token account.
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 {getInitializeMintInstruction,getMintSize,TOKEN_2022_PROGRAM_ADDRESS,extension,getTokenSize,findAssociatedTokenPda,getCreateAssociatedTokenInstructionAsync,getEnableMemoTransfersInstruction,getInitializeAccountInstruction,getMintToInstruction,getTransferCheckedInstruction} from "@solana-program/token-2022";import { getAddMemoInstruction } from "@solana-program/memo";// Create Connection, local validator in this exampleconst rpc = createSolanaRpc("http://localhost:8899");const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");// Generate the authority for the mint, (will also act as the fee payer)const authority = await generateKeyPairSigner();// Fund authority/fee payerawait airdropFactory({ rpc, rpcSubscriptions })({recipientAddress: authority.address,lamports: lamports(5_000_000_000n), // 5 SOLcommitment: "confirmed"});// Generate keypair to use as address of mintconst mint = await generateKeyPairSigner();// Get default mint account size (in bytes),const 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 createMintAccountInstruction = getCreateAccountInstruction({payer: authority,newAccount: mint,lamports: rent,space,programAddress: TOKEN_2022_PROGRAM_ADDRESS});// Instruction to initialize mint account data// Invokes the token22 programconst initializeMintInstruction = getInitializeMintInstruction({mint: mint.address,decimals: 9,mintAuthority: authority.address});// Use findAssociatedTokenPda to derive the ATA addressconst [associatedTokenAddress] = await findAssociatedTokenPda({mint: mint.address,owner: authority.address,tokenProgram: TOKEN_2022_PROGRAM_ADDRESS});// instruction to create the associated token account for the authorityconst createAtaInstruction = await getCreateAssociatedTokenInstructionAsync({payer: authority,mint: mint.address,owner: authority.address});// Create instruction to mint tokensconst mintToInstruction = getMintToInstruction({mint: mint.address,token: associatedTokenAddress,mintAuthority: authority.address,amount: 1000_000_000_000n // 1000.0 tokens with 9 decimals});// Generate keypair to use as address of token accountconst tokenAccount = await generateKeyPairSigner();// memo transfer extension.const memoTransferExtension = extension("MemoTransfer", {requireIncomingTransferMemos: true});// get token account size with extension enabledconst tokenAccountLen = BigInt(getTokenSize([memoTransferExtension]));// Get minimum balance for rent exemptionconst tokenAccountRent = await rpc.getMinimumBalanceForRentExemption(tokenAccountLen).send();// Instruction to create new account for the token account// Invokes the system programconst createTokenAccountInstruction = getCreateAccountInstruction({payer: authority,newAccount: tokenAccount,lamports: tokenAccountRent,space: tokenAccountLen,programAddress: TOKEN_2022_PROGRAM_ADDRESS});// Instruction to initialize the created token accountconst initializeTokenAccountInstruction = getInitializeAccountInstruction({account: tokenAccount.address,mint: mint.address,owner: authority.address});// create instruction to enable the MemoTransferExtensionconst enableMemoTransferExtensionInstruction =getEnableMemoTransfersInstruction({token: tokenAccount.address,owner: authority});const instructions = [createMintAccountInstruction,initializeMintInstruction,createAtaInstruction,mintToInstruction,createTokenAccountInstruction,initializeTokenAccountInstruction,enableMemoTransferExtensionInstruction];// Create transaction messageconst transactionMessage = pipe(createTransactionMessage({ version: 0 }),(tx) => setTransactionMessageFeePayerSigner(authority, 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", skipPreflight: true });// // Get transaction signatureconst transactionSignature = getSignatureFromTransaction(signedTransaction);console.log("Mint Address:", mint.address.toString());console.log("Transaction Signature:", transactionSignature);// Get a fresh blockhash for the transfer with memo enabledconst { value: latestBlockhash2 } = await rpc.getLatestBlockhash().send();// construct memo instructionconst transferMemoInstruction = getAddMemoInstruction({memo: "This transfer requires a memo to accompany it"});// create transfer insructionconst transferInstruction = getTransferCheckedInstruction({source: associatedTokenAddress,mint: mint.address,destination: tokenAccount.address,authority: authority,amount: 1_000_000_000,decimals: 9});// construct transaction message for transferconst transferMessage = pipe(createTransactionMessage({ version: 0 }),(tx) => setTransactionMessageFeePayerSigner(authority, tx),(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash2, tx),(tx) =>appendTransactionMessageInstructions([transferMemoInstruction, transferInstruction],tx));// Sign transaction message with all required signersconst signedTransferTx =await signTransactionMessageWithSigners(transferMessage);// Send and confirm transactionawait sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransferTx,{ commitment: "confirmed" });// Get transaction signatureconst transferTxSig = getSignatureFromTransaction(signedTransferTx);console.log("\nTransferred tokens with memo ix enabled");console.log("Transaction Signature:", transferTxSig);
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_memo::build_memo;use spl_token_2022::{ID as TOKEN_2022_PROGRAM_ID,extension::{ExtensionType, memo_transfer::instruction::enable_required_transfer_memos},instruction::{initialize_account, initialize_mint, mint_to, transfer_checked},state::{Account, 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 latest_blockhash = client.get_latest_blockhash().await?;// Generate a new keypair for the fee payerlet fee_payer = Keypair::new();// Airdrop 5 SOL to fee payerlet airdrop_signature = client.request_airdrop(&fee_payer.pubkey(), 5_000_000_000).await?;client.confirm_transaction(&airdrop_signature).await?;loop {let confirmed = client.confirm_transaction(&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 (token22)let create_mint_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, // program id&mint.pubkey(), // mint&fee_payer.pubkey(), // mint authoritySome(&fee_payer.pubkey()), // freeze authority9, // decimals)?;// Calculate the associated token account address for fee_payerlet associated_token_address = 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);// Amount of tokens to mint (1000 tokens with 9 decimals)let amount = 1000_000_000_000;// Create mint_to instruction to mint tokens to the associated token accountlet mint_to_instruction = mint_to(&TOKEN_2022_PROGRAM_ID, // program_id&mint.pubkey(), // mint&associated_token_address, // destination&fee_payer.pubkey(), // authority&[&fee_payer.pubkey()], // signeramount, // amount)?;// Generate keypair to use as address of token accountlet token_account = Keypair::new();// Get default token account size (in bytes), with memo transfer extension enabledlet token_account_space =ExtensionType::try_calculate_account_len::<Account>(&[ExtensionType::MemoTransfer])?;let token_account_rent = client.get_minimum_balance_for_rent_exemption(token_account_space).await?;// Instruction to create new account for token account (token22)let create_token_account_instruction = create_account(&fee_payer.pubkey(), // payer&token_account.pubkey(), // new account (token account)token_account_rent, // renttoken_account_space as u64, // space&TOKEN_2022_PROGRAM_ID, // program id);// initialize token accountlet initialize_token_account = initialize_account(&TOKEN_2022_PROGRAM_ID, // program_id&token_account.pubkey(), // token account&mint.pubkey(), // mint&fee_payer.pubkey(), // authority)?;// enable memo transfer extensionlet enable_memo_transfer_instruction = enable_required_transfer_memos(&TOKEN_2022_PROGRAM_ID, // program_id&token_account.pubkey(), // token account&fee_payer.pubkey(), // authority&[&fee_payer.pubkey()], // authority)?;// Construct transaction with previous instructionslet transaction = Transaction::new_signed_with_payer(&[create_mint_account_instruction,initialize_mint_instruction,create_ata_instruction,mint_to_instruction,create_token_account_instruction,initialize_token_account,enable_memo_transfer_instruction,],Some(&fee_payer.pubkey()),&[&fee_payer, &mint, &token_account],latest_blockhash,);// Send and confirm transactionlet transaction_signature = client.send_and_confirm_transaction(&transaction).await?;println!("Mint Address: {}", mint.pubkey());println!("Associated Token Account Address: {}",associated_token_address);println!("token account with memo transfer enabled: {}",token_account.pubkey());println!("\nSuccessfully enabled memo transfer extension on token account");println!("Transaction Signature: {}", transaction_signature);// Get the latest blockhash for the approve transactionlet latest_blockhash = client.get_latest_blockhash().await?;// Create transfer_checked instruction to send tokens from source to destinationlet transfer_instruction = transfer_checked(&TOKEN_2022_PROGRAM_ID, // program id&associated_token_address, // source&mint.pubkey(), // mint&token_account.pubkey(), // destination&fee_payer.pubkey(), // owner of source&[&fee_payer.pubkey()], // signers1_000_000_000, // amount9, // decimals)?;let memo = String::from("This transfer requires a memo to accompany it");let memo_instruction = build_memo(memo.as_bytes(), &[&fee_payer.pubkey()]);// Create transaction for approving delegatelet transaction = Transaction::new_signed_with_payer(&[memo_instruction, transfer_instruction],Some(&fee_payer.pubkey()),&[&fee_payer],latest_blockhash,);// Send and confirm transactionlet transaction_signature = client.send_and_confirm_transaction(&transaction).await?;println!("\nSuccessfully transferred tokens with memo transfer extension enabled");println!("Transaction Signature: {}", transaction_signature);Ok(())}
Console
Click to execute the code.
Is this page helpful?