I am trying to make a SOL transfer via a CPI call, I managed to create an account to which I have to transfer, this account's authority is owned by a (master) PDA, transfer/deposit works fine but when I try to transfer/withdraw the sol a user (a pubkey) from the CPI call it doesn't work and I get, I believe the signer PDA has the right authorization, correct me I am wrong

Error: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: Program failed to complete

My structs look like this enter image description here

My withdraw instruction look like this enter image description here

and my CPI code look like this enter image description here

To call the test I simply call it like that const wtx = await escrowMasterProgram.methods .pullStrings(new BN(lamportz), playerOne.publicKey) .accounts({ puppetProgram: program.programId, puppet: puppetKeypair.publicKey, authority: puppetMasterPDA, }).rpc()

Can someone please explain what went wrong in my code please?

  • 1
    please replace all of these screenshots with code blocks
    – trent.sol
    Jul 26, 2022 at 22:58
  • put the transaction inside try and catch block in client side and console out the error. You would get more information which would help solve the issue. You could also share the error logs so we could help. Jul 27, 2022 at 7:10
  • I console.logged the error and got a SendTransactionError: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: Cross-program invocation with unauthorized signer or writable account at Connection.sendEncodedTransaction
    – Sing
    Jul 27, 2022 at 7:58

3 Answers 3


Your struct PullStrings<'info> needs to list the receiver ("to" account).

Then, in the code for pull_strings, you need to add the receiver account to the CPI call, calling set_data. Then in the code for set_data, you need to add ctx.receiver... in the invoke_signed.

That way, the receiver account will be passed in from the client (you can add any Pubkey in the test client), and that receiver account will then be passed down, level by level, until you can use it in the invoke_signed of the transfer_instruction.

  • So I added in struct PullStrings<'info> a field pub to: AccountInfo<'info> but I get stuck with trying to add the receiver (sorry I am quite new to Rust), so should it be like ` pub fn pull_strings(ctx: Context<PullStrings>, lamportz: u64) -> Result<()> { rps_project::cpi::set_data(ctx.accounts.set_data_ctx() .with_signer(&[&[ b"escrow_wallet".as_ref(), ctx.accounts.puppet.to_account_info().key.as_ref(), ]]) , lamportz, ctx.accounts.to.to_account_info().key) }` ? I removed to:Pubkey from args
    – Sing
    Jul 26, 2022 at 23:39
  • So I also added a pub to: AccountInfo<'info> in the SetData struct snipboard.io/I4RLQJ.jpg , then I followed your instructions for next screen snipboard.io/fD160t.jpg snipboard.io/5gIEFl.jpg but somehow I still get ` Error: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: Program failed to complete`
    – Sing
    Jul 27, 2022 at 1:22

You need to include the "to" account in your SetData account context because your changing its' balance.

  • If I add a "to" accountInfo in my SetData struct, how do I pass on the "to" argument accountinfo in my CPI code? Because it takes a pubkey as argument
    – Sing
    Jul 26, 2022 at 21:30
  • Try call to.key if to is of type accountinfo.
    – Meow
    Jul 26, 2022 at 21:41

Your from account is a PDA, and it is not owned by the system program. This is going to sound weird, but that means you cannot use the "transfer" function.

Use try_mut_borrow_lamports:


The Three Rules to Transferring Lamports

Say you want to move lamports out of Account A.

  1. If SystemProgram doesn’t own account A, then you can’t put it in the from field of SystemProgram::transfer.
  2. If your program owns account A, then you can use try_mut_borrow_lamports.
  3. If some foreign program owns account A, then you must rely on that program exposing a means of moving lamports out of account A.

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.