1

I'm new here and I would like to transfer USDC from a defined wallet to another defined wallet. The From account could be a Signer account. I'm really confused and I don't know what I should do. With my knowledge I guess I should transfer wallet address to ATA.

I'm running these Anchor functions on NextJS & TSX. I have no problem transferring Solana to a destination but I don't understand how to do it for USDC.

Here's my example code for transferring Solana.

    system_program::transfer(
        CpiContext::new(
            ctx.accounts.system_program.to_account_info(),
            system_program::Transfer {
                from: ctx.accounts.authority.to_account_info(),
                to: contract_account.to_account_info(),
            },
        ),


    Ok(())

I would like to do the same for USDC. I made this function basically to get money from a signer to an Account PDA after a contract has been completed.

        **ctx
        .accounts
        .moneyto
        .to_account_info()
        .try_borrow_mut_lamports()? += ctx.accounts.contract_account.price;

Thank you so much!

1

1 Answer 1

2

It's a bit more complicated for SPL token, since, you need the source and destination token accounts, along with an authority (or owner) on the source token account.

Copying the example at https://github.com/solana-labs/solana-program-library/blob/master/examples/rust/transfer-tokens/src/processor.rs, and assuming you receive all the proper accounts, you would do:

use {
    solana_program::{
        account_info::{next_account_info, AccountInfo},
        entrypoint::ProgramResult,
        msg,
        program::invoke,
        program_error::ProgramError,
        program_pack::Pack,
        pubkey::Pubkey,
    },
    spl_token::{
        instruction::transfer_checked,
        state::{Account, Mint},
    },
};

/// Instruction processor
pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    _instruction_data: &[u8],
) -> ProgramResult {
    // Create an iterator to safely reference accounts in the slice
    let account_info_iter = &mut accounts.iter();

    // As part of the program specification the instruction gives:
    let source_info = next_account_info(account_info_iter)?; // 1.
    let mint_info = next_account_info(account_info_iter)?; // 2.
    let destination_info = next_account_info(account_info_iter)?; // 3.
    let authority_info = next_account_info(account_info_iter)?; // 4.
    let token_program_info = next_account_info(account_info_iter)?; // 5.

    // The program transfers everything out of its account, so extract that from
    // the account data.
    let source_account = Account::unpack(&source_info.try_borrow_data()?)?;
    let amount = source_account.amount;

    // The program uses `transfer_checked`, which requires the number of decimals
    // in the mint, so extract that from the account data too.
    let mint = Mint::unpack(&mint_info.try_borrow_data()?)?;
    let decimals = mint.decimals;

    // Invoke the transfer
    msg!("Attempting to transfer {} tokens", amount);
    invoke(
        &transfer_checked(
            token_program_info.key,
            source_info.key,
            mint_info.key,
            destination_info.key,
            authority_info.key,
            &[], // no multisig allowed
            amount,
            decimals,
        )
        .unwrap(),
        &[
            source_info.clone(),
            mint_info.clone(),
            destination_info.clone(),
            authority_info.clone(),
            token_program_info.clone(), // not required, but better for clarity
        ],
    )
}

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.