ntoken-solana-models 0.2.50

Nova finance nToken
Documentation
//! State turing machine types
use crate::constants::account_type::{TYPE_ACCOUNT_TRIGGUER_TURING_MACHINE_ACCOUNT, TYPE_ACCOUNT_TURING_MACHINE_ACCOUNT};
use crate::constants::{
    account_size::SPLU_SECONDARY_STRUCT_LEN,
    account_size::TURING_MACHINE_ACCOUNT_PREFIX,
    constant::PUBKEY_SIZE
};
use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs};
use serde::{Deserialize, Serialize};
use solana_program::entrypoint::ProgramResult;
use solana_program::{
    program_error::ProgramError,
    program_pack::Sealed,
    pubkey::Pubkey,
};
use crate::error::PortfolioError;

const TYPE_SIZE: usize = 1;
const STATE_SIZE: usize = 1;
const AMOUNT_SIZE: usize = 8;
const VERSION_SIZE: usize = 1;
const DATE_SIZE:usize = 8;

/// struct of SPLU of turing
#[repr(C)]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct SpluStateSecondaryStruct {
    /// SPLU secondary address.
    pub splu_secondary_address: Pubkey,
    /// State of SPLU secondary.
    pub splu_state: u8,
    /// SPLU secondary address temploral.
    pub splu_secondary_temporal: Pubkey,
}

impl SpluStateSecondaryStruct {
    /// update the state of splu secondary.
    pub fn update_state_splu(&mut self) -> ProgramResult {
        self.splu_state = self
            .splu_state
            .checked_add(1)
            .ok_or(PortfolioError::InvalidState)?;

        Ok(())
    }

    /// Update the state of splu.
    pub fn update_state_splu_with_param(&mut self, state: u8) -> ProgramResult {
        self.splu_state = state;
        Ok(())
    }

    /// Reset the state of splu secondary.
    pub fn reset_splu_secondary(&mut self) -> ProgramResult {
        self.splu_state = 0;
        Ok(())
    }

     /// Update splu secondary temporal.
     pub fn update_splu_sec_tmp(&mut self, splu_sec_tmp: Pubkey) -> ProgramResult {
        self.splu_secondary_temporal = splu_sec_tmp;
        Ok(())
    }
}

/// Account data.
#[repr(C)]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct TuringMachineAccount {
    /// The type of account.
    pub type_account: u8,
    /// The owner of this account.
    pub owner: Pubkey,
    /// The user portfolio linked to this account.
    pub splm_n_asset: Pubkey,
    /// State of Turing account to know which step was completed.
    pub state: u8,
    /// Last amount deposited or withrawal.
    pub amount: u64,
    /// Version of Turing struct.
    pub version: u8,
    /// Save a specific date.
    pub date: i64,
    /// List of splu state contain the state of each splu secondary after swap [`SpluStateSecondaryStruct`].
    pub splu_state_list: Vec<SpluStateSecondaryStruct>,
}

impl Sealed for TuringMachineAccount {}

pub trait IsInitializedTuringMachine {
    /// Is initialized
    fn is_initialized(&self) -> bool;
}
impl IsInitializedTuringMachine for TuringMachineAccount {
   fn is_initialized(&self) -> bool {
       return (self.type_account == TYPE_ACCOUNT_TRIGGUER_TURING_MACHINE_ACCOUNT) || (self.type_account == TYPE_ACCOUNT_TURING_MACHINE_ACCOUNT);
   }
}
/// pack and unpack for turing account
pub trait PackTuringMachineAccount {
    /// unpack user portfolio
    fn unpack_turing_machine_account(src: &[u8]) -> Result<TuringMachineAccount, ProgramError>;
    /// pack user portfolio
    fn pack_turing_machine_account(&self, dst: &mut [u8]);
}

impl PackTuringMachineAccount for TuringMachineAccount {
    // unpack turing trigguer account

