4

My goal is to have my own program receive any Token, store in one of PDAs of program. Then transfer they out to end user wallet.

Currently I successfully send token to program's PDA, but still not able to transfer token out. What I have try is following this guide: https://www.quicknode.com/guides/solana-development/anchor/transfer-tokens but it turn out that this guide just send token from one source account to destination, have nothing to do with program's PDA.

Can anyone share some proper guide or snippet, demo?

Thanks

2 Answers 2

5

with Anchor 0.29.0 you can use the TransferChecked Struct and transfer_checked fn that will do the invoke_signed under the hood. And send the specific token and amount that you want.

Example:

    let accounts = TransferChecked {
        from: self.pda.to_account_info(),
        to: self.owner_ata.to_account_info(),
        authority: self.pda.to_account_info(),
        mint: self.mint.to_account_info()
    };

    let seeds = &[
        &b"yourseeds"[..],
    ];

    let signer_seeds = &[&seeds[..]];

    let ctx = CpiContext::new_with_signer(
        self.token_program.to_account_info(),
        accounts,
        signer_seeds
    );

    transfer_checked(ctx, amount, self.mint.decimals)

Make sure you are importing:

    use anchor_spl::token_interface::{TransferChecked, transfer_checked};
8
  • This looks a lot nicer than the pre-0.29 answer!
    – Jacob Creech
    Commented Feb 3 at 3:20
  • I still have problem while trying your example. 1) is 'self.pda' PDA or ATA account ? 2) is "authority" the PDA or ATA account ? 3) is it correct to set 'token_program' to value 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' ? Commented Feb 8 at 13:05
  • The above example is transfering funds out of a pda. breeze 1-self.(name or pda account). 2- should be the same as 1. Unless you have an unchecked account just to sign things but doubt you are using, so you can use the pda. 3) No, incorrect. its self_token_program or whatever you called your type TokenInterface//0.29.0 or Token < 0.28.0 Note: ATA accounts are pdas. Commented Feb 8 at 21:38
  • I have manage to successfully fulfil my goal with your approach. But need to modify the 'from' account, not use PDA, but use ATA of PDA. Here is my demo: beta.solpg.io/65c6342bcffcf4b13384cf58 And the 'token_program' on playground GUI input actually is TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA when on devnet. Commented Feb 15 at 16:58
  • was checking your code: your vault seeds are wrong perhaps u meant seeds = [b"vault"].The way you have it right now its: from vault_ata to: something ata. //because you defined vault as system acc. If you want to do it directly from pda to any ata your vault account would look like this: #[account( init, payer = maker, seeds = [b"vault"], bump, token::mint = maker_token, token::authority = auth )] pub vault: InterfaceAccount<'info, TokenAccount>, TLDR: This pda already an ata. The SystemAcc is not pda. Commented Feb 15 at 23:38
3

To transfer out of a pda you'd basically have to something like:

let bump = *ctx.bumps.get("pda").unwrap();
let signer: &[&[&[u8]]] = &[&[constants::PDA_SEED, staker.as_ref(), &[bump]]];

transfer(
  CpiContext::new_with_signer(
    ctx.accounts.token_program.to_account_info(),
      Transfer {
        from: ctx.accounts.pda.to_account_info(),
        to: ctx.accounts.token_account.to_account_info(),
        authority: ctx.accounts.pda.to_account_info(),
       },
       signer,
    ),
  ctx.accounts.pda.amount, // Transfer all tokens from pda
)?;

This grabs the pda's seed and bump and uses it to sign the transfer out. This is written with anchor and transfer the full token amount to whatever account you put as token_account.

2
  • Thanks for you help. I'm doubt ctx.accounts.pda.amount is correct. Here is my demo follow your suggestion: beta.solpg.io/65c10271cffcf4b13384cf4a but it raise error when invoke, error message: "Invalid account data for instruction" Commented Feb 5 at 15:48
  • 1
    Finally I make it. Key popint is change : ctx.accounts.vault.to_account_info() to ctx.accounts.vault_ata.to_account_info() Full code: beta.solpg.io/65c4d8becffcf4b13384cf55 Commented Feb 8 at 13:53

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.