Typescript
Token2022 з Web3.js

Token2022 з Web3.js

Розширення комісії за переказ

Розширення TransferFee є розширенням Mint, яке дозволяє творцю встановлювати "податок" на токен, який стягується щоразу, коли хтось виконує обмін.

Щоб переконатися, що отримувач комісії не отримує блокування запису щоразу, коли хтось виконує обмін, і щоб забезпечити можливість паралельного виконання транзакцій, що містять Mint з цим розширенням, комісія відкладається на рахунку токенів отримувача, з якого може зняти кошти лише Withdraw Authority.

Initializing the Mint Account

Щоб ініціалізувати розширення TransferFee на рахунку Mint, нам знадобиться функція createInitializeTransferFeeConfigInstruction().

Ось як створити емісію з розширенням комісії за переказ:

ts
import {
    Keypair,
    SystemProgram,
    Transaction,
    sendAndConfirmTransaction,
} from '@solana/web3.js';
import {
    createInitializeMintInstruction,
    createInitializeTransferFeeConfigInstruction,
    getMintLen,
    ExtensionType,
    TOKEN_2022_PROGRAM_ID,
} from '@solana/spl-token';
 
const mint = Keypair.generate();
 
// Calculate the size needed for a Mint account with Transfer Fee extension
const mintLen = getMintLen([ExtensionType.TransferFeeConfig]);
 
// Calculate minimum lamports required for rent exemption
const lamports = await connection.getMinimumBalanceForRentExemption(mintLen);
 
// Create the account with the correct size and owner
const createAccountInstruction = SystemProgram.createAccount({
    fromPubkey: keypair.publicKey,
    newAccountPubkey: mint.publicKey,
    space: mintLen,
    lamports,
    programId: TOKEN_2022_PROGRAM_ID,
});
 
// Initialize the Transfer Fee extension
const initializeTransferFeeConfig = createInitializeTransferFeeConfigInstruction(
    mint.publicKey,
    keypair.publicKey,
    keypair.publicKey,
    500,
    BigInt(1e6),
    TOKEN_2022_PROGRAM_ID,
);
 
// Initialize the mint itself
const initializeMintInstruction = createInitializeMintInstruction(
    mint.publicKey,
    6,
    keypair.publicKey,
    null,
    TOKEN_2022_PROGRAM_ID,
);
 
// Combine all instructions in the correct order
const transaction = new Transaction().add(
    createAccountInstruction,
    initializeTransferFeeConfig,
    initializeMintInstruction,
);
 
const signature = await sendAndConfirmTransaction(connection, transaction, [keypair, mint]);
 
console.log(`Mint created! Check out your TX here: https://explorer.solana.com/tx/${signature}?cluster=devnet`);

Transferring Tokens with the Fee

Для переказу токенів для Mint, які мають розширення TransferFee`, у нас є два шляхи:

  • Ми можемо використовувати звичайну інструкцію transferChecked(), і при цьому розрахунок комісії обробляється автоматично
  • Ми можемо використовувати інструкцію transferCheckedWithFee() і вказати вручну fee, яку ми збираємося сплатити при цьому переказі. Це дуже корисно, якщо ми хочемо переконатися, що не станемо жертвою "раг пулу", якщо власник змінить комісію і створить аномально високу комісію; це схоже на встановлення проковзування для переказу.

Навіть якщо власник змінить комісію, нова комісія стає активною через 2 епохи після встановлення

Ось як створити переказ за допомогою інструкції transferCheckedWithFee():

ts
createTransferCheckedWithFeeInstruction(
    sourceTokenAccount,
    mint.publicKey, 
    destinationTokenAccount, 
    keypair.publicKey, 
    BigInt(100e6), // transfer amount
    6, // decimals
    BigInt(1e6), // fee paid for the transfer
    undefined,
    TOKEN_2022_PROGRAM_ID,
)
 
const transaction = new Transaction().add(transferInstructions);
 
const signature = await sendAndConfirmTransaction(connection, transaction, [keypair]);
 
console.log(`Tokens transferred! Check out your TX here: https://explorer.solana.com/tx/${signature}?cluster=devnet`);

