如何将 SOL 从创建令牌关联帐户的 PDA 转移到 Anchor 中的普通帐户?

Ken*_*Heo 5 rust solana anchor-solana

如果一旦将 PDA 创建为关联代币地址,就无法将 SOL 从 PDA 转移到另一个帐户?

我想使用单个 PDA 帐户转移 SOL 和 SPL 令牌。

我尝试了solana_program::program::invoke_signedsystem_instruction::transfertry_borrow_mut_lamports()但是,它不起作用。

每当使用 system_program 进行传输时,我都是Transfer: must not carry data,另一种方式是instruction spent from the balance of an account it does not own

我缺少什么?

我可以得到一些建议吗?

谢谢。

Struct 中的关联令牌帐户

#[account(init, 
    seeds = [authority.to_account_info().key.as_ref()], 
    bump, 
    payer = authority, 
    token::mint = mint, 
    token::authority = authority)
]    
pub vault: Account<'info, TokenAccount>,
Run Code Online (Sandbox Code Playgroud)

创建另一个 PDA,用于从保管库帐户转移 spl 令牌时的权限

let (vault_authority, vault_authority_bump) = Pubkey::find_program_address(
    &[ctx.accounts.vault.to_account_info().key.as_ref()], ctx.program_id
);

let cpi_accounts = SetAuthority {
    account_or_mint: ctx.accounts.vault.to_account_info().clone(),
    current_authority: ctx.accounts.authority.to_account_info().clone()
};
let cpi_context = CpiContext::new(ctx.accounts.token_program.to_account_info().clone(), cpi_accounts);
token::set_authority(cpi_context, AuthorityType::AccountOwner, Some(vault_authority))?;
Run Code Online (Sandbox Code Playgroud)

失败案例 1,使用 system_program 将 SOL 从保管库转移给所有者

// Error message : Transfer: `from` must not carry data
let vault_key = ctx.accounts.authority.to_account_info().key.as_ref();
let (_vault, bump) = Pubkey::find_program_address(&[vault_key], ctx.program_id);
let seeds = &[vault_key, &[bump]];
let signer = &[&seeds[..]];

let owner_key = &ctx.accounts.owner.key();
let vault_key = &ctx.accounts.vault.key();
let ix = system_instruction::transfer(vault_key, owner_key, amount);

let owner_account = ctx.accounts.owner.to_account_info();
let vault_account = ctx.accounts.vault.to_account_info();
solana_program::program::invoke_signed(&ix, &[vault_account, owner_account], signer)?;
Run Code Online (Sandbox Code Playgroud)

失败案例 2,使用“try_borrow_mut_lamports”将 SOL 从保管库转移给所有者

// Error message : instruction spent from the balance of an account it does not own
**ctx.accounts.vault.to_account_info().try_borrow_mut_lamports()? -= amount;
**ctx.accounts.owner.to_account_info().try_borrow_mut_lamports()? += amount;
Run Code Online (Sandbox Code Playgroud)

Jon*_*n C 4

无法从同一账户同时转移 SOL 和 SPL 代币。SPL 代币账户(关联或未关联)归 SPL 代币程序所有,这意味着只有 SPL 代币程序才能更改其数据并扣除其 lamport。否则,任何人都有可能将代币账户置于租金豁免之下并破坏代币计划的保证。

让我们回顾一下您的案例并解释为什么它们不起作用:

  • 失败的情况 1,使用system_program触发将 SOL 从保管库转移给所有者:Transfer: from must not carry data

这里实际上有两个错误,但只报告了第一个。当您尝试从保管库中进行操作时system_instruction::transfer,主要会失败,因为保管库不属于系统程序。它由令牌程序拥有,因此只有令牌程序可以移动其灯,而系统程序则不能。报告的失败表明该帐户还有数据,即代币数据(所有者、金额、委托人等)。

  • 失败案例 2,使用“try_borrow_mut_lamports”将 SOL 从保管库转移给所有者

这个非常相似——不是系统程序试图从令牌帐户中扣除 lamport,而是你的程序试图这样做,所以运行时会再次说“这是不允许的”。