0

Basically I'm trying to figure out to transfer SOL out of a wallet account which is owned by a PDA. the PDA is in turn owned by my program.

I've tried invoke_signed, my seeds are all correct, and I keep getting signer escalation on the wallet account pubkey itself when trying to transfer that way. I understand that system program transfer function requires the account where lamports are being sent from to be a signer.

And the method that uses try borrow mut lamports also doesnt work because the program isnt the owner of the wallet account, the PDA is. I'm really stuck, does anyone know how to do this?

creating the pda:

invoke_signed(
            &system_instruction::create_account(
                initializer.key,
                pda_account.key,
                lamports,
                space as u64,
                program_id,
            ),
            &[initializer.clone(), pda_account.clone(), system_program.clone()],
            &[&[seed.as_bytes(), initializer.key.as_ref(), &[bump]]],
        )?;

assigning ownership to the pda:

            let instruction = system_instruction::assign(&initializer.key, pda_account.key);
        invoke(
            &instruction,
            &[initializer.clone(), pda_account.clone()],
        )?;

when trying to transfer lamports from the initializer to the pda via "try_borrow_mut_lamports", it doesnt work. Neither does using an invoke_signed transfer instruction.

**wallet_account.try_borrow_mut_lamports()? -= lamports_to_transfer;
**_pda_account.try_borrow_mut_lamports()? += lamports_to_transfer;

when using "invoke_signed" transfer, I get a signer escalation error, the runtime thinks the wallet_account should have signed the transaction, but it cant as i dont have access to the users keys to sign on the frontend.

let lamports_to_transfer = wallet_account.lamports();

let ix = system_instruction::transfer(
    wallet_account.key,
    pda_account.key,
    lamports_to_transfer,
);

invoke_signed(
    &ix,
    &[ wallet_account.clone(), pda_account.clone() system_program.clone()],
    &[&[seed.as_bytes(), &wallet_account.key.as_ref(), &[bump3]]],
)?;

shouldnt signing it with the PDA seeds be enough?

I am certain i am deriving the keys correctly, i have msg!'s littered throughout to debug line by line.

is this even possible?

2 Answers 2

1

**from_account.try_borrow_mut_lamports()? -= amount_of_lamports; **to_account.try_borrow_mut_lamports()? += amount_of_lamports;

where from_account is your PDA

21
  • if this does not work, could you please share your code where you are trying to this along with the context for the instruction?
    – keegan
    Commented Jul 8 at 3:11
  • I get the "instruction spent from the balance of an account it does not own" error. this is because the PDA is the owner of the wallet, which was done with 'assign' instruction after the user creates a PDA. When running this instruction, the transaction is signed by the program itself. Now I want to transfer sol from the PDA owned wallet account. does that make sense? invoke_signed doesnt work either. Commented Jul 8 at 3:41
  • hmm, can you share your full instruction code here?
    – keegan
    Commented Jul 8 at 3:51
  • i updated my post with the relevant code / notes. hoping to get any clarification. is it proper etiquette to assign wallet ownership to pda? Commented Jul 8 at 4:08
  • what is the wallet account? can you share the context as well for this instruction?
    – keegan
    Commented Jul 8 at 4:23
0
  &system_instruction::create_account(
                initializer.key,
                pda_account.key,
                lamports,
                space as u64,
                ***program_id***,
            ),

The problem is in the owner field specified in the account creation. You assigned your "program_id" as the account's owner. Then, you invoke another program(The Solana Token program, using &system_instruction::create_aqccount) to perform an action on an account it doesn't own.

To fix this, you would have to manually debit the account and credit another account the same amount of lamports so the total account balance before and after the transaction would be the same. like so

**account_one.lamports.borrow_mut() -= <amount_in_lamports>; **account_two.lamports.borrow_mut() += <amount_in_lamports>;;

This would act as your program performing actions on an account it owns. But for more security, you'd want to do this rarely and use the token program instruction to interact with native SOL accounts.

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.