Function solana_program::system_instruction::transfer

source ·
pub fn transfer(
    from_pubkey: &Pubkey,
    to_pubkey: &Pubkey,
    lamports: u64
) -> Instruction
Expand description

Transfer lamports from an account owned by the system program.

This function produces an Instruction which must be submitted in a Transaction or invoked to take effect, containing a serialized SystemInstruction::Transfer.

§Required signers

The from_pubkey signer must sign the transaction.

§Examples

These examples allocate space for an account, transfer it the minimum balance for rent exemption, and assign the account to a program.

§Example: client-side RPC

This example submits the instructions from an RPC client. It assigns the account to a provided program account. The payer and new_account are signers.

use solana_rpc_client::rpc_client::RpcClient;
use solana_sdk::{
    pubkey::Pubkey,
    signature::{Keypair, Signer},
    system_instruction,
    transaction::Transaction,
};
use anyhow::Result;

fn create_account(
    client: &RpcClient,
    payer: &Keypair,
    new_account: &Keypair,
    owning_program: &Pubkey,
    space: u64,
) -> Result<()> {
    let rent = client.get_minimum_balance_for_rent_exemption(space.try_into()?)?;

    let transfer_instr = system_instruction::transfer(
        &payer.pubkey(),
        &new_account.pubkey(),
        rent,
    );

    let allocate_instr = system_instruction::allocate(
        &new_account.pubkey(),
        space,
    );

    let assign_instr = system_instruction::assign(
        &new_account.pubkey(),
        owning_program,
    );

    let blockhash = client.get_latest_blockhash()?;
    let tx = Transaction::new_signed_with_payer(
        &[transfer_instr, allocate_instr, assign_instr],
        Some(&payer.pubkey()),
        &[payer, new_account],
        blockhash,
    );

    let _sig = client.send_and_confirm_transaction(&tx)?;

    Ok(())
}

§Example: on-chain program

This example submits the instructions from an on-chain Solana program. The created account is a program derived address, funded by payer, and assigned to the running program. The payer and new_account_pda are signers, with new_account_pda being signed for virtually by the program itself via invoke_signed, payer being signed for by the client that submitted the transaction.

use solana_program::{
    account_info::{next_account_info, AccountInfo},
    entrypoint,
    entrypoint::ProgramResult,
    msg,
    program::invoke_signed,
    pubkey::Pubkey,
    system_instruction,
    system_program,
    sysvar::rent::Rent,
    sysvar::Sysvar,
};

#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct CreateAccountInstruction {
    /// The PDA seed used to distinguish the new account from other PDAs
    pub new_account_seed: [u8; 16],
    /// The PDA bump seed
    pub new_account_bump_seed: u8,
    /// The amount of space to allocate for `new_account_pda`
    pub space: u64,
}

entrypoint!(process_instruction);

fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    instruction_data: &[u8],
) -> ProgramResult {
    let instr = CreateAccountInstruction::deserialize(&mut &instruction_data[..])?;

    let account_info_iter = &mut accounts.iter();

    let payer = next_account_info(account_info_iter)?;
    let new_account_pda = next_account_info(account_info_iter)?;
    let system_account = next_account_info(account_info_iter)?;

    assert!(payer.is_signer);
    assert!(payer.is_writable);
    // Note that `new_account_pda` is not a signer yet.
    // This program will sign for it via `invoke_signed`.
    assert!(!new_account_pda.is_signer);
    assert!(new_account_pda.is_writable);
    assert!(system_program::check_id(system_account.key));

    let new_account_seed = &instr.new_account_seed;
    let new_account_bump_seed = instr.new_account_bump_seed;

    let rent = Rent::get()?
        .minimum_balance(instr.space.try_into().expect("overflow"));

    invoke_signed(
        &system_instruction::transfer(
            payer.key,
            new_account_pda.key,
            rent,
        ),
        &[payer.clone(), new_account_pda.clone()],
        &[&[payer.key.as_ref(), new_account_seed, &[new_account_bump_seed]]],
    )?;

    invoke_signed(
        &system_instruction::allocate(
            new_account_pda.key,
            instr.space,
        ),
        &[new_account_pda.clone()],
        &[&[payer.key.as_ref(), new_account_seed, &[new_account_bump_seed]]],
    )?;

    invoke_signed(
        &system_instruction::assign(
            new_account_pda.key,
            &program_id,
        ),
        &[new_account_pda.clone()],
        &[&[payer.key.as_ref(), new_account_seed, &[new_account_bump_seed]]],
    )?;

    Ok(())
}