Solana/在主网发行您的代币/由程序控制的代币
空投就像是给大家发糖果, 可是, 要实现一个自动发糖的合约(我们这里指的是空投合约), 首先必须确保合约有足够的糖果库存. 这就像是, 你想在派对上分发糖果, 首先得保证自己手里有糖果!
在 solana 上, 代币不会直接存储在钱包或程序里, 而是通过关联代币账户来管理. 由程序控制的代币也需要通过关联代币账户来管理和转移.
代币转账流程
我们再来复习一下关联代币账户. 代币的转账并不是直接发生在用户的钱包和接收账户之间, 而是通过关联代币账户来完成的. 你可以把它想象成你大钱包里的一个小专用钱包盒, 每个小钱包盒都对应一种代币.
代币转账是打开您的大钱包后, 再打开您的小钱包, 然后发送到另一个用户的小钱包里.
通常来讲, 要实现由程序控制的代币这个功能, 需要有以下三个账户层级.
- 程序账户. 这儿的程序账户是就是我们的空投程序, 控制着代币的所有权. 它负责分配和转移代币. 程序账户通过执行 invoke 或 invoke_signed 指令来与其他账户交互.
- 程序 pda 账户. 程序账户通常不能直接拥有代币, 程序账户可以通过派生一个 pda 账户来存储代币. 这个 pda 账户是通过程序地址和特定的种子生成的. 派生账户的签名权限是由程序账户通过
invoke_signed
来控制的. - 关联代币账户. 实际存储代余额的账户. 关联代币账户由程序的 pda 账户派生而来.
简单来说, 账户之间的关系: 程序账户 -> 程序 pda 账户 -> 关联代币账户.
真正拥有代币所有权的是程序 pda 账户, 但得以于 pda 账户的特性, 程序账户可以代替其 pda 账户签名, 因此程序账户也就变相拥有了代币的所有权.
工作原理详解
在 solana 中, 程序账户通过签名来控制 pda 账户, 使得程序能够代替 pda 账户进行代币管理. 这是由于 pda 账户本身没有私钥, 它的签名操作只能通过与程序账户相关的签名种子来完成.
假设你有一个程序, 它需要把代币转给用户. 那么过程如下.
- 程序账户通过
invoke_signed
指令向 pda 账户发起转账请求. - pda 账户存储着代币, 程序通过签名种子签署转账, 完成从 pda 账户到用户关联代币账户的代币转移.
核心代码示例:
let account_seed = &[];
let account_bump = solana_program::pubkey::Pubkey::find_program_address(&[account_seed], account_mana.key).1;
solana_program::program::invoke_signed(
&spl_token_2022::instruction::transfer_checked(
&account_spl.key,
&account_mana_spla.key,
&account_mint.key,
&account_user_spla.key,
&account_mana_auth.key,
&[],
5000000000,
9,
)?,
accounts,
&[&[account_seed, &[account_bump]]],
)?;