    fn unpack_turing_machine_account(src: &[u8]) -> Result<Self, ProgramError> {
        let numbre_splu_state =
            (&src.len() - TURING_MACHINE_ACCOUNT_PREFIX) / SPLU_SECONDARY_STRUCT_LEN;
        let len_splu_data = &src.len() - TURING_MACHINE_ACCOUNT_PREFIX;

        let src_fix = array_ref![&src, 0, TURING_MACHINE_ACCOUNT_PREFIX];

        let (type_account, owner, splm_n_asset, state, amount, version, date) = array_refs![
            src_fix,
            TYPE_SIZE,
            PUBKEY_SIZE,
            PUBKEY_SIZE,
            STATE_SIZE,
            AMOUNT_SIZE,
            VERSION_SIZE,
            DATE_SIZE
        ];

        let mut splu_vec: Vec<SpluStateSecondaryStruct> = Vec::with_capacity(numbre_splu_state);

        let list_splu_data = &src[TURING_MACHINE_ACCOUNT_PREFIX
            ..TURING_MACHINE_ACCOUNT_PREFIX + (len_splu_data) as usize];

        // Unpack list of splu struct.
        let mut offset = 0;
        for _ in 0..numbre_splu_state {
            let splu_secondary = array_ref![list_splu_data, offset, SPLU_SECONDARY_STRUCT_LEN];
            #[allow(clippy::ptr_offset_with_cast)]
            let (splu_secondary_address, splu_state,splu_secondary_temporal) = array_refs![splu_secondary, PUBKEY_SIZE, 1,PUBKEY_SIZE];
            splu_vec.push(SpluStateSecondaryStruct {
                splu_secondary_address: Pubkey::new_from_array(*splu_secondary_address),
                splu_state: u8::from_le_bytes(*splu_state),
                splu_secondary_temporal: Pubkey::new_from_array(*splu_secondary_temporal),
            });
            offset += SPLU_SECONDARY_STRUCT_LEN;
        }
        Ok(TuringMachineAccount {
            type_account: u8::from_le_bytes(*type_account),
            owner: Pubkey::new_from_array(*owner),
            splm_n_asset: Pubkey::new_from_array(*splm_n_asset),
            state: u8::from_le_bytes(*state),
            amount: u64::from_le_bytes(*amount),
            version: u8::from_le_bytes(*version),
            date: i64::from_le_bytes(*date),
            splu_state_list: splu_vec.to_vec(),
        })
    }

    // Pack turing machine account.
    fn pack_turing_machine_account(&self, dst: &mut [u8]) {
        let dst_tmp = array_mut_ref![dst, 0, TURING_MACHINE_ACCOUNT_PREFIX];
        let (type_account_dst, owner_dst, splm_n_asset_dst, state_dst, amount_dst, version_dst,date_dst) = mut_array_refs![
            dst_tmp,
            TYPE_SIZE,
            PUBKEY_SIZE,
            PUBKEY_SIZE,
            STATE_SIZE,
            AMOUNT_SIZE,
            VERSION_SIZE,
            DATE_SIZE
        ];
        let TuringMachineAccount {
            type_account,
            owner,
            splm_n_asset,
            state,
            amount,
            version,
            date,
            splu_state_list,
        } = self;

        let splu_vec_tmp = bincode::serialize(&splu_state_list).unwrap();
        let len_splu = splu_vec_tmp.len();
        let nbre_splu = (len_splu - 8) / SPLU_SECONDARY_STRUCT_LEN;
        let len_slu_reel = nbre_splu * SPLU_SECONDARY_STRUCT_LEN;
        let mut splu_data_tmp = [0; SPLU_SECONDARY_STRUCT_LEN * 10]; // maximum 10 splu

        splu_data_tmp[0..len_slu_reel as usize].clone_from_slice(&splu_vec_tmp[8..len_splu]); // 0..8 : 8 bytes contain length of struct

        *type_account_dst = type_account.to_le_bytes();
        owner_dst.copy_from_slice(owner.as_ref());
        splm_n_asset_dst.copy_from_slice(splm_n_asset.as_ref());
        *state_dst = state.to_le_bytes();
        *amount_dst = amount.to_le_bytes();
        *version_dst = version.to_le_bytes();
        *date_dst = date.to_le_bytes();
        dst[TURING_MACHINE_ACCOUNT_PREFIX..TURING_MACHINE_ACCOUNT_PREFIX + len_slu_reel as usize]
            .copy_from_slice(&splu_data_tmp[0..len_slu_reel]);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::constants::account_type::TYPE_ACCOUNT_TURING_MACHINE_ACCOUNT;

    #[test]
    fn test_pack_turing_account() {
        let type_account = TYPE_ACCOUNT_TURING_MACHINE_ACCOUNT;
        let owner = Pubkey::new_unique();
        let state = 0;
        let splm_n_asset = Pubkey::new_unique();
        let amount = 2;
        let version = 1;
        let date = 234;

        let splu_struct = SpluStateSecondaryStruct {
            splu_secondary_address: Pubkey::new_unique(),
            splu_state: 0,
            splu_secondary_temporal: Pubkey::new_unique(),
        };

        let mut splu_state_list = Vec::new();
        splu_state_list.push(splu_struct);
        let turing = TuringMachineAccount {
            type_account,
            owner,
            splm_n_asset,
            state,
            amount,
            version,
            date,
            splu_state_list,
        };

        const LEN: usize = TURING_MACHINE_ACCOUNT_PREFIX + (SPLU_SECONDARY_STRUCT_LEN * 1); // 204: @préfix + 164:splu_len * 1
        let mut packed = [0u8; LEN];

        TuringMachineAccount::pack_turing_machine_account(&turing, &mut packed[..]);
        let unpacked = TuringMachineAccount::unpack_turing_machine_account(&packed).unwrap();
        assert_eq!(turing, unpacked);
        assert_eq!(unpacked.type_account, TYPE_ACCOUNT_TURING_MACHINE_ACCOUNT);
    }
}