use solana_program::{
account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult,
program_error::ProgramError, pubkey::Pubkey, sysvar::Sysvar,
};
pub const DEFAULT_TTL: u64 = 150;
pub struct Arguments<'a, 'b> {
pub to: &'b AccountInfo<'a>,
pub from: &'b AccountInfo<'a>,
pub lamports: u64,
pub space: u64,
pub owner: Option<Pubkey>,
pub slot: u64,
}
pub fn create_account(program_id: &Pubkey, arguments: Arguments) -> ProgramResult {
_create_account(program_id, arguments, None, DEFAULT_TTL)
}
pub fn create_account_with_seeds(
program_id: &Pubkey,
arguments: Arguments,
seeds: &[&[u8]],
) -> ProgramResult {
_create_account(program_id, arguments, Some(seeds), DEFAULT_TTL)
}
pub fn create_account_with_ttl(
program_id: &Pubkey,
arguments: Arguments,
ttl: u64,
) -> ProgramResult {
_create_account(program_id, arguments, None, ttl)
}
pub fn create_account_with_seeds_and_ttl(
program_id: &Pubkey,
arguments: Arguments,
seeds: &[&[u8]],
ttl: u64,
) -> ProgramResult {
_create_account(program_id, arguments, Some(seeds), ttl)
}
#[inline(always)]
fn _create_account(
program_id: &Pubkey,
arguments: Arguments,
seeds: Option<&[&[u8]]>,
ttl: u64,
) -> ProgramResult {
let currrent_slot = Clock::get()?.slot;
if currrent_slot > arguments.slot + ttl {
return Err(ProgramError::InvalidArgument);
}
let slot_seeds = arguments.slot.to_le_bytes();
let mut seeds = if let Some(seeds) = seeds {
let mut seeds_with_slot = Vec::with_capacity(seeds.len() + 3);
seeds_with_slot.push(arguments.from.key.as_ref());
seeds_with_slot.push(&slot_seeds);
seeds_with_slot.extend_from_slice(seeds);
seeds_with_slot
} else {
let mut seeds_with_slot = Vec::with_capacity(3);
seeds_with_slot.extend_from_slice(&[arguments.from.key.as_ref(), &slot_seeds]);
seeds_with_slot
};
let (address, bump) = Pubkey::find_program_address(&seeds, program_id);
if arguments.to.key != &address {
return Err(ProgramError::InvalidSeeds);
}
let signer_bump = [bump];
seeds.push(&signer_bump);
solana_program::program::invoke_signed(
&solana_program::system_instruction::create_account(
arguments.from.key,
arguments.to.key,
arguments.lamports,
arguments.space,
arguments.owner.as_ref().unwrap_or(program_id),
),
&[arguments.from.clone(), arguments.to.clone()],
&[&seeds],
)
}