这里是新的 Solana Anchor 开发人员,我有一个关于当前如何将 Sol 发送到程序中的多个钱包的问题。 目前我使用下面的代码两次,然后调用两个单独的事务。
system_instruction::transfer(from_account.key, to_account.key, amount);
但是,我注意到 Rust 文档中有一个使用 vec 指令数组的“transfer_many”系统指令。
有人可以向我解释如何使用transfer_many 创建 1 条指令然后调用该指令吗? 该文档对我来说是胡言乱语,所以如果有人能用人性化的语言解释我将不胜感激。
下面是我将 sol 发送到多个地址的完整代码。 请忽略“feeaccount”,因为最终我将更改我的代码以发送程序帐户接受的 sol 的百分比。 (稍后,一旦我了解更多)
use anchor_lang::prelude::*;
use anchor_spl::token::{self, Token, TokenAccount, Transfer as SplTransfer};
use solana_program::system_instruction;
declare_id!("HBj3u9jbTigqXb47TAF2H44TAoTckVJnjzFc4jxusUN2");
#[derive(Accounts)]
pub struct TransferLamports<'info> {
#[account(mut)]
pub from: Signer<'info>,
#[account(mut)]
pub to: AccountInfo<'info>,
#[account(mut)]
pub feeto: AccountInfo<'info>,
pub system_program: Program<'info, System>,
}
#[program]
pub mod solana_lamport_transfer {
use super::*;
pub fn transfer_lamports(ctx: Context<TransferLamports>, amount: u64) -> Result<()> {
let from_account = &ctx.accounts.from;
let to_account = &ctx.accounts.to;
let fee_account = &ctx.accounts.feeto;
// Create the transfer instruction
let transfer_instruction1 =
system_instruction::transfer(from_account.key, to_account.key, amount);
// Create the transfer instruction
let transfer_instruction2 =
system_instruction::transfer(from_account.key, fee_account.key, amount);
// Invoke the transfer instruction
anchor_lang::solana_program::program::invoke_signed(
&transfer_instruction1,
&[
from_account.to_account_info(),
to_account.clone(),
ctx.accounts.system_program.to_account_info(),
],
&[],
)?;
// Invoke the transfer instruction
anchor_lang::solana_program::program::invoke_signed(
&transfer_instruction2,
&[
from_account.to_account_info(),
fee_account.clone(),
ctx.accounts.system_program.to_account_info(),
],
&[],
)?;
Ok(())
}
}
我的代码按照我编写的方式工作,但是,我在使用“transfer_many”片段时迷失了方向。 我写的代码没问题吗? 或者我会遇到问题吗? 我注意到我没有支付两次交易费用,因为它是在同一个调用中,所以也许我不需要使用transfer_many?
TLDR;你的代码没问题。
通过链上程序传输 Sol 需要对系统程序进行“跨程序调用”。这个本机程序有一组已定义的可能的指令,您可以向它提供这些指令,这些指令在此处的文档中定义为枚举。我们首先注意到的是,在 13 条可能的指令中,只有 2 条提到了转移:SystemInstruction::Transfer
和
SystemInstruction::TransferWithSeed
。没有可用的 TransferMany
说明。当我们深入研究 solana_program::system_instruction::transfer_many()
函数时,我们发现它返回一个
Vec<Instruction>
,而 transfer()
函数仅返回一个 Instruction
。如果你能在源代码中找到它的定义,你可以看到以下内容:
pub fn transfer_many(from_pubkey: &Pubkey, to_lamports: &[(Pubkey, u64)]) -> Vec<Instruction> {
to_lamports
.iter()
.map(|(to_pubkey, lamports)| transfer(from_pubkey, to_pubkey, *lamports))
.collect()
}
这个功能其实作用很少。
from_pubkey
、
to_pubkey
和lamports
作为参数(例如transfer()
函数),transfer_many()
采用一个from_pubkey
和元组切片,每个元组包含一个to_pubkey
和lamports
组合。对于每个元组,它调用常规 transfer()
方法来构造 Instruction
,然后将它们全部返回(作为 Vec
的 Instruction
)。现在,当您创建链上程序时,transfer_many()
几乎没有什么价值,因为跨程序调用只允许您指定一条指令。这与创建客户端程序(例如与 Solana 交互的链下软件)时不同,其中指令被捆绑到交易中。在这种情况下,使用
transfer_many()
是有意义的,因为您可以将一组指令捆绑到一个事务中。过去,solana-sdk
(用于客户端或链下开发)和
solana_program
组合了板条箱,因此这就是为什么您会看到一些“遗留”功能,这些功能在创建链上时毫无意义程序,但在构建某些客户端应用程序时非常合乎逻辑。上述文档中的示例实际上说明了这一点。 客户端示例使用transfer_many()
构造多个传输指令,并直接将生成的
Vec<Instruction>
放入新的Transaction
中。同一页上的程序示例在链上开发的背景下解释这个概念的效果很差,但最关键的是最后的 for 循环:
for instr in instrs {
invoke_signed(&instr, accounts, &[&[b"bank", &[bank_pda_bump_seed]]])?;
}
它实际上为
invoke_signed
中的每个
Instruction
分别调用 transfer_many()
。希望这能为您澄清一些点滴!