Harvesting the Fee

Як зазначено у вступі, комісія за переказ залишається на рахунку Token, який отримує токени, щоб уникнути блокування запису для рахунку Mint або sourceTokenAccount. З цієї причини, перш ніж мати можливість зняти комісію, нам потрібно буде знайти всі рахунки Token, які мають комісії для отримання.

Ми можемо зробити це, встановивши фільтр і отримавши всі рахунки, що належать до цього випуску, таким чином:

ts
// Retrieve all Token Accounts for the Mint Account
const allAccounts = await connection.getProgramAccounts(TOKEN_2022_PROGRAM_ID, {
    commitment: "confirmed",
    filters: [
        {
            memcmp: {
                offset: 0,
                bytes: mint.publicKey.toString(), // Mint Account address
            },
        },
    ],
});

І отримати список усіх рахунків Token, які мають комісію, розпакувавши рахунок Token і використовуючи функцію getTransferAmoun() таким чином:

ts
// List of Token Accounts to withdraw fees from
const accountsToWithdrawFrom: PublicKey[] = [];
 
for (const accountInfo of allAccounts) {
    const account = unpackAccount(
        accountInfo.pubkey,
        accountInfo.account,
        TOKEN_2022_PROGRAM_ID,
    );
 
    // Extract transfer fee data from each account
    const transferFeeAmount = getTransferFeeAmount(account);
 
    // Check if fees are available to be withdrawn
    if (transferFeeAmount !== null && transferFeeAmount.withheldAmount > 0) {
        accountsToWithdrawFrom.push(accountInfo.pubkey);
    }
}

Після цього ми можемо використати інструкцію withdrawWithheldTokensFromAccounts з Withdraw Authority, щоб передати список accountsToWithdrawFrom таким чином:

ts
const harvestInstructions = createWithdrawWithheldTokensFromAccountsInstruction(
    mint.publicKey,
    sourceTokenAccount,
    keypair.publicKey,
    [],
    accountsToWithdrawFrom,
    TOKEN_2022_PROGRAM_ID,
);
 
const transaction = new Transaction().add(harvestInstructions);
 
const signature = await sendAndConfirmTransaction(connection, transaction, [keypair]);
 
console.log(`Withheld tokens harvested! Check out your TX here: https://explorer.solana.com/tx/${signature}?cluster=devnet`);

Оновлення комісії

Після ініціалізації нашого Mint з розширенням TranferFee, нам може знадобитися оновити цю конкретну комісію в майбутньому. І щоб переконатися, що творець не "обманює" власників токенів за допомогою "приманки та підміни", встановлюючи дуже високу комісію щоразу, коли виконується переказ, нова TranferFee буде активована через 2 епохи.

Щоб врахувати це, ось як виглядають дані розширення TransferFee:

rust
pub struct TransferFeeConfig {
    pub transfer_fee_config_authority: Pubkey,
    pub withdraw_withheld_authority: Pubkey,
    pub withheld_amount: u64,
    pub older_transfer_fee: TransferFee,
    pub newer_transfer_fee: TransferFee,
}
 
pub struct TransferFee {
    pub epoch: u64,
    pub maximum_fee: u64,
    pub transfer_fee_basis_point: u16,
}

Отже, щоб змінити комісію, ми можемо використати інструкцію setTransferFee таким чином:

ts
const setTransferFeeInstruction = createSetTransferFeeInstruction(
    mint.publicKey
    keypaird.publicKey
    [],
    BigInt(1000), // new transfer fee
    BigInt(100e6), // new maximum fee amount
    TOKEN_2022_PROGRAM_ID,
)
 
const transaction = new Transaction().add(setTransferFeeInstruction);
 
const signature = await sendAndConfirmTransaction(connection, transaction, [keypair]);
 
console.log(`Withheld tokens harvested! Check out your TX here: https://explorer.solana.com/tx/${signature}?cluster=devnet`);
Blueshift © 2025Commit: 6d01265
Blueshift | Token2022 з Web3.js | Розширення комісії за переказ