3 个不稳定版本
0.4.1 | 2024年3月29日 |
---|---|
0.4.0 | 2023年12月24日 |
0.3.0 | 2023年11月21日 |
#158 在 神奇豆
每月557次 下载
用于 67 个crate(3个直接使用)
245KB
4K 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
(转账)——所有额外所需账户将自动解决!
账户解析
鼓励实现转账钩子接口的开发者使用 solarti-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]
工具
solarti-transfer-hook-interface
库提供了离链和链上助手,用于解决所需的其他账户。有关链上使用的说明,请参阅 invoke.rs,有关使用任何异步离链客户端(如 BanksClient 或
RpcClient
)获取所需的其他账户元数据的说明,请参阅 offchain.rs。
依赖关系
~21–30MB
~479K SLoC