manifest/
utils.rs

1use solana_program::{
2    account_info::AccountInfo, entrypoint::ProgramResult, keccak, program::invoke_signed,
3    program_error::ProgramError, pubkey::Pubkey, rent::Rent, system_instruction,
4};
5
6/// Canonical discriminant of the given struct. It is the hash of program ID and
7/// the name of the type.
8pub fn get_discriminant<T>() -> Result<u64, ProgramError> {
9    let type_name: &str = std::any::type_name::<T>();
10    let discriminant: u64 = u64::from_le_bytes(
11        keccak::hashv(&[crate::ID.as_ref(), type_name.as_bytes()]).as_ref()[..8]
12            .try_into()
13            .map_err(|_| ProgramError::InvalidAccountData)?,
14    );
15    Ok(discriminant)
16}
17
18/// Send CPI for creating a new account on chain.
19pub fn create_account<'a, 'info>(
20    payer: &'a AccountInfo<'info>,
21    new_account: &'a AccountInfo<'info>,
22    system_program: &'a AccountInfo<'info>,
23    program_owner: &Pubkey,
24    rent: &Rent,
25    space: u64,
26    seeds: Vec<Vec<u8>>,
27) -> ProgramResult {
28    invoke_signed(
29        &system_instruction::create_account(
30            payer.key,
31            new_account.key,
32            rent.minimum_balance(space as usize),
33            space,
34            program_owner,
35        ),
36        &[payer.clone(), new_account.clone(), system_program.clone()],
37        &[seeds
38            .iter()
39            .map(|seed| seed.as_slice())
40            .collect::<Vec<&[u8]>>()
41            .as_slice()],
42    )
43}
44
45#[test]
46fn test_get_discriminant() {
47    // Update this when updating program id.
48    assert_eq!(
49        get_discriminant::<crate::state::MarketFixed>().unwrap(),
50        4859840929024028656
51    );
52}