2

I have a program which consists of transferring funds to an account and works fine on the frontend, but that PDA is owned by the system program and when calling the function to transfer the funds, the end user has to approve the transaction to receive it, which is not user-friendly, the question is, does this have to be done through CPI? Or can that be done in another way? And if so I already tried CPI but I get "8DynevFKukK5FXXnhjPj8y97vX3zW6bi9xtU8A1H91rM's writable privilege escalated", 'Program HmbTLCmaGvZhKnn1Zfa1JVnp7vkMV4DYVxPLWBVoN65L consumed 7791 of 200000 compute units', 'Program HmbTLCmaGvZhKnn1Zfa1JVnp7vkMV4DYVxPLWBVoN65L failed: Cross-program invocation with unauthorized signer or writable account' (I read the anchor docs about CPI/PDA's already) and I am still stuck. Thanks in advance for potential replies! :)

Here is my CPI master code

#[program]
mod escrow_master {
    use super::*;
    pub fn pull_strings(ctx: Context<PullStrings>,masterbump: u8, amount: u64, bump:u8, p1:Pubkey, p2:Pubkey, rstring:String) -> Result<()> {
        let abump = &[masterbump][..];
        deposit_app::cpi::pay_winner(
            ctx.accounts.pay_ctx().with_signer(&[&[abump][..]]),
             amount, bump,p1, p2, rstring.clone()
        )?;
        Ok(())
    }
}

#[derive(Accounts)]
pub struct PullStrings<'info> {
    pub puppet: SystemAccount<'info>, //puppet PDA
    pub puppet_program: Program<'info, DepositApp>,
    /// CHECK: only used as a signing PDA
    pub authority: UncheckedAccount<'info>, //master PDA
    /// CHECK:
    #[account(mut)]
    pub destination: SystemAccount<'info>,
    #[account(mut)]
    /// CHECK:
    fee_acc: AccountInfo<'info>,
}


impl<'info> PullStrings<'info> {
    pub fn pay_ctx(&self) -> CpiContext<'_, '_, '_, 'info, SendSolt<'info>> {
        let cpi_program = self.puppet_program.to_account_info();
        let cpi_accounts = SendSolt {
            destination: self.destination.to_account_info(), //master PDA
            pda: self.puppet.to_account_info(), //PDA that we want to sign the transac
            system_program: self.puppet_program.to_account_info(),
            fee_acc: self.fee_acc.to_account_info(),
            authority: self.authority.to_account_info()
        };
        CpiContext::new(cpi_program, cpi_accounts)
    }
} 

Transfer function

 pub fn pay_winner(ctx: Context<SendSolt>, amount: u64, bump: u8,
        player_one: Pubkey, player_two: Pubkey, asring: String) -> Result<()> {
        let payout:f64 = amount as f64 * 0.95;
        let fee:f64 = amount as f64 * 0.05;
        let ix = transfer(ctx.accounts.pda.key, ctx.accounts.destination.key, payout as u64);

        invoke_signed(
            &ix,
            &[
                ctx.accounts.pda.to_account_info(),
                ctx.accounts.destination.to_account_info(),
                ctx.accounts.system_program.to_account_info(),
            ],
            &[&[
                asring.as_bytes().as_ref(),
                player_one.as_ref(),
                player_two.as_ref(),
                &[bump],
            ]],
        )?;
        
        //pay the fees
        let fee_ix = transfer(ctx.accounts.pda.key, ctx.accounts.fee_acc.key, fee as u64);
        invoke_signed(
            &fee_ix,
            &[
                ctx.accounts.pda.to_account_info(),
                ctx.accounts.fee_acc.to_account_info(),
                ctx.accounts.system_program.to_account_info(),
            ],
            &[&[
                asring.as_bytes().as_ref(),
                player_one.as_ref(),
                player_two.as_ref(),
                &[bump],
            ]],
        )?;

        Ok(())
    }

#[derive(Accounts)]
pub struct SendSolt<'info> {
    #[account(mut)]
    destination: SystemAccount<'info>,
    #[account(mut)]
    pda: SystemAccount<'info>,
    system_program: Program<'info, System>,
    #[account(mut, constraint = FEE_WALLET == fee_acc.key.to_string())]
    /// CHECK:
    fee_acc: AccountInfo<'info>,
    pub authority: Signer<'info>
}

And here is my CPI on the frotend

   //CPI
      await puppetMasterProgram.methods
      .pullStrings(puppetMasterBump, new BN(lampsToSend*2), testCrowPDABump, user1.publicKey, user2.publicKey, randomString)
      .accounts({
        puppetProgram: program.programId,
        puppet: escrowPda,
        authority: puppetMasterPDA,
        destination:random.publicKey,
        feeAcc: fee_wallet
      })
      .rpc()

UPDATE: I get a "DFr2TLNxa8dLiLXt9gHLtJSY4nMxQqwMWuKgfPMmXn2L's writable privilege escalated", 'Program HmbTLCmaGvZhKnn1Zfa1JVnp7vkMV4DYVxPLWBVoN65L consumed 7791 of 200000 compute units', 'Program HmbTLCmaGvZhKnn1Zfa1JVnp7vkMV4DYVxPLWBVoN65L failed: Cross-program invocation with unauthorized signer or writable account' Error now...

2
  • Could you share the code that produces that error.
    – C.OG
    Aug 12, 2022 at 19:26
  • I updated with the code
    – Sing
    Aug 12, 2022 at 19:35

1 Answer 1

1

Looks like puppet should also be mut in your PullStrings struct.

#[derive(Accounts)]
pub struct PullStrings<'info> {
    #[account(mut)]
    pub puppet: SystemAccount<'info>, //puppet PDA
    ...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.