Anchor
Token2022 với Anchor

Token2022 với Anchor

Memo Transfer Extension

MemoTranfer Extension là một Token account extension thực thi rằng tất cả transfer đến một token account phải bao gồm memo, tạo điều kiện cho việc theo dõi giao dịch nâng cao và nhận dạng người dùng.

Khởi tạo Token Account

Anchor không có bất kỳ macro nào cho phần mở rộng memo_transfer, chúng ta sẽ tạo Token account bằng cách sử dụng một CPI thô.

Đây là cách tạo token với phần mở rộng Memo Transfer:

use anchor_lang::prelude::*;
use anchor_lang::system_program::{create_account, CreateAccount};
use anchor_spl::{
    token_2022::{
        initialize_account3,
        spl_token_2022::{extension::ExtensionType, pod::PodAccount},
        InitializeAccount3,
    },
    token_interface::{memo_transfer_initialize, MemoTransfer, Mint, Token2022},
};
 
// There is currently not an anchor constraint to automatically initialize the MemoTransfer extension
// We can manually create and initialize the token account via CPIs in the instruction handler
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
    // Calculate space required for token and extension data
    let token_account_size =
        ExtensionType::try_calculate_account_len::<PodAccount>(&[ExtensionType::MemoTransfer])?;
 
    // Calculate minimum lamports required for size of token account with extensions
    let lamports = (Rent::get()?).minimum_balance(token_account_size);
 
    // Invoke System Program to create new account with space for token account and extension data
    create_account(
        CpiContext::new(
            ctx.accounts.system_program.to_account_info(),
            CreateAccount {
                from: ctx.accounts.payer.to_account_info(),
                to: ctx.accounts.token_account.to_account_info(),
            },
        ),
        lamports,                          // Lamports
        token_account_size as u64,         // Space
        &ctx.accounts.token_program.key(), // Owner Program
    )?;
 
    // Initialize the standard token account data
    initialize_account3(CpiContext::new(
        ctx.accounts.token_program.to_account_info(),
        InitializeAccount3 {
            account: ctx.accounts.token_account.to_account_info(),
            mint: ctx.accounts.mint_account.to_account_info(),
            authority: ctx.accounts.payer.to_account_info(),
        },
    ))?;
 
    // Initialize the memo transfer extension
    // This instruction must come after the token account initialization
    memo_transfer_initialize(CpiContext::new(
        ctx.accounts.token_program.to_account_info(),
        MemoTransfer {
            token_program_id: ctx.accounts.token_program.to_account_info(),
            account: ctx.accounts.token_account.to_account_info(),
            owner: ctx.accounts.payer.to_account_info(),
        },
    ))?;
 
    Ok(())
}
 
#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(mut)]
    pub payer: Signer<'info>,
 
    #[account(mut)]
    pub token_account: Signer<'info>,
    pub mint_account: InterfaceAccount<'info, Mint>,
    pub token_program: Program<'info, Token2022>,
    pub system_program: Program<'info, System>,
}

Transfer Token với Memo

Để sử dụng Memo program trên Solana, chúng ta có hai cách khả thi.

Xây dựng memo instruction "thô" của riêng chúng ta như thế này:

const message = "Hello, Solana";
 
new TransactionInstruction({
    keys: [{ pubkey: keypair.publicKey, isSigner: true, isWritable: true }],
    data: Buffer.from(message, "utf-8"), // Memo message. In this case it is "Hello, Solana"
    programId: new PublicKey("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"), // Memo program that validates keys and memo message
}),
 
Hoặc chúng ta có thể sử dụng Memo program SDK sau khi tải gói hỗ trợ như thế này:
 

npm i @solana/spl-memo


> Sau khi tạo memo, instruction tiếp theo sẽ là một instruction chuyển token đơn giản. 

Trong ví dụ của chúng ta, chúng ta sẽ sử dụng cách thứ hai và nó sẽ trông như thế này:

```ts
const memoInstruction = createMemoInstruction(
    "Hello, world!",
    [keypair.publicKey],
);

//...anchor instruction with the transfer instruction

const transferTransaction = new Transaction().add(
    memoInstruction,
    transferInstruction,
);

const transferSignature = await sendAndConfirmTransaction(connection, transferTransaction, [keypair]);

console.log(`Tokens transferred with memo! Check out your TX here: https://explorer.solana.com/tx/${transferSignature}?cluster=devnet`);

Vô hiệu hóa và kích hoạt Memo

Nếu chúng ta không muốn thực thi transfer phải đi kèm với memo, chúng ta có thể làm như vậy bằng cách sử dụng hàm memo_transfer_disable và nó sẽ trông như thế này:

use anchor_lang::prelude::*;
use anchor_spl::token_interface::{memo_transfer_disable, MemoTransfer, Token, Mint, Token2022};
 
#[derive(Accounts)]
pub struct DisableMemo<'info> {
    #[account(mut)]
    pub owner: Signer<'info>,
 
    #[account(
        mut,
        token::authority = owner,
    )]
    pub token_account: InterfaceAccount<'info, TokenAccount>,
    pub token_program: Program<'info, Token2022>,
}
 
pub fn disable_memo(
    ctx: Context<DisableMemo>,
) -> Result<()> {
    memo_transfer_disable(CpiContext::new(
        ctx.accounts.token_program.to_account_info(),
        MemoTransfer {
            token_program_id: ctx.accounts.token_program.to_account_info(),
            account: ctx.accounts.token_account.to_account_info(),
            owner: ctx.accounts.owner.to_account_info(),
        },
    ))?;
    
    Ok(())
}
Nội dung
Xem mã nguồn
Blueshift © 2025Commit: f7a03c2