use anchor_lang::Result;
use crate::math::{casting::Cast, safe_math::SafeMath};
use super::errors::ErrorCodes;
pub const MIN_TICK: i32 = -16383;
pub const MAX_TICK: i32 = 16383;
pub const TICK_HAS_DEBT_ARRAY_SIZE: usize = 8;
pub const TICK_HAS_DEBT_CHILDREN_SIZE: usize = 32; pub const BIT_PER_BYTE: usize = 8;
pub const TICK_HAS_DEBT_CHILDREN_SIZE_IN_BITS: usize = TICK_HAS_DEBT_CHILDREN_SIZE * BIT_PER_BYTE;
pub const TICKS_PER_TICK_HAS_DEBT: usize =
TICK_HAS_DEBT_ARRAY_SIZE * TICK_HAS_DEBT_CHILDREN_SIZE_IN_BITS;
pub const TOTAL_INDICES_NEEDED: usize = 16;
pub fn get_array_index_for_tick(tick: i32) -> Result<u8> {
if tick < MIN_TICK || tick > MAX_TICK {
return Err(ErrorCodes::VaultTickHasDebtOutOfRange.into());
}
let tick_offset = tick.safe_sub(MIN_TICK)?;
let index = (tick_offset / TICKS_PER_TICK_HAS_DEBT as i32) as u8;
Ok(index)
}
pub fn get_tick_indices_for_array(tick: i32, array_index: u8) -> Result<(u8, u8, u8)> {
if tick < MIN_TICK || tick > MAX_TICK {
return Err(ErrorCodes::VaultTickHasDebtOutOfRange.into());
}
let expected_index = get_array_index_for_tick(tick)?;
if expected_index != array_index {
return Err(ErrorCodes::VaultTickHasDebtIndexMismatch.into());
}
let first_tick_for_index = get_first_tick_for_array_index(array_index)?;
let tick_within_array = tick.safe_sub(first_tick_for_index)?;
if tick_within_array >= TICKS_PER_TICK_HAS_DEBT as i32 {
return Err(ErrorCodes::VaultTickHasDebtOutOfRange.into());
}
let map_index =
(tick_within_array / TICK_HAS_DEBT_CHILDREN_SIZE_IN_BITS as i32).cast::<u8>()?;
let tick_within_map = tick_within_array % TICK_HAS_DEBT_CHILDREN_SIZE_IN_BITS as i32;
let byte_index = (tick_within_map / BIT_PER_BYTE as i32).cast::<u8>()?;
let bit_index = (tick_within_map % BIT_PER_BYTE as i32).cast::<u8>()?;
Ok((map_index, byte_index, bit_index))
}
pub fn get_first_tick_for_array_index(index: u8) -> Result<i32> {
if index >= TOTAL_INDICES_NEEDED as u8 {
return Err(ErrorCodes::VaultTickHasDebtOutOfRange.into());
}
Ok(MIN_TICK.safe_add((index as i32).safe_mul(TICKS_PER_TICK_HAS_DEBT as i32)?)?)
}
pub fn get_tick_indices(tick: i32) -> Result<(u8, usize, usize, usize)> {
let array_index = get_array_index_for_tick(tick)?;
let (map_index, byte_index, bit_index) = get_tick_indices_for_array(tick, array_index)?;
Ok((
array_index,
map_index.cast()?,
byte_index.cast()?,
bit_index.cast()?,
))
}