use alloy_primitives::U256;
use crate::evm::protocol::curve::math::swap;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PoolError {
NotApplicable,
IndexOutOfRange,
}
impl std::fmt::Display for PoolError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::NotApplicable => f.write_str("field not applicable to this pool variant"),
Self::IndexOutOfRange => f.write_str("index out of range"),
}
}
}
impl std::error::Error for PoolError {}
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum Pool {
StableSwapV0 { balances: Vec<U256>, rates: Vec<U256>, amp: U256, fee: U256 },
StableSwapV1 { balances: Vec<U256>, rates: Vec<U256>, amp: U256, fee: U256 },
StableSwapV2 { balances: Vec<U256>, rates: Vec<U256>, amp: U256, fee: U256 },
StableSwapSTETH { balances: Vec<U256>, rates: Vec<U256>, amp: U256, fee: U256 },
StableSwapALend {
balances: Vec<U256>,
precision_mul: Vec<U256>,
amp: U256,
fee: U256,
offpeg_fee_multiplier: U256,
},
StableSwapNG {
balances: Vec<U256>,
rates: Vec<U256>,
amp: U256,
fee: U256,
offpeg_fee_multiplier: U256,
},
StableSwapMeta { balances: Vec<U256>, rates: Vec<U256>, amp: U256, fee: U256 },
TwoCryptoV1 {
balances: [U256; 2],
precisions: [U256; 2],
price_scale: U256,
d: U256,
ann: U256,
gamma: U256,
mid_fee: U256,
out_fee: U256,
fee_gamma: U256,
eth_variant: bool,
},
TwoCryptoNG {
balances: [U256; 2],
precisions: [U256; 2],
price_scale: U256,
d: U256,
ann: U256,
gamma: U256,
mid_fee: U256,
out_fee: U256,
fee_gamma: U256,
},
TwoCryptoStable {
balances: [U256; 2],
precisions: [U256; 2],
price_scale: U256,
d: U256,
ann: U256,
mid_fee: U256,
out_fee: U256,
fee_gamma: U256,
},
TriCryptoV1 {
balances: [U256; 3],
precisions: [U256; 3],
price_scale: [U256; 2],
d: U256,
ann: U256,
gamma: U256,
mid_fee: U256,
out_fee: U256,
fee_gamma: U256,
},
TriCryptoNG {
balances: [U256; 3],
precisions: [U256; 3],
price_scale: [U256; 2],
d: U256,
ann: U256,
gamma: U256,
mid_fee: U256,
out_fee: U256,
fee_gamma: U256,
},
}
impl Pool {
pub fn balances(&self) -> &[U256] {
match self {
Pool::StableSwapV0 { balances, .. } |
Pool::StableSwapV1 { balances, .. } |
Pool::StableSwapV2 { balances, .. } |
Pool::StableSwapSTETH { balances, .. } |
Pool::StableSwapALend { balances, .. } |
Pool::StableSwapNG { balances, .. } |
Pool::StableSwapMeta { balances, .. } => balances,
Pool::TwoCryptoV1 { balances, .. } |
Pool::TwoCryptoNG { balances, .. } |
Pool::TwoCryptoStable { balances, .. } => balances,
Pool::TriCryptoV1 { balances, .. } | Pool::TriCryptoNG { balances, .. } => balances,
}
}
pub fn get_amount_out(&self, i: usize, j: usize, dx: U256) -> Option<U256> {
match self {
Pool::StableSwapV0 { balances, rates, amp, fee } => {
swap::stableswap_v0::get_amount_out(balances, rates, *amp, *fee, i, j, dx)
}
Pool::StableSwapV1 { balances, rates, amp, fee } => {
swap::stableswap_v1::get_amount_out(balances, rates, *amp, *fee, i, j, dx)
}
Pool::StableSwapV2 { balances, rates, amp, fee } => {
swap::stableswap_v2::get_amount_out(balances, rates, *amp, *fee, i, j, dx)
}
Pool::StableSwapSTETH { balances, rates, amp, fee } => {
swap::stableswap_steth::get_amount_out(balances, rates, *amp, *fee, i, j, dx)
}
Pool::StableSwapALend { balances, precision_mul, amp, fee, offpeg_fee_multiplier } => {
swap::stableswap_alend::get_amount_out(
balances,
precision_mul,
*amp,
*fee,
*offpeg_fee_multiplier,
i,
j,
dx,
)
}
Pool::StableSwapNG { balances, rates, amp, fee, offpeg_fee_multiplier } => {
swap::stableswap_ng::get_amount_out(
balances,
rates,
*amp,
*fee,
*offpeg_fee_multiplier,
i,
j,
dx,
)
}
Pool::StableSwapMeta { balances, rates, amp, fee } => {
swap::stableswap_meta::get_amount_out(balances, rates, *amp, *fee, i, j, dx)
}
Pool::TwoCryptoV1 {
balances,
precisions,
price_scale,
d,
ann,
gamma,
mid_fee,
out_fee,
fee_gamma,
eth_variant,
} => swap::twocrypto_v1::get_amount_out(
balances,
precisions,
*price_scale,
*d,
*ann,
*gamma,
*mid_fee,
*out_fee,
*fee_gamma,
*eth_variant,
i,
j,
dx,
),
Pool::TwoCryptoNG {
balances,
precisions,
price_scale,
d,
ann,
gamma,
mid_fee,
out_fee,
fee_gamma,
} => swap::twocrypto_ng::get_amount_out(
balances,
precisions,
*price_scale,
*d,
*ann,
*gamma,
*mid_fee,
*out_fee,
*fee_gamma,
i,
j,
dx,
),
Pool::TwoCryptoStable {
balances,
precisions,
price_scale,
d,
ann,
mid_fee,
out_fee,
fee_gamma,
} => swap::twocrypto_stable::get_amount_out(
balances,
precisions,
*price_scale,
*d,
*ann,
*mid_fee,
*out_fee,
*fee_gamma,
i,
j,
dx,
),
Pool::TriCryptoV1 {
balances,
precisions,
price_scale,
d,
ann,
gamma,
mid_fee,
out_fee,
fee_gamma,
} => swap::tricrypto_v1::get_amount_out(
balances,
precisions,
price_scale,
*d,
*ann,
*gamma,
*mid_fee,
*out_fee,
*fee_gamma,
i,
j,
dx,
),
Pool::TriCryptoNG {
balances,
precisions,
price_scale,
d,
ann,
gamma,
mid_fee,
out_fee,
fee_gamma,
} => swap::tricrypto_ng::get_amount_out(
balances,
precisions,
price_scale,
*d,
*ann,
*gamma,
*mid_fee,
*out_fee,
*fee_gamma,
i,
j,
dx,
),
}
}
pub fn get_amount_in(&self, i: usize, j: usize, desired_output: U256) -> Option<U256> {
match self {
Pool::StableSwapV0 { balances, rates, amp, fee } => swap::stableswap_v0::get_amount_in(
balances,
rates,
*amp,
*fee,
i,
j,
desired_output,
),
Pool::StableSwapV1 { balances, rates, amp, fee } => swap::stableswap_v1::get_amount_in(
balances,
rates,
*amp,
*fee,
i,
j,
desired_output,
),
Pool::StableSwapV2 { balances, rates, amp, fee } => swap::stableswap_v2::get_amount_in(
balances,
rates,
*amp,
*fee,
i,
j,
desired_output,
),
Pool::StableSwapSTETH { balances, rates, amp, fee } => {
swap::stableswap_steth::get_amount_in(
balances,
rates,
*amp,
*fee,
i,
j,
desired_output,
)
}
Pool::StableSwapALend { balances, precision_mul, amp, fee, offpeg_fee_multiplier } => {
swap::stableswap_alend::get_amount_in(
balances,
precision_mul,
*amp,
*fee,
*offpeg_fee_multiplier,
i,
j,
desired_output,
)
}
Pool::StableSwapNG { balances, rates, amp, fee, offpeg_fee_multiplier } => {
swap::stableswap_ng::get_amount_in(
balances,
rates,
*amp,
*fee,
*offpeg_fee_multiplier,
i,
j,
desired_output,
)
}
Pool::StableSwapMeta { balances, rates, amp, fee } => {
swap::stableswap_meta::get_amount_in(
balances,
rates,
*amp,
*fee,
i,
j,
desired_output,
)
}
Pool::TwoCryptoV1 {
balances,
precisions,
price_scale,
d,
ann,
gamma,
mid_fee,
out_fee,
fee_gamma,
eth_variant,
} => swap::twocrypto_v1::get_amount_in(
balances,
precisions,
*price_scale,
*d,
*ann,
*gamma,
*mid_fee,
*out_fee,
*fee_gamma,
*eth_variant,
i,
j,
desired_output,
),
Pool::TwoCryptoNG {
balances,
precisions,
price_scale,
d,
ann,
gamma,
mid_fee,
out_fee,
fee_gamma,
} => swap::twocrypto_ng::get_amount_in(
balances,
precisions,
*price_scale,
*d,
*ann,
*gamma,
*mid_fee,
*out_fee,
*fee_gamma,
i,
j,
desired_output,
),
Pool::TwoCryptoStable {
balances,
precisions,
price_scale,
d,
ann,
mid_fee,
out_fee,
fee_gamma,
} => swap::twocrypto_stable::get_amount_in(
balances,
precisions,
*price_scale,
*d,
*ann,
*mid_fee,
*out_fee,
*fee_gamma,
i,
j,
desired_output,
),
Pool::TriCryptoV1 {
balances,
precisions,
price_scale,
d,
ann,
gamma,
mid_fee,
out_fee,
fee_gamma,
} => swap::tricrypto_v1::get_amount_in(
balances,
precisions,
price_scale,
*d,
*ann,
*gamma,
*mid_fee,
*out_fee,
*fee_gamma,
i,
j,
desired_output,
),
Pool::TriCryptoNG {
balances,
precisions,
price_scale,
d,
ann,
gamma,
mid_fee,
out_fee,
fee_gamma,
} => swap::tricrypto_ng::get_amount_in(
balances,
precisions,
price_scale,
*d,
*ann,
*gamma,
*mid_fee,
*out_fee,
*fee_gamma,
i,
j,
desired_output,
),
}
}
pub fn spot_price(&self, i: usize, j: usize) -> Option<(U256, U256)> {
match self {
Pool::StableSwapV0 { balances, rates, amp, fee } => {
swap::stableswap_v0::spot_price(balances, rates, *amp, *fee, i, j)
}
Pool::StableSwapV1 { balances, rates, amp, fee } => {
swap::stableswap_v1::spot_price(balances, rates, *amp, *fee, i, j)
}
Pool::StableSwapV2 { balances, rates, amp, fee } => {
swap::stableswap_v2::spot_price(balances, rates, *amp, *fee, i, j)
}
Pool::StableSwapSTETH { balances, rates, amp, fee } => {
swap::stableswap_steth::spot_price(balances, rates, *amp, *fee, i, j)
}
Pool::StableSwapALend { balances, precision_mul, amp, fee, offpeg_fee_multiplier } => {
swap::stableswap_alend::spot_price(
balances,
precision_mul,
*amp,
*fee,
*offpeg_fee_multiplier,
i,
j,
)
}
Pool::StableSwapNG { balances, rates, amp, fee, offpeg_fee_multiplier } => {
swap::stableswap_ng::spot_price(
balances,
rates,
*amp,
*fee,
*offpeg_fee_multiplier,
i,
j,
)
}
Pool::StableSwapMeta { balances, rates, amp, fee } => {
swap::stableswap_meta::spot_price(balances, rates, *amp, *fee, i, j)
}
Pool::TwoCryptoV1 {
balances,
precisions,
price_scale,
d,
ann,
gamma,
mid_fee,
out_fee,
fee_gamma,
eth_variant,
} => swap::twocrypto_v1::spot_price(
balances,
precisions,
*price_scale,
*d,
*ann,
*gamma,
*mid_fee,
*out_fee,
*fee_gamma,
*eth_variant,
i,
j,
),
Pool::TwoCryptoNG {
balances,
precisions,
price_scale,
d,
ann,
gamma,
mid_fee,
out_fee,
fee_gamma,
} => swap::twocrypto_ng::spot_price(
balances,
precisions,
*price_scale,
*d,
*ann,
*gamma,
*mid_fee,
*out_fee,
*fee_gamma,
i,
j,
),
Pool::TwoCryptoStable {
balances,
precisions,
price_scale,
d,
ann,
mid_fee,
out_fee,
fee_gamma,
} => swap::twocrypto_stable::spot_price(
balances,
precisions,
*price_scale,
*d,
*ann,
*mid_fee,
*out_fee,
*fee_gamma,
i,
j,
),
Pool::TriCryptoV1 {
balances,
precisions,
price_scale,
d,
ann,
gamma,
mid_fee,
out_fee,
fee_gamma,
} => swap::tricrypto_v1::spot_price(
balances,
precisions,
price_scale,
*d,
*ann,
*gamma,
*mid_fee,
*out_fee,
*fee_gamma,
i,
j,
),
Pool::TriCryptoNG {
balances,
precisions,
price_scale,
d,
ann,
gamma,
mid_fee,
out_fee,
fee_gamma,
} => swap::tricrypto_ng::spot_price(
balances,
precisions,
price_scale,
*d,
*ann,
*gamma,
*mid_fee,
*out_fee,
*fee_gamma,
i,
j,
),
}
}
pub fn amp(&self) -> U256 {
match self {
Pool::StableSwapV0 { amp, .. } |
Pool::StableSwapV1 { amp, .. } |
Pool::StableSwapV2 { amp, .. } |
Pool::StableSwapSTETH { amp, .. } |
Pool::StableSwapALend { amp, .. } |
Pool::StableSwapNG { amp, .. } |
Pool::StableSwapMeta { amp, .. } => *amp,
Pool::TwoCryptoV1 { ann, .. } |
Pool::TwoCryptoNG { ann, .. } |
Pool::TwoCryptoStable { ann, .. } => *ann,
Pool::TriCryptoV1 { ann, .. } | Pool::TriCryptoNG { ann, .. } => *ann,
}
}
pub fn fee(&self) -> Option<U256> {
match self {
Pool::StableSwapV0 { fee, .. } |
Pool::StableSwapV1 { fee, .. } |
Pool::StableSwapV2 { fee, .. } |
Pool::StableSwapSTETH { fee, .. } |
Pool::StableSwapALend { fee, .. } |
Pool::StableSwapNG { fee, .. } |
Pool::StableSwapMeta { fee, .. } => Some(*fee),
_ => None,
}
}
pub fn crypto_fees(&self) -> Option<(U256, U256, U256)> {
match self {
Pool::TwoCryptoV1 { mid_fee, out_fee, fee_gamma, .. } |
Pool::TwoCryptoNG { mid_fee, out_fee, fee_gamma, .. } |
Pool::TwoCryptoStable { mid_fee, out_fee, fee_gamma, .. } |
Pool::TriCryptoV1 { mid_fee, out_fee, fee_gamma, .. } |
Pool::TriCryptoNG { mid_fee, out_fee, fee_gamma, .. } => {
Some((*mid_fee, *out_fee, *fee_gamma))
}
_ => None,
}
}
pub fn rates(&self) -> Option<&[U256]> {
match self {
Pool::StableSwapV0 { rates, .. } |
Pool::StableSwapV1 { rates, .. } |
Pool::StableSwapV2 { rates, .. } |
Pool::StableSwapSTETH { rates, .. } |
Pool::StableSwapNG { rates, .. } |
Pool::StableSwapMeta { rates, .. } => Some(rates),
_ => None,
}
}
pub fn d(&self) -> Option<U256> {
match self {
Pool::TwoCryptoV1 { d, .. } |
Pool::TwoCryptoNG { d, .. } |
Pool::TwoCryptoStable { d, .. } => Some(*d),
Pool::TriCryptoV1 { d, .. } | Pool::TriCryptoNG { d, .. } => Some(*d),
_ => None,
}
}
pub fn gamma(&self) -> Option<U256> {
match self {
Pool::TwoCryptoV1 { gamma, .. } | Pool::TwoCryptoNG { gamma, .. } => Some(*gamma),
Pool::TriCryptoV1 { gamma, .. } | Pool::TriCryptoNG { gamma, .. } => Some(*gamma),
_ => None,
}
}
pub fn precision_mul(&self) -> Option<&[U256]> {
match self {
Pool::StableSwapALend { precision_mul, .. } => Some(precision_mul),
_ => None,
}
}
pub fn precisions(&self) -> Option<&[U256]> {
match self {
Pool::TwoCryptoV1 { precisions, .. } |
Pool::TwoCryptoNG { precisions, .. } |
Pool::TwoCryptoStable { precisions, .. } => Some(precisions),
Pool::TriCryptoV1 { precisions, .. } | Pool::TriCryptoNG { precisions, .. } => {
Some(precisions)
}
_ => None,
}
}
pub fn offpeg_fee_multiplier(&self) -> Option<U256> {
match self {
Pool::StableSwapNG { offpeg_fee_multiplier, .. } |
Pool::StableSwapALend { offpeg_fee_multiplier, .. } => Some(*offpeg_fee_multiplier),
_ => None,
}
}
pub fn price_scale(&self) -> Option<&[U256]> {
match self {
Pool::TwoCryptoV1 { price_scale, .. } |
Pool::TwoCryptoNG { price_scale, .. } |
Pool::TwoCryptoStable { price_scale, .. } => std::slice::from_ref(price_scale).into(),
Pool::TriCryptoV1 { price_scale, .. } | Pool::TriCryptoNG { price_scale, .. } => {
Some(price_scale)
}
_ => None,
}
}
pub fn set_balance(&mut self, index: usize, value: U256) -> Result<(), PoolError> {
let bal = match self {
Pool::StableSwapV0 { balances, .. } |
Pool::StableSwapV1 { balances, .. } |
Pool::StableSwapV2 { balances, .. } |
Pool::StableSwapSTETH { balances, .. } |
Pool::StableSwapALend { balances, .. } |
Pool::StableSwapNG { balances, .. } |
Pool::StableSwapMeta { balances, .. } => balances.get_mut(index),
Pool::TwoCryptoV1 { balances, .. } |
Pool::TwoCryptoNG { balances, .. } |
Pool::TwoCryptoStable { balances, .. } => balances.get_mut(index),
Pool::TriCryptoV1 { balances, .. } | Pool::TriCryptoNG { balances, .. } => {
balances.get_mut(index)
}
};
*bal.ok_or(PoolError::IndexOutOfRange)? = value;
Ok(())
}
pub fn set_rate(&mut self, index: usize, value: U256) -> Result<(), PoolError> {
match self {
Pool::StableSwapV0 { rates, .. } |
Pool::StableSwapV1 { rates, .. } |
Pool::StableSwapV2 { rates, .. } |
Pool::StableSwapSTETH { rates, .. } |
Pool::StableSwapNG { rates, .. } |
Pool::StableSwapMeta { rates, .. } => {
*rates
.get_mut(index)
.ok_or(PoolError::IndexOutOfRange)? = value;
Ok(())
}
_ => Err(PoolError::NotApplicable),
}
}
pub fn set_d(&mut self, value: U256) -> Result<(), PoolError> {
match self {
Pool::TwoCryptoV1 { d, .. } |
Pool::TwoCryptoNG { d, .. } |
Pool::TwoCryptoStable { d, .. } => {
*d = value;
Ok(())
}
Pool::TriCryptoV1 { d, .. } | Pool::TriCryptoNG { d, .. } => {
*d = value;
Ok(())
}
_ => Err(PoolError::NotApplicable),
}
}
pub fn set_price_scale(&mut self, index: usize, value: U256) -> Result<(), PoolError> {
match self {
Pool::TwoCryptoV1 { price_scale, .. } |
Pool::TwoCryptoNG { price_scale, .. } |
Pool::TwoCryptoStable { price_scale, .. } => {
if index != 0 {
return Err(PoolError::IndexOutOfRange);
}
*price_scale = value;
Ok(())
}
Pool::TriCryptoV1 { price_scale, .. } | Pool::TriCryptoNG { price_scale, .. } => {
*price_scale
.get_mut(index)
.ok_or(PoolError::IndexOutOfRange)? = value;
Ok(())
}
_ => Err(PoolError::NotApplicable),
}
}
pub fn set_amp(&mut self, value: U256) {
match self {
Pool::StableSwapV0 { amp, .. } |
Pool::StableSwapV1 { amp, .. } |
Pool::StableSwapV2 { amp, .. } |
Pool::StableSwapSTETH { amp, .. } |
Pool::StableSwapALend { amp, .. } |
Pool::StableSwapNG { amp, .. } |
Pool::StableSwapMeta { amp, .. } => *amp = value,
Pool::TwoCryptoV1 { ann, .. } |
Pool::TwoCryptoNG { ann, .. } |
Pool::TwoCryptoStable { ann, .. } => *ann = value,
Pool::TriCryptoV1 { ann, .. } | Pool::TriCryptoNG { ann, .. } => *ann = value,
}
}
pub fn set_gamma(&mut self, value: U256) -> Result<(), PoolError> {
match self {
Pool::TwoCryptoV1 { gamma, .. } | Pool::TwoCryptoNG { gamma, .. } => {
*gamma = value;
Ok(())
}
Pool::TriCryptoV1 { gamma, .. } | Pool::TriCryptoNG { gamma, .. } => {
*gamma = value;
Ok(())
}
_ => Err(PoolError::NotApplicable),
}
}
}