Solana Anchor 传递非自有账户信息以转移 SOL

Solana Anchor passing Non Owned Account Info to Transfer SOL

我需要一个程序来将 PDA 拥有的 SOL 分发到另一个帐户。

如下定义 distribute 指令的上下文。

#[derive(Accounts)]
pub struct Pool<'info> {
    #[account(
        mut, 
        seeds = [
            b"pool_account".as_ref()], 
            bump = pool_account.pool_account_bump
        )
    ]
    pool_account: Account<'info, PoolState>,
    #[account()]
    soho_account: Account<'info, PoolState>
}

distribute指令是

pub fn distribute(ctx: Context<Pool>) -> ProgramResult {
        let pool_account = &ctx.accounts.pool_account;
        let pool_account_balance = pool_account.to_account_info().lamports();
        let soho_account = &ctx.accounts.soho_account;

        println!("Distributing {:?} lamports ", pool_account_balance,);

        let from_pub_key = pool_account.to_account_info().key;
        let to_pub_key = soho_account.to_account_info().key;
        let ix = system_instruction::transfer(from_pub_key, to_pub_key, pool_account_balance);
        anchor_lang::solana_program::program::invoke(
            &ix,
            &[
                ctx.accounts.pool_account.to_account_info(),
                soho_account.to_account_info()
            ],
        )?;

        Ok(())
    }

测试

it(`Distrubutes funds to shareholders`, async () => {
    let [poolAccount, poolAccountBump] = await web3.PublicKey.findProgramAddress(
      [Buffer.from("pool_account")],
      program.programId
    )

    // Airdrop SOL to pool account PDA
    const connection = await anchor.getProvider().connection;
    let signature = await connection.requestAirdrop(poolAccount, LAMPORTS_PER_SOL)
    await connection.confirmTransaction(signature);

    balance = await connection.getBalance(poolAccount);
    console.log(`Pool Account: ${poolAccount} balance: ${balance}`)
    assert.ok(balance == 1000953520, `Program account has ${balance}`)

    const sohoAccount = anchor.web3.Keypair.generate();
    signature = await connection.requestAirdrop(sohoAccount.publicKey, LAMPORTS_PER_SOL)
    await connection.confirmTransaction(signature);

    await program.rpc.distribute({
      accounts: {
        poolAccount: poolAccount,
        sohoAccount: sohoAccount.publicKey,
        // soho2: soho2.publicKey,
      }
    })

  })

当我 运行 测试 distribute 指令时,测试失败 w/ Error: 3007: The given account is owned by a different program than expected 留言。

基本上,它希望 soho_account 归程序所有。但是它应该是一个外部帐户。

system 转移要求 from 帐户至少是系统拥有的帐户。不是 PDA,也不是程序拥有的帐户。

如果您的程序 owned PDA,那么您的程序可以从它转移到任何帐户,而无需调用系统转移。

参见食谱:https://solanacookbook.com/references/programs.html#transferring-lamports