solana_sdk::system_instruction

Function transfer_many

source
pub fn transfer_many(
    from_pubkey: &Pubkey,
    to_lamports: &[(Pubkey, u64)],
) -> Vec<Instruction>
Expand description

Transfer lamports from an account owned by the system program to multiple accounts.

This function produces a vector of Instructions which must be submitted in a Transaction or invoked to take effect, containing serialized SystemInstruction::Transfers.

§Required signers

The from_pubkey signer must sign the transaction.

§Examples

§Example: client-side RPC

This example performs multiple transfers in a single transaction.

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

fn transfer_lamports_to_many(
    client: &RpcClient,
    from: &Keypair,
    to_and_amount: &[(Pubkey, u64)],
) -> Result<()> {
    let instrs = system_instruction::transfer_many(&from.pubkey(), to_and_amount);

    let blockhash = client.get_latest_blockhash()?;
    let tx = Transaction::new_signed_with_payer(
        &instrs,
        Some(&from.pubkey()),
        &[from],
        blockhash,
    );

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

    Ok(())
}

§Example: on-chain program

This example makes multiple transfers out of a “bank” account, a program derived address owned by the calling program. This example submits the instructions from an on-chain Solana program. The created account is a program derived address, and it is 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, next_account_infos, AccountInfo},
    entrypoint,
    entrypoint::ProgramResult,
    msg,
    program::invoke_signed,
    pubkey::Pubkey,
    system_instruction,
    system_program,
};

/// # Accounts
///
/// - 0: bank_pda - writable
/// - 1: system_program - executable
/// - *: to - writable
#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct TransferLamportsToManyInstruction {
    pub bank_pda_bump_seed: u8,
    pub amount_list: Vec<u64>,
}

entrypoint!(process_instruction);

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

    let account_info_iter = &mut accounts.iter();

    let bank_pda = next_account_info(account_info_iter)?;
    let bank_pda_bump_seed = instr.bank_pda_bump_seed;
    let system_account = next_account_info(account_info_iter)?;

    assert!(system_program::check_id(system_account.key));

    let to_accounts = next_account_infos(account_info_iter, account_info_iter.len())?;

    for to_account in to_accounts {
         assert!(to_account.is_writable);
         // ... do other verification ...
    }

    let to_and_amount = to_accounts
        .iter()
        .zip(instr.amount_list.iter())
        .map(|(to, amount)| (*to.key, *amount))
        .collect::<Vec<(Pubkey, u64)>>();

    let instrs = system_instruction::transfer_many(bank_pda.key, to_and_amount.as_ref());

    for instr in instrs {
        invoke_signed(&instr, accounts, &[&[b"bank", &[bank_pda_bump_seed]]])?;
    }

    Ok(())
}