use super::SingleSideLiquidity;
use super::error::{CoreError, INVALID_ORACLE_DATA};
use super::oracle::{build_liquidity, build_price, consume_liquidity, OraclePayload};
use borsh::BorshDeserialize;
use riptide_amm_macros::alias;
#[cfg(feature = "wasm")]
use riptide_amm_macros::wasm_expose;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "wasm", wasm_expose)]
pub enum QuoteType {
TokenAExactIn,
TokenAExactOut,
TokenBExactIn,
TokenBExactOut,
}
impl QuoteType {
pub(crate) fn new(amount_is_token_a: bool, amount_is_input: bool) -> Self {
match (amount_is_token_a, amount_is_input) {
(true, true) => QuoteType::TokenAExactIn,
(true, false) => QuoteType::TokenAExactOut,
(false, true) => QuoteType::TokenBExactIn,
(false, false) => QuoteType::TokenBExactOut,
}
}
pub fn exact_in(&self) -> bool {
matches!(self, QuoteType::TokenAExactIn | QuoteType::TokenBExactIn)
}
pub fn exact_out(&self) -> bool {
matches!(self, QuoteType::TokenAExactOut | QuoteType::TokenBExactOut)
}
#[alias(output_is_token_b, a_to_b)]
pub fn input_is_token_a(&self) -> bool {
matches!(self, QuoteType::TokenAExactIn | QuoteType::TokenBExactOut)
}
#[alias(output_is_token_a, b_to_a)]
pub fn input_is_token_b(&self) -> bool {
matches!(self, QuoteType::TokenBExactIn | QuoteType::TokenAExactOut)
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "wasm", wasm_expose)]
pub struct Quote {
pub amount_in: u64,
pub amount_out: u64,
pub quote_type: QuoteType,
}
#[derive(Default, Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "wasm", wasm_expose)]
pub struct Prices {
pub oracle_price_q64_64: u128,
pub best_bid_price_q64_64: u128,
pub best_ask_price_q64_64: u128,
pub ask_spread_per_m: i32,
pub bid_spread_per_m: i32,
}
#[derive(Default, Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "wasm", wasm_expose)]
pub struct Price {
pub oracle_price_q64_64: u128,
pub best_price_q64_64: u128,
pub spread_per_m: i32,
}
#[cfg_attr(feature = "wasm", wasm_expose)]
pub fn quote_exact_in(
amount: u64,
amount_is_token_a: bool,
oracle_data: &[u8],
reserves_a: u64,
reserves_b: u64,
) -> Result<Quote, CoreError> {
let mut oracle_data = oracle_data;
let payload = OraclePayload::deserialize(&mut oracle_data).map_err(|_| INVALID_ORACLE_DATA)?;
let quote_type = QuoteType::new(amount_is_token_a, true);
let liquidity = build_liquidity(&payload, quote_type, reserves_a, reserves_b)?;
consume_liquidity(amount, quote_type, &liquidity)
}
#[cfg_attr(feature = "wasm", wasm_expose)]
pub fn quote_exact_out(
amount: u64,
amount_is_token_a: bool,
oracle_data: &[u8],
reserves_a: u64,
reserves_b: u64,
) -> Result<Quote, CoreError> {
let mut oracle_data = oracle_data;
let payload = OraclePayload::deserialize(&mut oracle_data).map_err(|_| INVALID_ORACLE_DATA)?;
let quote_type = QuoteType::new(amount_is_token_a, false);
let liquidity = build_liquidity(&payload, quote_type, reserves_a, reserves_b)?;
consume_liquidity(amount, quote_type, &liquidity)
}
#[cfg_attr(feature = "wasm", wasm_expose)]
pub fn bid_price(
oracle_data: &[u8],
liquidity: SingleSideLiquidity,
reserves_a: u64,
reserves_b: u64,
) -> Result<Price, CoreError> {
let mut oracle_data = oracle_data;
let payload = OraclePayload::deserialize(&mut oracle_data).map_err(|_| INVALID_ORACLE_DATA)?;
build_price(
&liquidity,
&payload.data,
QuoteType::TokenAExactIn,
reserves_a,
reserves_b,
)
}
#[cfg_attr(feature = "wasm", wasm_expose)]
pub fn ask_price(
oracle_data: &[u8],
liquidity: SingleSideLiquidity,
reserves_a: u64,
reserves_b: u64,
) -> Result<Price, CoreError> {
let mut oracle_data = oracle_data;
let payload = OraclePayload::deserialize(&mut oracle_data).map_err(|_| INVALID_ORACLE_DATA)?;
build_price(
&liquidity,
&payload.data,
QuoteType::TokenBExactIn,
reserves_a,
reserves_b,
)
}
#[cfg_attr(feature = "wasm", wasm_expose)]
pub fn bid_liquidity(
oracle_data: &[u8],
reserves_a: u64,
reserves_b: u64,
) -> Result<SingleSideLiquidity, CoreError> {
let mut oracle_data = oracle_data;
let payload = OraclePayload::deserialize(&mut oracle_data).map_err(|_| INVALID_ORACLE_DATA)?;
build_liquidity(&payload, QuoteType::TokenAExactIn, reserves_a, reserves_b)
}
#[cfg_attr(feature = "wasm", wasm_expose)]
pub fn ask_liquidity(
oracle_data: &[u8],
reserves_a: u64,
reserves_b: u64,
) -> Result<SingleSideLiquidity, CoreError> {
let mut oracle_data = oracle_data;
let payload = OraclePayload::deserialize(&mut oracle_data).map_err(|_| INVALID_ORACLE_DATA)?;
build_liquidity(&payload, QuoteType::TokenBExactIn, reserves_a, reserves_b)
}