6

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

所以我的问题有两个:

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

这是客户端中的 JS createAccountWithSeed

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
4

1 回答 1

6

好的,所以转账账户归系统程序而不是我的程序所有的原因是因为我在交易之外创建了账户。关键是将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方法,请寻找它。

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

于 2021-08-04T06:55:14.870 回答