use crate::solana_lib::solana_program::program_error::ProgramError;
use crate::solana_lib::solana_program::program_pack::{Pack, Sealed};
use crate::solana_lib::spl::token_swap::curve::calculator::CurveCalculator;
use crate::solana_lib::spl::token_swap::curve::constant_price::ConstantPriceCurve;
use crate::solana_lib::spl::token_swap::curve::constant_product::ConstantProductCurve;
use crate::solana_lib::spl::token_swap::curve::offset::OffsetCurve;
use crate::solana_lib::spl::token_swap::curve::stable::StableCurve;
use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs};
use std::sync::Arc;
#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CurveType {
ConstantProduct,
ConstantPrice,
Stable,
Offset,
}
#[repr(C)]
#[derive(Debug)]
pub struct SwapCurve {
pub curve_type: CurveType,
pub calculator: Arc<dyn CurveCalculator + Sync + Send>,
}
impl Sealed for SwapCurve {}
impl Pack for SwapCurve {
const LEN: usize = 33;
fn unpack_from_slice(input: &[u8]) -> Result<Self, ProgramError> {
let input = array_ref![input, 0, 33];
#[allow(clippy::ptr_offset_with_cast)]
let (curve_type, calculator) = array_refs![input, 1, 32];
let curve_type = curve_type[0].try_into()?;
Ok(Self {
curve_type,
calculator: match curve_type {
CurveType::ConstantProduct => {
Arc::new(ConstantProductCurve::unpack_from_slice(calculator)?)
}
CurveType::ConstantPrice => {
Arc::new(ConstantPriceCurve::unpack_from_slice(calculator)?)
}
CurveType::Stable => Arc::new(StableCurve::unpack_from_slice(calculator)?),
CurveType::Offset => Arc::new(OffsetCurve::unpack_from_slice(calculator)?),
},
})
}
fn pack_into_slice(&self, output: &mut [u8]) {
let output = array_mut_ref![output, 0, 33];
let (curve_type, calculator) = mut_array_refs![output, 1, 32];
curve_type[0] = self.curve_type as u8;
self.calculator.pack_into_slice(&mut calculator[..]);
}
}
impl TryFrom<u8> for CurveType {
type Error = ProgramError;
fn try_from(curve_type: u8) -> Result<Self, Self::Error> {
match curve_type {
0 => Ok(CurveType::ConstantProduct),
1 => Ok(CurveType::ConstantPrice),
2 => Ok(CurveType::Stable),
3 => Ok(CurveType::Offset),
_ => Err(ProgramError::InvalidAccountData),
}
}
}