64 个稳定版本
4.1.2 | 2024 年 3 月 7 日 |
---|---|
4.0.1 | 2024 年 1 月 31 日 |
3.3.0 |
|
3.2.3 | 2023 年 11 月 28 日 |
1.2.5 | 2022 年 2 月 24 日 |
#1453 在 魔法豆
45,734 每月下载量
用于 128 个 crate (91 个直接使用)
3MB
67K SLoC
Metaplex Token Metadata SDK
Rust 库,用于与 Metaplex Token Metadata 程序交互。
为什么使用客户端库(SDK)?
将程序 crate 作为依赖项有其局限性。最主要的是,您将绑定到该程序的相同依赖项,这些依赖项往往相当多。在许多情况下,这会导致在尝试更新 crate 版本时出现(不必要的)依赖项问题。其次,程序 crate 是从程序源代码生成的,其主要目的是提供程序的功能,而不一定是 友好 的客户端 API。
引入 SDK crate:最少的依赖项,有用的辅助工具。通过自动生成包含所有 accounts
、types
、instructions
和 errors
的客户端 SDK,我们可以显著减少依赖项的数量。可以通过添加(手动编写的)辅助工具来改进自动生成的代码。
尽管 SDK crate 有 5 个依赖项,但实际上唯一的“真实”依赖项是 solana-program
crate,因为其余依赖项也是 solana-program
的依赖项。
入门
从您的项目文件夹
cargo add mpl-token-metadata
注意 如果您正在使用
solana-program
版本早于1.16
,首先将solana-program
依赖项添加到您的项目中,然后添加mpl-token-metadata
。这将确保您只有一个borsh
crate 的副本。
结构
客户端 SDK 被分为几个模块
accounts
:表示程序账户的结构体errors
:表示程序错误的枚举instructions
:用于创建指令、指令参数和CPI指令的结构体types
:表示程序使用的类型的结构体
指令构建器
客户端SDK的主要功能之一是简化指令的创建。自动生成两种“类型”的指令构建器——两者都支持通过名称和可选位置传递账户
客户端指令构建器
这些是为离链客户端代码使用的。每个指令都由相应的结构体表示——例如,CreateV1
pub struct CreateV1 {
/// Unallocated metadata account with address as pda of ['metadata', program id, mint id]
pub metadata: solana_program::pubkey::Pubkey,
/// Unallocated edition account with address as pda of ['metadata', program id, mint, 'edition']
pub master_edition: Option<solana_program::pubkey::Pubkey>,
/// Mint of token asset
pub mint: (solana_program::pubkey::Pubkey, bool),
/// Mint authority
pub authority: solana_program::pubkey::Pubkey,
/// Payer
pub payer: solana_program::pubkey::Pubkey,
/// Update authority for the metadata account
pub update_authority: (solana_program::pubkey::Pubkey, bool),
/// System program
pub system_program: solana_program::pubkey::Pubkey,
/// Instructions sysvar account
pub sysvar_instructions: solana_program::pubkey::Pubkey,
/// SPL Token program
pub spl_token_program: solana_program::pubkey::Pubkey,
}
填写指令账户字段后,您可以使用 instruction(...)
方法生成相应的 solana_program::instruction::Instruction
// instruction args
let args = CreateV1InstructionArgs {
name: String::from("pNFT"),
symbol: String::from(""),
uri: String::from("http://my.pnft"),
seller_fee_basis_points: 500,
primary_sale_happened: false,
is_mutable: true,
token_standard: TokenStandard::ProgrammableNonFungible,
collection: None,
uses: None,
collection_details: None,
creators: None,
rule_set: None,
decimals: Some(0),
print_supply: Some(PrintSupply::Zero),
};
// instruction accounts
let create_ix = CreateV1 {
metadata,
master_edition: Some(master_edition),
mint: (mint_pubkey, true),
authority: payer_pubkey,
payer: payer_pubkey,
update_authority: (payer_pubkey, true),
system_program: system_program::ID,
sysvar_instructions: solana_program::sysvar::instructions::ID,
spl_token_program: spl_token::ID,
};
// creates the instruction
let create_ix = create_ix.instruction(args);
或者,您可以使用 CreateV1Builder
创建适当的指令
let create_ix = CreateV1Builder::new()
.metadata(metadata)
.master_edition(Some(master_edition))
.mint(mint_pubkey, true)
.authority(payer_pubkey)
.payer(payer_pubkey)
.update_authority(payer_pubkey, true)
.is_mutable(true)
.primary_sale_happened(false)
.name(String::from("pNFT"))
.uri(String::from("http://my.pnft"))
.seller_fee_basis_points(500)
.token_standard(TokenStandard::ProgrammableNonFungible)
.print_supply(PrintSupply::Zero)
.instruction();
CPI 指令构建器
这些是为链上代码使用的构建器,它们将CPI到Token Metadata。与“离链”构建器类似,每个指令都有一个结构体来调用CPI指令——例如,TransferV1Cpi
pub struct TransferV1Cpi<'a> {
/// The program to invoke.
pub __program: &'a solana_program::account_info::AccountInfo<'a>,
/// Token account
pub token: &'a solana_program::account_info::AccountInfo<'a>,
/// Token account owner
pub token_owner: &'a solana_program::account_info::AccountInfo<'a>,
/// Destination token account
pub destination_token: &'a solana_program::account_info::AccountInfo<'a>,
/// Destination token account owner
pub destination_owner: &'a solana_program::account_info::AccountInfo<'a>,
/// Mint of token asset
pub mint: &'a solana_program::account_info::AccountInfo<'a>,
/// Metadata (pda of ['metadata', program id, mint id])
pub metadata: &'a solana_program::account_info::AccountInfo<'a>,
/// Edition of token asset
pub edition: Option<&'a solana_program::account_info::AccountInfo<'a>>,
/// Owner token record account
pub token_record: Option<&'a solana_program::account_info::AccountInfo<'a>>,
/// Destination token record account
pub destination_token_record: Option<&'a solana_program::account_info::AccountInfo<'a>>,
/// Transfer authority (token owner or delegate)
pub authority: &'a solana_program::account_info::AccountInfo<'a>,
/// Payer
pub payer: &'a solana_program::account_info::AccountInfo<'a>,
/// System Program
pub system_program: &'a solana_program::account_info::AccountInfo<'a>,
/// Instructions sysvar account
pub sysvar_instructions: &'a solana_program::account_info::AccountInfo<'a>,
/// SPL Token Program
pub spl_token_program: &'a solana_program::account_info::AccountInfo<'a>,
/// SPL Associated Token Account program
pub spl_ata_program: &'a solana_program::account_info::AccountInfo<'a>,
/// Token Authorization Rules Program
pub authorization_rules_program: Option<&'a solana_program::account_info::AccountInfo<'a>>,
/// Token Authorization Rules account
pub authorization_rules: Option<&'a solana_program::account_info::AccountInfo<'a>>,
/// The arguments for the instruction.
pub __args: TransferV1InstructionArgs,
}
填写程序、指令账户和参数字段后,您可以使用 invoke()
或 invoke_signed(...)
方法执行CPI
// instruction args
let mut args = TransferV1InstructionArgs {
amount,
authorization_data: None,
};
// instruction accounts
let cpi_transfer = TransferV1Cpi::new(
metadata_program_info,
TransferV1CpiAccounts {
token: owner_token_info,
token_owner: owner_info,
destination_token: destination_token_info,
destination_owner: destination_info,
mint: mint_info,
metadata: metadata_info,
authority: vault_info,
payer: payer_info,
system_program: system_program_info,
sysvar_instructions: sysvar_instructions_info,
spl_token_program: spl_token_program_info,
spl_ata_program: spl_ata_program_info,
edition: edition_info,
token_record: None,
destination_token_record: None,
authorization_rules: None,
authorization_rules_program: None,
},
args,
);
// performs the CPI
cpi_transfer.invoke_signed(&[&signer_seeds])
您还可以使用 TransferV1CpiBuilder
简化流程
let cpi_transfer = TransferV1CpiBuilder::new(metadata_program_info)
.token(owner_token_info)
.token_owner(owner_info)
.destination_token(destination_token_info)
.destination_owner(destination_info)
.mint(mint_info)
.metadata(metadata_info)
.edition(edition_info)
.authority(vault_info)
.payer(payer_info)
.system_program(system_program_info)
.sysvar_instructions(sysvar_instructions_info)
.spl_token_program(spl_token_program_info)
.spl_ata_program(spl_ata_program_info)
.amount(amount);
// performs the CPI
cpi_transfer.invoke_signed(&[&signer_seeds])
注意 >
*Builder
提供了一种简化创建所需结构体的方法,因为它们利用了在Kinobi配置上设置的任何默认值,并且不需要为可选字段设置None
值。
PDA助手
账户类型(例如,Metadata
)有相关函数来查找PDA或创建PDA Pubkey
impl Metadata {
pub fn find_pda(mint: Pubkey) -> (solana_program::pubkey::Pubkey, u8) {
solana_program::pubkey::Pubkey::find_program_address(
&[
"metadata".as_bytes(),
crate::MPL_TOKEN_METADATA_ID.as_ref(),
mint.as_ref(),
],
&crate::MPL_TOKEN_METADATA_ID,
)
}
pub fn create_pda(
mint: Pubkey,
bump: u8,
) -> Result<solana_program::pubkey::Pubkey, solana_program::pubkey::PubkeyError> {
solana_program::pubkey::Pubkey::create_program_address(
&[
"metadata".as_bytes(),
crate::MPL_TOKEN_METADATA_ID.as_ref(),
mint.as_ref(),
&[bump],
],
&crate::MPL_TOKEN_METADATA_ID,
)
}
}
如果已知bump种子,使用
create_pda
函数更便宜(在计算单位方面),特别是对于链上代码。
测试
要运行SDK测试,请从存储库的根目录运行以下命令
pnpm install
然后
pnpm clients:rust:test
文档
crate文档可以在 这里 找到。
依赖关系
~16–25MB
~423K SLoC