solana_sdk::system_instruction

Function create_account

source
pub fn create_account(
    from_pubkey: &Pubkey,
    to_pubkey: &Pubkey,
    lamports: u64,
    space: u64,
    owner: &Pubkey,
) -> Instruction
Expand description

Create an account.

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

Account creation typically involves three steps: allocate space, transfer lamports for rent, assign to its owning program. The create_account function does all three at once.

§Required signers

The from_pubkey and to_pubkey signers must sign the transaction.

§Examples

These examples use a single invocation of SystemInstruction::CreateAccount to create a new account, allocate some space, transfer it the minimum lamports for rent exemption, and assign it to the system program,

§Example: client-side RPC

This example submits the instruction from an RPC client. The payer and new_account are signers.

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

fn create_account(
    client: &RpcClient,
    payer: &Keypair,
    new_account: &Keypair,
    space: u64,
) -> Result<()> {
    let rent = client.get_minimum_balance_for_rent_exemption(space.try_into()?)?;
    let instr = system_instruction::create_account(
        &payer.pubkey(),
        &new_account.pubkey(),
        rent,
        space,
        &system_program::ID,
    );

    let blockhash = client.get_latest_blockhash()?;
    let tx = Transaction::new_signed_with_payer(
        &[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 instruction from an on-chain Solana program. The created account is a program derived address. 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::create_account(
            payer.key,
            new_account_pda.key,
            rent,
            instr.space,
            &system_program::ID
        ),
        &[payer.clone(), new_account_pda.clone()],
        &[&[payer.key.as_ref(), new_account_seed, &[new_account_bump_seed]]],
    )?;

    Ok(())
}