1use core::f64;
2use std::sync::Arc;
3
4use async_trait::async_trait;
5use num_bigint::BigUint;
6use serde::{Deserialize, Serialize};
7use starknet::{
8 core::{
9 types::{BlockId, BlockTag, Felt, FunctionCall, StarknetError},
10 utils::get_selector_from_name,
11 },
12 providers::Provider,
13};
14use tracing::instrument;
15
16use crate::{
17 amm::{pool::AutomatedMarketMaker, types::Reserves},
18 errors::AMMError,
19};
20
21use super::get_data::get_pool_info;
22
23#[derive(Serialize, Deserialize, Clone, Debug, Default)]
24pub struct TenkSwapPool {
25 pub pool_address: Felt,
26 pub token_a: Felt,
27 pub token_b: Felt,
28 pub token_a_decimals: u8,
29 pub token_b_decimals: u8,
30 pub reserve_a: Felt,
31 pub reserve_b: Felt,
32 pub fee: u32,
33}
34
35#[async_trait]
36impl AutomatedMarketMaker for TenkSwapPool {
37 fn address(&self) -> Felt {
38 self.pool_address
39 }
40
41 fn tokens(&self) -> Vec<Felt> {
42 vec![self.token_a, self.token_b]
43 }
44
45 #[allow(unused)]
46 fn calculate_price(&self, base_token: Felt, quote_token: Felt) -> Result<f64, StarknetError> {
47 unimplemented!();
48 }
49
50 #[allow(unused)]
51 async fn simulate_swap<P>(
52 &self,
53 base_token: Felt,
54 amount_in: Felt,
55 provider: Arc<P>,
56 ) -> Result<Felt, StarknetError>
57 where
58 P: Provider + Sync + Send,
59 {
60 if self.token_a == base_token {
61 Ok(self.get_amount_out(amount_in, self.reserve_a, self.reserve_b, true))
62 } else {
63 Ok(self.get_amount_out(amount_in, self.reserve_b, self.reserve_a, false))
64 }
65 }
66
67 #[allow(unused)]
71 fn simulate_swap_mut(
72 &mut self,
73 base_token: Felt,
74 quote_token: Felt,
75 amount_in: Felt,
76 ) -> Result<Felt, StarknetError> {
77 unimplemented!()
78 }
79
80 #[instrument(skip(self, provider), level = "debug")]
81 async fn sync<P>(&mut self, provider: Arc<P>) -> Result<(), StarknetError>
82 where
83 P: Provider + Send + Sync,
84 {
85 let Reserves {
86 reserve_a,
87 reserve_b,
88 } = self.get_reserves(provider.clone()).await?;
89 tracing::info!(?reserve_a, ?reserve_b, address = ?self.address(), "UniswapV2 sync");
90
91 self.reserve_a = reserve_a;
92 self.reserve_b = reserve_b;
93
94 Ok(())
95 }
96}
97
98impl TenkSwapPool {
99 pub fn new(
100 pool_address: Felt,
101 token_a: Felt,
102 token_b: Felt,
103 token_a_decimals: u8,
104 token_b_decimals: u8,
105 reserve_a: Felt,
106 reserve_b: Felt,
107 fee: u32,
108 ) -> TenkSwapPool {
109 TenkSwapPool {
110 pool_address,
111 token_a,
112 token_b,
113 token_a_decimals,
114 token_b_decimals,
115 reserve_a,
116 reserve_b,
117 fee,
118 }
119 }
120
121 pub fn get_amount_out(
122 &self,
123 amount_in: Felt,
124 reserve_in: Felt,
125 reserve_out: Felt,
126 is_input_token_a: bool,
127 ) -> Felt {
128 let in_decimals: BigUint;
129 let out_decimals: BigUint;
130 if is_input_token_a {
131 in_decimals = BigUint::from(10u32).pow(self.token_a_decimals.into());
132 out_decimals = BigUint::from(10u32).pow(self.token_b_decimals.into());
133 } else {
134 in_decimals = BigUint::from(10u32).pow(self.token_b_decimals.into());
135 out_decimals = BigUint::from(10u32).pow(self.token_a_decimals.into());
136 }
137
138 let amount_in = BigUint::from_bytes_be(&amount_in.to_bytes_be()) * in_decimals.clone();
139 let reserve_in = BigUint::from_bytes_be(&reserve_in.to_bytes_be()) * in_decimals.clone();
140 let reserve_out = BigUint::from_bytes_be(&reserve_out.to_bytes_be()) * out_decimals.clone();
141
142 println!(
143 "Reserves in get_amount_out {:?} {:?} {:?}",
144 amount_in, reserve_in, reserve_out
145 );
146
147 if amount_in == BigUint::from(0u32)
148 || reserve_in == BigUint::from(0u32)
149 || reserve_out == BigUint::from(0u32)
150 {
151 return Felt::ZERO;
152 }
153
154 let fee = (BigUint::from(10000u32) - (BigUint::from(self.fee) / BigUint::from(10u32)))
155 / BigUint::from(10u32);
156 let amount_in_with_fee = amount_in * fee.clone();
157 let numerator = amount_in_with_fee.clone() * reserve_out;
158 let denominator = reserve_in * BigUint::from(1000u32) + amount_in_with_fee.clone();
159
160 let result = numerator.clone() / denominator.clone();
161
162 println!("Amount out: {:?}", result);
169 println!("{:?}", Felt::from_bytes_be_slice(&result.to_bytes_be()));
170
171 Felt::from_bytes_be_slice(&result.to_bytes_be())
172 }
173
174 async fn get_reserves<P>(&mut self, provider: Arc<P>) -> Result<Reserves, StarknetError>
175 where
176 P: Provider + Sync + Send,
177 {
178 let call = FunctionCall {
179 contract_address: self.pool_address,
180 entry_point_selector: get_selector_from_name("getReserves").unwrap(),
181 calldata: vec![],
182 };
183
184 let result: Vec<Felt> = provider
185 .call(call, BlockId::Tag(BlockTag::Latest))
186 .await
187 .unwrap();
188
189 let reserve_a = Felt::from_bytes_le(&result[0].to_bytes_le());
190 let reserve_b = Felt::from_bytes_le(&result[1].to_bytes_le());
191
192 self.reserve_a = reserve_a.clone();
193 self.reserve_b = reserve_b.clone();
194 Ok(Reserves {
195 reserve_a,
196 reserve_b,
197 })
198 }
199
200 pub async fn new_from_address<P>(
201 pool_address: Felt,
202 fee: u32,
203 provider: Arc<P>,
204 ) -> Result<Self, AMMError>
205 where
206 P: Provider + Send + Sync,
207 {
208 let mut pool = get_pool_info(pool_address, provider).await.unwrap();
209 pool.fee = fee;
210
211 Ok(pool)
212 }
213}