How to transfer SOL in anchor smart contract instruction

Viewed 3398

I am creating a dapp where multiple users can deposit SOL into an event account, and depending on whoever wins the event, they can redeem SOL back to their wallet.

How can I transfer native SOL (not any other spl-token) directly into the event account's vault address in an anchor smart contract instruction?

Would the following anchor instruction work? If yes, what should be the PROGRAM_ACCOUNT in the following? Presumably, it should be the account that handles native SOL, but I couldn't find it in the documentation.

token::transfer(
    CpiContext::new(
        PROGRAM_ACCOUNT,
        anchor_spl::token::Transfer {
            from: source_user_info,
            to: destination_user_info,
            authority: source_user_info,
        },
    ),
    1,
)?; 

Thanks in advance!

5 Answers

To send native SOL using Anchor, you can use the following code inside an instruction:

    let ix = anchor_lang::solana_program::system_instruction::transfer(
        &ctx.accounts.from.key(),
        &ctx.accounts.to.key(),
        amount,
    );
    anchor_lang::solana_program::program::invoke(
        &ix,
        &[
            ctx.accounts.from.to_account_info(),
            ctx.accounts.to.to_account_info(),
        ],
    );

Where amount is a number (u64) representing the Lamports (0.000000001 SOL).

You can check the Transfer function in the Solana Program documentation and the Solana Cookbook section of Sending SOL.

Unfortunately, all of the answers thus far are for plain Solana, not Anchor.

Anchor already comes with additional conveniences to make transfers easier. You were on the right track with the code in the question:

use anchor_lang::system_program;

let cpi_context = CpiContext::new(
    ctx.accounts.system_program.to_account_info(), 
    system_program::Transfer {
        from: ctx.accounts.account_a.clone(),
        to: ctx.accounts.account_b.clone(),
    });
system_program::transfer(cpi_context, bid_amount)?;

This is assuming this accounts struct:

#[derive(Accounts)]
pub struct MyInstruction<'info> {
    account_a: AccountInfo<'info>,
    account_b: AccountInfo<'info>,
}

Of course, if you are using Account<> wrappers, just replace clone() with to_account_info().

You have to do something like this

let lamports: u64  = 1000000;

let sol_transfer = anchor_lang::solana_program::system_instruction::transfer(
    &ctx.accounts.from.key,
    &ctx.accounts.to.key,
    lamports,
);
invoke(
    &sol_transfer,
    &[
        ctx.accounts.from.clone(),
        ctx.accounts.to.clone(),
        ctx.accounts.system_program.clone(),
    ],
)?;

Also, make sure to pass system_program to your program. For example

 #[derive(Accounts)]
pub struct SolSend<'info> {
    #[account(mut, signer)]
    /// CHECK: This is not dangerous because we don't read or write from this account
    pub from: AccountInfo<'info>,       
    /// CHECK: This is not dangerous because we don't read or write from this account
    #[account(mut)]
    pub to: AccountInfo<'info>,        
    /// CHECK: This is not dangerous because we don't read or write from this account
    pub system_program: AccountInfo<'info>,
}

Hope this helps.

To send native SOL with Anchor

#[program]
pub mod learn_solana_anchor {
    use super::*;

    pub fn transfer_native_sol(ctx: Context<Transfer>) -> Result<()> {
        let amount_of_lamports = 42; // could be an argument ;-)
        let from = ctx.accounts.from.to_account_info();
        let to = ctx.accounts.to.to_account_info();

        // Debit from_account and credit to_account
        **from.try_borrow_mut_lamports()? -= amount_of_lamports;
        **to.try_borrow_mut_lamports()? += amount_of_lamports;

        Ok(())
    }

}

#[derive(Accounts)]
pub struct Transfer<'info> {
    #[account(mut)]
    /// CHECK: This is not dangerous because its just a stackoverflow sample o.O
    pub from: AccountInfo<'info>,
    #[account(mut)]
    /// CHECK: This is not dangerous because we just pay to this account
    pub to: AccountInfo<'info>,
    #[account()]
    pub user: Signer<'info>,
    pub system_program: Program<'info, System>,
}

Ref

https://solanacookbook.com/references/programs.html#how-to-transfer-sol-in-a-program

Related