1use super::SingleSideLiquidity;
2
3use super::error::{CoreError, INVALID_ORACLE_DATA};
4
5use super::oracle::{build_liquidity, build_price, consume_liquidity, OraclePayload};
6
7use borsh::BorshDeserialize;
8
9use riptide_amm_macros::alias;
10
11#[cfg(feature = "wasm")]
12use riptide_amm_macros::wasm_expose;
13
14#[derive(Debug, Clone, Copy, Eq, PartialEq)]
15#[cfg_attr(feature = "wasm", wasm_expose)]
16pub enum QuoteType {
17 TokenAExactIn,
18 TokenAExactOut,
19 TokenBExactIn,
20 TokenBExactOut,
21}
22
23impl QuoteType {
24 pub(crate) fn new(amount_is_token_a: bool, amount_is_input: bool) -> Self {
25 match (amount_is_token_a, amount_is_input) {
26 (true, true) => QuoteType::TokenAExactIn,
27 (true, false) => QuoteType::TokenAExactOut,
28 (false, true) => QuoteType::TokenBExactIn,
29 (false, false) => QuoteType::TokenBExactOut,
30 }
31 }
32
33 pub fn exact_in(&self) -> bool {
34 matches!(self, QuoteType::TokenAExactIn | QuoteType::TokenBExactIn)
35 }
36
37 pub fn exact_out(&self) -> bool {
38 matches!(self, QuoteType::TokenAExactOut | QuoteType::TokenBExactOut)
39 }
40
41 #[alias(output_is_token_b, a_to_b)]
42 pub fn input_is_token_a(&self) -> bool {
43 matches!(self, QuoteType::TokenAExactIn | QuoteType::TokenBExactOut)
44 }
45
46 #[alias(output_is_token_a, b_to_a)]
47 pub fn input_is_token_b(&self) -> bool {
48 matches!(self, QuoteType::TokenBExactIn | QuoteType::TokenAExactOut)
49 }
50}
51
52#[derive(Debug, Clone, Copy, Eq, PartialEq)]
53#[cfg_attr(feature = "wasm", wasm_expose)]
54pub struct Quote {
55 pub amount_in: u64,
56 pub amount_out: u64,
57 pub quote_type: QuoteType,
58}
59
60#[derive(Default, Debug, Clone, Eq, PartialEq)]
61#[cfg_attr(feature = "wasm", wasm_expose)]
62pub struct Prices {
63 pub oracle_price_q64_64: u128,
64 pub best_bid_price_q64_64: u128,
65 pub best_ask_price_q64_64: u128,
66 pub ask_spread_per_m: i32,
67 pub bid_spread_per_m: i32,
68}
69
70#[derive(Default, Debug, Clone, Eq, PartialEq)]
71#[cfg_attr(feature = "wasm", wasm_expose)]
72pub struct Price {
73 pub oracle_price_q64_64: u128,
74 pub best_price_q64_64: u128,
75 pub spread_per_m: i32,
76}
77
78#[cfg_attr(feature = "wasm", wasm_expose)]
79pub fn quote_exact_in(
80 amount: u64,
81 amount_is_token_a: bool,
82 oracle_data: &[u8],
83 reserves_a: u64,
84 reserves_b: u64,
85 skew_cliff_min_per_m: i32,
86 skew_cliff_max_per_m: i32,
87) -> Result<Quote, CoreError> {
88 let mut oracle_data = oracle_data;
89 let payload = OraclePayload::deserialize(&mut oracle_data).map_err(|_| INVALID_ORACLE_DATA)?;
90 let quote_type = QuoteType::new(amount_is_token_a, true);
91 let liquidity = build_liquidity(
92 &payload,
93 quote_type,
94 reserves_a,
95 reserves_b,
96 skew_cliff_min_per_m,
97 skew_cliff_max_per_m,
98 )?;
99 consume_liquidity(amount, quote_type, &liquidity)
100}
101
102#[cfg_attr(feature = "wasm", wasm_expose)]
103pub fn quote_exact_out(
104 amount: u64,
105 amount_is_token_a: bool,
106 oracle_data: &[u8],
107 reserves_a: u64,
108 reserves_b: u64,
109 skew_cliff_min_per_m: i32,
110 skew_cliff_max_per_m: i32,
111) -> Result<Quote, CoreError> {
112 let mut oracle_data = oracle_data;
113 let payload = OraclePayload::deserialize(&mut oracle_data).map_err(|_| INVALID_ORACLE_DATA)?;
114 let quote_type = QuoteType::new(amount_is_token_a, false);
115 let liquidity = build_liquidity(
116 &payload,
117 quote_type,
118 reserves_a,
119 reserves_b,
120 skew_cliff_min_per_m,
121 skew_cliff_max_per_m,
122 )?;
123 consume_liquidity(amount, quote_type, &liquidity)
124}
125
126#[cfg_attr(feature = "wasm", wasm_expose)]
127pub fn bid_price(
128 oracle_data: &[u8],
129 liquidity: SingleSideLiquidity,
130 reserves_a: u64,
131 reserves_b: u64,
132) -> Result<Price, CoreError> {
133 let mut oracle_data = oracle_data;
134 let payload = OraclePayload::deserialize(&mut oracle_data).map_err(|_| INVALID_ORACLE_DATA)?;
135 build_price(
136 &liquidity,
137 &payload.data,
138 QuoteType::TokenAExactIn,
139 reserves_a,
140 reserves_b,
141 )
142}
143
144#[cfg_attr(feature = "wasm", wasm_expose)]
145pub fn ask_price(
146 oracle_data: &[u8],
147 liquidity: SingleSideLiquidity,
148 reserves_a: u64,
149 reserves_b: u64,
150) -> Result<Price, CoreError> {
151 let mut oracle_data = oracle_data;
152 let payload = OraclePayload::deserialize(&mut oracle_data).map_err(|_| INVALID_ORACLE_DATA)?;
153 build_price(
154 &liquidity,
155 &payload.data,
156 QuoteType::TokenBExactIn,
157 reserves_a,
158 reserves_b,
159 )
160}
161
162#[cfg_attr(feature = "wasm", wasm_expose)]
163pub fn bid_liquidity(
164 oracle_data: &[u8],
165 reserves_a: u64,
166 reserves_b: u64,
167 skew_cliff_min_per_m: i32,
168 skew_cliff_max_per_m: i32,
169) -> Result<SingleSideLiquidity, CoreError> {
170 let mut oracle_data = oracle_data;
171 let payload = OraclePayload::deserialize(&mut oracle_data).map_err(|_| INVALID_ORACLE_DATA)?;
172 build_liquidity(
173 &payload,
174 QuoteType::TokenAExactIn,
175 reserves_a,
176 reserves_b,
177 skew_cliff_min_per_m,
178 skew_cliff_max_per_m,
179 )
180}
181
182#[cfg_attr(feature = "wasm", wasm_expose)]
183pub fn ask_liquidity(
184 oracle_data: &[u8],
185 reserves_a: u64,
186 reserves_b: u64,
187 skew_cliff_min_per_m: i32,
188 skew_cliff_max_per_m: i32,
189) -> Result<SingleSideLiquidity, CoreError> {
190 let mut oracle_data = oracle_data;
191 let payload = OraclePayload::deserialize(&mut oracle_data).map_err(|_| INVALID_ORACLE_DATA)?;
192 build_liquidity(
193 &payload,
194 QuoteType::TokenBExactIn,
195 reserves_a,
196 reserves_b,
197 skew_cliff_min_per_m,
198 skew_cliff_max_per_m,
199 )
200}