【问题标题】:Solana Anchor How to withdraw tokens from program account to user account?Solana Anchor 如何将代币从程序账户提取到用户账户?
【发布时间】:2021-08-17 17:13:55
【问题描述】:

我可以成功地将 USDC 代币从用户账户质押到程序账户, 但是提取USDC代币,在“check4”之后就失败了:

  pub fn withdraw_usdc(ctx: Context<UsdcDoge>, amount: u64, nonce: u8) -> ProgramResult {
    let seeds = &[ctx.accounts.usdc_mint.to_account_info().key.as_ref(), &[nonce], ];
    let signer = &[&seeds[..]];
    msg!("check3");
    let cpi_accounts = Transfer {
      from: ctx.accounts.usdc_pgid.to_account_info(),
      to: ctx.accounts.usdc_user.to_account_info(),
      authority: ctx.accounts.program_signer.clone(),
    };
    let cpi_program = ctx.accounts.token_program.clone();
    let cpi_ctx = CpiContext::new_with_signer(cpi_program, cpi_accounts, signer);
    msg!("check4");
    token::transfer(cpi_ctx, amount).expect("transfer2 failed");//?;
    Ok(())
  }

...

#[derive(Accounts)]
pub struct UsdcDoge<'info> {
  pub program_signer: AccountInfo<'info>,

  #[account(signer)]//authority should sign this txn
  pub authority: AccountInfo<'info>,

  pub usdc_mint: CpiAccount<'info, Mint>,

  #[account(mut, "usdc_user.owner == *authority.key")]
  pub usdc_user: CpiAccount<'info, TokenAccount>,

  #[account(mut)]
  pub usdc_pgid: CpiAccount<'info, TokenAccount>,

  #[account(mut,
  "doge_mint.mint_authority == COption::Some(*program_signer.key)")]
  pub doge_mint: CpiAccount<'info, Mint>,

  #[account(mut, "doge_user.owner == *authority.key")]
  pub doge_user: CpiAccount<'info, TokenAccount>,

  #[account(mut)]
  pub doge_pgid: CpiAccount<'info, TokenAccount>,

  //pub program_id: Pubkey<'info>,
  
  // We already know its address and that it's executable
  #[account(executable,"token_program.key == &token::ID")]
  pub token_program: AccountInfo<'info>,

  pub system_program: AccountInfo<'info>,
}

'程序日志:错误:所有者不匹配'

错误:发送交易失败:交易模拟失败:错误处理指令0:自定义程序错误:0x4

'Program log: --------------== withdraw_usdc',
'Program log: check1',
'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]',
'Program log: Instruction: Transfer',
'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 3402 of 188791 compute units',
'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success',
'Program log: transfer1 successful. amount: 5000000',
'Program log: check3',
'Program log: check4',
'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]',
'Program log: Instruction: Transfer',
'Program log: Error: owner does not match',
'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 2902 of 181411 compute units',
'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA failed: custom program error: 0x4',
'Program J1JQ8f2s77Xhx7xQCRZmMTK2j3HuahgeSMUuccL5ywnb consumed 200000 of 200000 compute units',
'Program J1JQ8f2s77Xhx7xQCRZmMTK2j3HuahgeSMUuccL5ywnb failed: custom program error: 0x4'

在锚脚本中:

await program.rpc.withdrawUsdc(
  amt2, nonce, {
  accounts: {
    programSigner,
    authority: userKeys.publicKey,
    usdcMint,
    usdcUser,
    usdcPgid,
    dogeMint,
    dogeUser,
    dogePgid,
    tokenProgram: TOKEN_PROGRAM_ID,
    systemProgram: anchor.web3.SystemProgram.programId,
  },
  signers: [userKeys],
});

上面的accounts对象、amt2、nonce值和stakeUsdc函数调用中的完全一样……所以不知道owner是哪里错了……

在失败之前,USDC 在 usdc_pgid 账户上,该账户来自:

usdcPgid = await createTokenAccount(provider, usdcMint, program.programId);//arguments: privider, mint, owner

usdc_pgid 的所有者是 program.programId,所以我应该让 cpi_accounts 使用 programId 作为权限... 比如:

 authority: ctx.program_id.to_account_info(),

错误[E0599]:在当前范围内找不到名为to_account_info 的方法以供参考&amp;anchor_lang::prelude::Pubkey --> 程序/doge/src/lib.rs:265:33 | 265 |权限:ctx.program_id.to_account_info(), | ^^^^^^^^^^^^^^^ 方法在&amp;anchor_lang::prelude::Pubkey中找不到

anchor_lang::CpiAccount https://docs.rs/anchor-lang/0.13.2/anchor_lang/struct.CpiAccount.html

anchor_lang::prelude::Pubkey https://docs.rs/anchor-lang/0.13.2/anchor_lang/prelude/struct.Pubkey.html

从上面的文档看,Pubkey 类型没有从 Pubkey 转换为 AccountInfo 类型的方法! 我该怎么做?

【问题讨论】:

    标签: rust solana


    【解决方案1】:

    程序的代币余额账户必须有一个签名者PDA作为所有者!

    所以token余额账户的所有者必须是programSigner!

    锚代码:

    programVault = await createTokenAccount(provider, usdcMint, programSigner);
    

    第三个参数必须是programSigner!!!

    【讨论】:

      猜你喜欢
      • 2022-11-14
      • 2021-12-06
      • 2018-11-09
      • 2020-10-21
      • 2021-12-17
      • 2018-03-20
      • 2021-12-25
      • 1970-01-01
      • 2022-01-06
      相关资源
      最近更新 更多