mev_engine/amm/tenkswap/
pool.rs

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    /// Locally simulates a swap in the AMM.
68    /// Mutates the AMM state to the state of the AMM after swapping.
69    /// Returns the amount received for `amount_in` of `token_in`.
70    #[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!("Fee {:?} {:?}", self.fee, fee);
163        // println!("Amount in with fee: {:?}", amount_in_with_fee);
164        // println!("Input decimals: {:?}", in_decimals);
165        // println!("Output decimals: {:?}", out_decimals);
166        // println!("Numerator: {:?}", numerator);
167        // println!("Denominator: {:?}", denominator);
168        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}