Jacky Gu

Solana开发笔记: Token2022 - 为什么Transfer fee更改后要等2个Epoch?

01 Jan 2025 Share to

为什么Transfer fee更改后要等2个Epoch?

为了防止更改Transfer fee费率被随意更改,Solana规定每次更改Transfer fee后,必须等待2个Epoch才能生效。

代码见:https://github.com/solana-program/token-2022/blob/6ae924718a5a4b0a35a25795f6d581d8310559a4/program/src/extension/transfer_fee/processor.rs#L103

fn process_set_transfer_fee(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    transfer_fee_basis_points: u16,
    maximum_fee: u64,
) -> ProgramResult {
    let account_info_iter = &mut accounts.iter();
    let mint_account_info = next_account_info(account_info_iter)?;
    let authority_info = next_account_info(account_info_iter)?;
    let authority_info_data_len = authority_info.data_len();

    let mut mint_data = mint_account_info.data.borrow_mut();
    let mut mint = PodStateWithExtensionsMut::<PodMint>::unpack(&mut mint_data)?;
    let extension = mint.get_extension_mut::<TransferFeeConfig>()?;

    let transfer_fee_config_authority =
        Option::<Pubkey>::from(extension.transfer_fee_config_authority)
            .ok_or(TokenError::NoAuthorityExists)?;
    Processor::validate_owner(
        program_id,
        &transfer_fee_config_authority,
        authority_info,
        authority_info_data_len,
        account_info_iter.as_slice(),
    )?;

    if transfer_fee_basis_points > MAX_FEE_BASIS_POINTS {
        return Err(TokenError::TransferFeeExceedsMaximum.into());
    }

    // When setting the transfer fee, we have two situations:
    // * newer transfer fee epoch <= current epoch: newer transfer fee is the active
    //   one, so overwrite older transfer fee with newer, then overwrite newer
    //   transfer fee
    // * newer transfer fee epoch >= next epoch: it was never used, so just
    //   overwrite next transfer fee
    let epoch = Clock::get()?.epoch;
    if u64::from(extension.newer_transfer_fee.epoch) <= epoch {
        extension.older_transfer_fee = extension.newer_transfer_fee;
    }
    // set two epochs ahead to avoid rug pulls at the end of an epoch
    let newer_fee_start_epoch = epoch.saturating_add(2);                <--- 2 epochs ahead
    let transfer_fee = TransferFee {
        epoch: newer_fee_start_epoch.into(),
        transfer_fee_basis_points: transfer_fee_basis_points.into(),
        maximum_fee: maximum_fee.into(),
    };
    extension.newer_transfer_fee = transfer_fee;

    Ok(())
}