什么是用于创建程序可用于执行合同付款的转账账户的 Solana 模式?

Posted

技术标签:

【中文标题】什么是用于创建程序可用于执行合同付款的转账账户的 Solana 模式?【英文标题】:What is the Solana pattern for creating a transfer account the program can use to execute a contract payment? 【发布时间】:2021-10-09 04:45:34 【问题描述】:

我正在尝试处理我的 solana 合同中的交易。我似乎应该这样做的方式是使用createAccountWithSeed 生成一个由程序(8DqELvN5TFeMtNJciUYvGqso2CyG5M6XNWxh3HRr3Vjv)和付款人拥有的转账账户。因此,我创建了新的转账账户以发送到 solana 程序处理器以执行交易。但是当我将转账账户传递给我的 Rust 程序时,check_account_owner 声明该账户归系统程序 (11111111111111111111111111111111) 而不是我的程序所有。

所以我的问题有两个:

在这种情况下使用的模式是否正确? 如果是,我如何创建一个程序和付款人都可以执行的帐户?

这是客户端中createAccountWithSeed 的 JS。

const transferAcc = await PublicKey.createWithSeed(
    payer.publicKey,
    "payer",
    PROGRAM_ID,
  );
  await connection.requestAirdrop(transferAcc, 100000);
  SystemProgram.createAccountWithSeed(
    basePubkey: payer.publicKey,
    fromPubkey: payer.publicKey,
    lamports: 100000,
    newAccountPubkey: transferAcc,
    programId: PROGRAM_ID,
    seed: "payer",
    space: 1024,
  );

  const accInfo = await connection.getAccountInfo(transferAcc);
  console.log(
    `Paying from acc: $transferAcc.toBase58(), Owned by: $accInfo?.owner.toBase58()`
  );

这是尝试进行转移的 Rust 代码。

pub fn process_payment(
        program_id: &Pubkey,
        accounts: &[AccountInfo],
        payment_fee: u64,
    ) -> ProgramResult 
        let account_info_iter = &mut accounts.iter();
        let token_program = next_account_info(account_info_iter)?;
        let payer_acc = next_account_info(account_info_iter)?;
        let transfer_acc = next_account_info(account_info_iter)?;
        let receiver_acc = next_account_info(account_info_iter)?;

        if !payer_acc.is_signer 
            return Err(ProgramError::MissingRequiredSignature);
        

        if *token_program.key != id() 
            return Err(SosolError::IncorrectTokenProgramId.into());
        

        check_account_owner(payer_payment_acc, &program_id)?;

        msg!("Calling the token program to transfer tokens to the receiver...");
        token_transfer(
            token_program.clone(),
            transfer_acc.clone(),
            receiver_account_key.clone(),
            payer_acc.clone(),
            payment_fee,
        )?;

        Ok(())
    

/// Issue a spl_token `Transfer` instruction.
#[allow(clippy::too_many_arguments)]
fn token_transfer<'a>(
    token_program: AccountInfo<'a>,
    source: AccountInfo<'a>,
    destination: AccountInfo<'a>,
    authority: AccountInfo<'a>,
    amount: u64,
) -> Result<(), ProgramError> 
    let ix = transfer(
        token_program.key,
        source.key,
        destination.key,
        authority.key,
        &[],
        amount,
    )?;
    invoke(&ix, &[source, destination, authority, token_program])

错误日志状态:

    Program log: Expected account to be owned by program 8DqELvN5TFeMtNJciUYvGqso2CyG5M6XNWxh3HRr3Vjv, received 11111111111111111111111111111111
    Program log: CUSTOM-ERROR: The account did not have the expected program id

【问题讨论】:

【参考方案1】:

好的,所以转账账户归系统程序而不是我的程序所有的原因是因为我在交易之外创建了账户。关键是将createAccountWithSeed(或者实际上只是createAccount,因为我实际上想要为每笔交易创建一个新帐户)方法添加到您的交易链中,如下所示:

  const transaction = new Transaction();
  const transferAcc = new Keypair();
  const transferAccPubKey = transferAcc.publicKey;

  transaction.add(
    SystemProgram.createAccount(
      fromPubkey: payerAccount.publicKey,
      newAccountPubkey: transferAccPubKey,
      lamports: paymentFee,
      space: dataLayout.span,
      programId: PROGRAM_ID,
    )
  );

runloop 是一个非常好的合作伙伴资源,可以在这方面提供帮助。将所有交易项目添加到交易项目后,您将使用以下方式发送它:

  return await sendAndConfirmTransaction(connection, transaction, [
    payerAccount, transferAcc
  ]);

因此,如果您不知道在哪里插入 transaction.add 方法,请寻找它。

我花了很长时间才弄清楚这一点,所以希望它对某人有所帮助。

【讨论】:

为更清晰添加了链接测试链接 - github.com/solana-labs/solana-web3.js/blob/…

以上是关于什么是用于创建程序可用于执行合同付款的转账账户的 Solana 模式?的主要内容,如果未能解决你的问题,请参考以下文章

苹果手机app内购是从哪儿扣费

如何使用银行转账 (BACS) 以电子方式将资金转入另一个账户

微信开发-- 企业付款到用户

在 PHP 中使用 Paypal 进行 ACH 支付转账

Omnipay:将钱从 PayPal 账户转移到 Stripe 账户

Stripe connect - 在付款过程中保存卡