0

I am struggling to successfully create a PDA account (pdaUSER) paid for by another PDA account.

I am doing it like this, and it does not work:

        invoke_signed(
        &system_instruction::create_account(
            &pdaGLOBAL.key,
            &pdaUSER.key,
            rentUSER,
            SIZE_USER.into(),
            &program_id,
        ),
        &[
            pdaGLOBAL.clone(),
            pdaUSER.clone(),
        ],
        &[&[&seedUSER, &[bumpUSER]]]
        )?;

The balance of pdaGLOBAL is 100 SOL.

On the other hand, when I pay for pdaUSER creation with the address that signed the transaction, just a regular solana account. It works fine, like this:

        invoke_signed(
        &system_instruction::create_account(
            &owner.key,
            &pdaUSER.key,
            rentUSER,
            SIZE_USER.into(),
            &program_id,
        ),
        &[
            owner.clone(),
            pdaUSER.clone(),
        ],
        &[&[&seedUSER, &[bumpUSER]]]
        )?;

Do I need to provide

&[&[&seedGLOBAL, &[bumpGLOBAL]]],
&[&[&seedUSER, &[bumpUSER]]],

instead? Or something entirely different altogether?

Thanks for your help.

1
  • please provide the error you are receiving
    – trent.sol
    Commented Jul 28, 2022 at 18:00

2 Answers 2

1

It's relatively likely that you need to include the signatures of both accounts, the PDA payer and the PDA account that will be created.

You don't need to explicitly add the signature when there's an external signature because the Solana run time automatically includes any existing signatures in the CPI. But for PDAs which use seed based signing, you will need to include every seed for every PDA that needs to sign.

For signing with multiple PDAs though they all need to go into the same array. Hence it should the seeds should look like this:

&[&[&seedGLOBAL, &[bumpGLOBAL]], &[&seedUSER, &[bumpUSER]]]
4
  • I verified that this answer is indeed correct. Thank you @Henry E! Commented Jul 28, 2022 at 21:10
  • Well, it was working, but I restarted my validator and now it isn't working anymore. Back to square 1. Commented Jul 28, 2022 at 23:20
  • Try posting another question if you're getting a new error. It really helps to have the exact error message. Usually if it stops working after restarting a validator that means you didn't initialize some account properly
    – Henry E
    Commented Jul 29, 2022 at 7:22
  • Sorry about this, but my original implementation of your answer turned out to be me tricking myself. After starting from scratch with my validator, I could not get the above to work. Instead I found a different working solution, answered below. Commented Jul 29, 2022 at 16:44
0

The originally accepted answer above turned out to be incorrect (I was confounding different results with the incorrect solution's implementation I made. (sorry for the confusion)

According to sources, it is actually impossible to invoke system_instruction to modify balance/state on a pda, because the pda is owned by the pda program, not the system program.

The only way modify pda balance is by borrowing after any system_instruction calls have been made. (I do not understand why this is, but I verified it.)

The fix was to use a regular signing account ('owner') to fund create_account, then afterwards reimburse the regular account by borrowing from pdaGLOBAL. Working version below:

        &system_instruction::create_account(
            &owner.key,
            &pdaUSER.key,
            rentUSER,
            SIZE_USER.into(),
            &program_id,
        ),
        &[
            owner.clone(),
            pdaUSER.clone(),
        ],
        &[&[&seedUSER, &[bumpUSER]]],
        )?;
        msg!("Successfully created pdaUSER");
        
        // cover rent costs by transferring lamp to owner
        **pdaGLOBAL.try_borrow_mut_lamports()? -= rentUSER;
        **owner.try_borrow_mut_lamports()? += rentUSER;

To reiterate, multiple seed signers like &[&[&seedGLOBAL, &[bumpGLOBAL]], &[&seedUSER, &[bumpUSER]]] did NOT work for me.

2
  • You can modify the balance of a PDA owned by the system program. Even if the PDA is derived from the program calling the instruction
    – Henry E
    Commented Jul 29, 2022 at 17:50
  • please clarify that the manipulation of the lamports field must be performed after any CPI calls, not only system program invocations
    – trent.sol
    Commented Jul 29, 2022 at 23:24

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.