use light_compressed_account::TreeType;
use light_token::compat::TokenData;
use solana_account::Account;
use solana_pubkey::Pubkey;
use super::super::{base58::decode_base58_to_fixed_array, IndexerError};
pub type SolanaAccountData = Account;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct InterfaceTreeInfo {
pub tree: Pubkey,
pub queue: Pubkey,
pub tree_type: TreeType,
pub seq: Option<u64>,
pub slot_created: u64,
}
#[derive(Clone, Debug, PartialEq)]
pub struct ColdData {
pub discriminator: [u8; 8],
pub data: Vec<u8>,
pub data_hash: [u8; 32],
}
#[derive(Clone, Debug, PartialEq)]
pub struct ColdContext {
pub hash: [u8; 32],
pub leaf_index: u64,
pub tree_info: InterfaceTreeInfo,
pub data: ColdData,
pub address: Option<[u8; 32]>,
pub prove_by_index: bool,
}
fn decode_tree_info_v2(
merkle_ctx: &photon_api::types::MerkleContextV2,
seq: Option<u64>,
slot_created: u64,
) -> Result<InterfaceTreeInfo, IndexerError> {
let tree = Pubkey::new_from_array(decode_base58_to_fixed_array(&merkle_ctx.tree)?);
let queue = Pubkey::new_from_array(decode_base58_to_fixed_array(&merkle_ctx.queue)?);
let tree_type = TreeType::from(merkle_ctx.tree_type as u64);
Ok(InterfaceTreeInfo {
tree,
queue,
tree_type,
seq,
slot_created,
})
}
fn decode_account_data(data: &photon_api::types::AccountData) -> Result<ColdData, IndexerError> {
let disc_val = *data.discriminator;
let discriminator = disc_val.to_le_bytes();
Ok(ColdData {
discriminator,
data: base64::decode_config(&*data.data, base64::STANDARD_NO_PAD)
.map_err(|e| IndexerError::decode_error("data", e))?,
data_hash: decode_base58_to_fixed_array(&data.data_hash)?,
})
}
fn convert_account_v2(av2: &photon_api::types::AccountV2) -> Result<ColdContext, IndexerError> {
let tree_info = decode_tree_info_v2(
&av2.merkle_context,
av2.seq.as_ref().map(|s| **s),
*av2.slot_created,
)?;
let data = match &av2.data {
Some(d) => decode_account_data(d)?,
None => ColdData {
discriminator: [0u8; 8],
data: Vec::new(),
data_hash: [0u8; 32],
},
};
let address = av2
.address
.as_ref()
.map(|a| decode_base58_to_fixed_array(a))
.transpose()?;
Ok(ColdContext {
hash: decode_base58_to_fixed_array(&av2.hash)?,
leaf_index: *av2.leaf_index,
tree_info,
data,
address,
prove_by_index: av2.prove_by_index,
})
}
#[derive(Clone, Debug, PartialEq)]
pub struct AccountInterface {
pub key: Pubkey,
pub account: SolanaAccountData,
pub cold: Option<ColdContext>,
}
impl AccountInterface {
pub fn is_hot(&self) -> bool {
self.cold.is_none()
}
pub fn is_cold(&self) -> bool {
self.cold.is_some()
}
}
fn convert_account_interface(
ai: &photon_api::types::AccountInterface,
) -> Result<AccountInterface, IndexerError> {
let cold = ai
.cold
.as_ref()
.and_then(|entries| entries.first())
.map(convert_account_v2)
.transpose()?;
let data = base64::decode_config(&*ai.account.data, base64::STANDARD_NO_PAD)
.map_err(|e| IndexerError::decode_error("account.data", e))?;
Ok(AccountInterface {
key: Pubkey::new_from_array(decode_base58_to_fixed_array(&ai.key)?),
account: Account {
lamports: *ai.account.lamports,
data,
owner: Pubkey::new_from_array(decode_base58_to_fixed_array(&ai.account.owner)?),
executable: ai.account.executable,
rent_epoch: *ai.account.rent_epoch,
},
cold,
})
}
impl TryFrom<&photon_api::types::AccountInterface> for AccountInterface {
type Error = IndexerError;
fn try_from(ai: &photon_api::types::AccountInterface) -> Result<Self, Self::Error> {
convert_account_interface(ai)
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct TokenAccountInterface {
pub account: AccountInterface,
pub token: TokenData,
}