10个版本 (重大更改)

0.7.0 2024年6月25日
0.6.3 2024年3月28日
0.4.1 2023年12月11日
0.3.0 2023年9月26日
0.1.0 2023年6月27日

#66 in #transfer

Download history 32423/week @ 2024-05-03 32518/week @ 2024-05-10 29990/week @ 2024-05-17 29682/week @ 2024-05-24 35558/week @ 2024-05-31 35493/week @ 2024-06-07 35762/week @ 2024-06-14 35406/week @ 2024-06-21 33372/week @ 2024-06-28 33092/week @ 2024-07-05 31641/week @ 2024-07-12 36117/week @ 2024-07-19 39916/week @ 2024-07-26 56421/week @ 2024-08-02 45329/week @ 2024-08-09 32581/week @ 2024-08-16

181,769 每月下载量
451 个crate中使用(4直接使用)

Apache-2.0

285KB
5.5K SLoC

转账钩子接口

示例程序

以下是一个示例程序,它仅实现了所需的“执行”指令,假设适当的账户数据已经写入接口定义的适当程序导出的地址。

use {
    solana_program::{entrypoint::ProgramResult, program_error::ProgramError},
    spl_tlv_account_resolution::state::ExtraAccountMetaList,
    spl_transfer_hook_interface::instruction::{ExecuteInstruction, TransferHookInstruction},
    spl_type_length_value::state::TlvStateBorrowed,
};
pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    input: &[u8],
) -> ProgramResult {
    let instruction = TransferHookInstruction::unpack(input)?;
    let _amount = match instruction {
        TransferHookInstruction::Execute { amount } => amount,
        _ => return Err(ProgramError::InvalidInstructionData),
    };
    let account_info_iter = &mut accounts.iter();

    // Pull out the accounts in order, none are validated in this test program
    let _source_account_info = next_account_info(account_info_iter)?;
    let mint_info = next_account_info(account_info_iter)?;
    let _destination_account_info = next_account_info(account_info_iter)?;
    let _authority_info = next_account_info(account_info_iter)?;
    let extra_account_metas_info = next_account_info(account_info_iter)?;

    // Only check that the correct pda and account are provided
    let expected_validation_address = get_extra_account_metas_address(mint_info.key, program_id);
    if expected_validation_address != *extra_account_metas_info.key {
        return Err(ProgramError::InvalidSeeds);
    }

    // Load the extra required accounts from the validation account
    let data = extra_account_metas_info.try_borrow_data()?;

    // Check the provided accounts against the validation data
    ExtraAccountMetaList::check_account_infos::<ExecuteInstruction>(
        accounts,
        &TransferHookInstruction::Execute { amount }.pack(),
        program_id,
        &data,
    )?;

    Ok(())
}

动机

代币创建者可能需要更多地控制其代币的转账方式。最突出的用例是NFT版税。每当代币被移动时,创作者应有权获得版税,但由于当前代币程序的设计,在协议级别阻止转账是不可能的。

目前的解决方案通常依赖于永久冻结代币,这需要一个完整的代理层来与代币交互。钱包和市场需要了解代理层才能正确使用代币。

更糟糕的是,不同的版税系统有不同的代理层来使用它们的代币。总的来说,这些系统损害了可组合性,使得开发变得更加困难。

解决方案

为了改善这种情况,Token-2022引入了转账钩子接口和扩展的概念。代币创建者必须开发和部署一个实现接口的程序,然后配置他们的代币铸造以使用他们的程序。

在转账过程中,Token-2022调用程序,并将在该铸造和程序ID下定义的已定义程序导出地址中指定的账户传递给程序。这个调用发生在所有其他转账逻辑之后,因此账户反映了转账的最终状态。

如何使用

开发者必须实现 Execute 指令,以及可选地实现 InitializeExtraAccountMetaList 指令,以便将所需的额外账户公钥写入铸币和程序ID定义的程序生成的地址。

注意:在指令描述符中实现 InitializeExtraAccountMetaList 并非技术要求。您的程序可以实现多个接口,因此程序中的任何其他指令都可以在程序生成的地址上创建账户!

当您的程序在定义良好的程序生成的地址中存储额外所需账户的配置时,可以发送一个指令(如 Execute(转账))到您的程序,仅使用接口指令所需的账户,所有额外所需的账户都将自动解析!

账户解析

鼓励实现转账钩子接口的开发者使用 spl-tlv-account-resolution 库来管理他们的转账钩子程序所需的额外账户。

TLV 账户解析能够在调用需要额外账户的指令时启动链上账户解析。有关账户解析如何工作的更多信息,请参阅存储库的 README 文件

示例

您创建了一个 DAO 来管理一个社区。您的 DAO 的权限是多签账户,您想确保您的代币的任何转账都得到 DAO 的批准。您还想要确保打算转账您代币的人有适当的权限。

让我们假设 DAO 多签有一个 固定地址。并且假设为了获得 can_transfer 权限,用户必须通过以下种子将此 动态程序生成的地址 与他们的钱包相关联: "can_transfer" + <wallet_address>

使用转账钩子接口,您可以将这些配置存储在您的铸币和程序ID定义的预定义程序生成的地址中。

当用户尝试转账您的代币时,他们可能会提供给 Token-2022

[source, mint, destination, owner/delegate]

然后 Token-2022 将调用您的程序,从您存储的配置中自动解析额外的所需账户,以便向您的程序提供以下账户

[source, mint, destination, owner/delegate, dao_authority, can_transfer_pda]

实用工具

spl-transfer-hook-interface 库为解析额外所需账户提供离链和链上辅助工具。有关链上使用的用法,请参阅 onchain.rs,有关使用任何异步离链客户端(如 BanksClientRpcClient)获取额外所需账户元数据的用法,请参阅 offchain.rs

依赖关系

~16–25MB
~339K SLoC