1use crate::PoolId;
2use crate::pool_error::PoolError;
3use crate::required_state::RequiredState;
4use crate::swap_direction::SwapDirection;
5use alloy_evm::EvmEnv;
6use alloy_primitives::{Address, Bytes, U256};
7use eyre::{Result, eyre};
8use kabu_defi_address_book::FactoryAddress;
9use kabu_evm_db::KabuDBError;
10use revm::DatabaseRef;
11use serde::{Deserialize, Serialize};
12use std::any::Any;
13use std::cmp::Ordering;
14use std::fmt::{Debug, Display, Formatter};
15use std::hash::{Hash, Hasher};
16use std::ops::Deref;
17use std::sync::Arc;
18use strum_macros::{Display, EnumIter, EnumString, VariantNames};
19
20pub fn get_protocol_by_factory(factory_address: Address) -> PoolProtocol {
21 if factory_address == FactoryAddress::UNISWAP_V2 {
22 PoolProtocol::UniswapV2
23 } else if factory_address == FactoryAddress::UNISWAP_V3 {
24 PoolProtocol::UniswapV3
25 } else if factory_address == FactoryAddress::PANCAKE_V3 {
26 PoolProtocol::PancakeV3
27 } else if factory_address == FactoryAddress::NOMISWAP {
28 PoolProtocol::NomiswapStable
29 } else if factory_address == FactoryAddress::ANTFARM {
30 PoolProtocol::AntFarm
31 } else if factory_address == FactoryAddress::SUSHISWAP_V2 {
32 PoolProtocol::Sushiswap
33 } else if factory_address == FactoryAddress::SUSHISWAP_V3 {
34 PoolProtocol::SushiswapV3
35 } else if factory_address == FactoryAddress::DOOARSWAP {
36 PoolProtocol::DooarSwap
37 } else if factory_address == FactoryAddress::SAFESWAP {
38 PoolProtocol::Safeswap
39 } else if factory_address == FactoryAddress::MINISWAP {
40 PoolProtocol::Miniswap
41 } else if factory_address == FactoryAddress::SHIBASWAP {
42 PoolProtocol::Shibaswap
43 } else if factory_address == FactoryAddress::MAVERICK {
44 PoolProtocol::Maverick
45 } else if factory_address == FactoryAddress::INTEGRAL {
46 PoolProtocol::Integral
47 } else {
48 PoolProtocol::Unknown
49 }
50}
51
52#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq, EnumString, VariantNames, Display, Default, Deserialize, Serialize, EnumIter)]
53#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
54pub enum PoolClass {
55 #[default]
56 #[serde(rename = "unknown")]
57 #[strum(serialize = "unknown")]
58 Unknown,
59 #[serde(rename = "uniswap2")]
60 #[strum(serialize = "uniswap2")]
61 UniswapV2,
62 #[serde(rename = "uniswap3")]
63 #[strum(serialize = "uniswap3")]
64 UniswapV3,
65 #[serde(rename = "uniswap4")]
66 #[strum(serialize = "uniswap4")]
67 UniswapV4,
68 #[serde(rename = "maverick")]
69 #[strum(serialize = "maverick")]
70 Maverick,
71 #[serde(rename = "maverick2")]
72 #[strum(serialize = "maverick2")]
73 MaverickV2,
74 #[serde(rename = "pancake3")]
75 #[strum(serialize = "pancake3")]
76 PancakeV3,
77 #[serde(rename = "curve")]
78 #[strum(serialize = "curve")]
79 Curve,
80 #[serde(rename = "steth")]
81 #[strum(serialize = "steth")]
82 LidoStEth,
83 #[serde(rename = "wsteth")]
84 #[strum(serialize = "wsteth")]
85 LidoWstEth,
86 #[serde(rename = "rocketpool")]
87 #[strum(serialize = "rocketpool")]
88 RocketPool,
89 #[serde(rename = "balancer1")]
90 #[strum(serialize = "balancer1")]
91 BalancerV1,
92 #[serde(rename = "balancer2")]
93 #[strum(serialize = "balancer2")]
94 BalancerV2,
95 #[serde(rename = "custom")]
96 #[strum(serialize = "custom")]
97 Custom(u64),
98}
99
100#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
101pub enum PoolProtocol {
102 Unknown,
103 AaveV2,
104 AaveV3,
105 UniswapV2,
106 UniswapV2Like,
107 NomiswapStable,
108 Sushiswap,
109 SushiswapV3,
110 DooarSwap,
111 OgPepe,
112 AntFarm,
113 Safeswap,
114 Miniswap,
115 Shibaswap,
116 UniswapV3,
117 UniswapV3Like,
118 UniswapV4,
119 PancakeV3,
120 Integral,
121 Maverick,
122 MaverickV2,
123 Curve,
124 LidoStEth,
125 LidoWstEth,
126 RocketEth,
127 BalancerV1,
128 BalancerV2,
129 Custom(u64),
130}
131
132impl Display for PoolProtocol {
133 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
134 let protocol_name = match self {
135 Self::Unknown => "Unknown",
136 Self::AaveV2 => "AaveV2",
137 Self::AaveV3 => "AaveV3",
138 Self::UniswapV2 => "UniswapV2",
139 Self::UniswapV2Like => "UniswapV2Like",
140 Self::UniswapV3 => "UniswapV3",
141 Self::PancakeV3 => "PancakeV3",
142 Self::UniswapV4 => "UniswapV4",
143 Self::UniswapV3Like => "UniswapV3Like",
144 Self::NomiswapStable => "NomiswapStable",
145 Self::Sushiswap => "Sushiswap",
146 Self::SushiswapV3 => "SushiswapV3",
147 Self::DooarSwap => "Dooarswap",
148 Self::OgPepe => "OgPepe",
149 Self::AntFarm => "AntFarm",
150 Self::Miniswap => "Miniswap",
151 Self::Shibaswap => "Shibaswap",
152 Self::Safeswap => "Safeswap",
153 Self::Integral => "Integral",
154 Self::Maverick => "Maverick",
155 Self::MaverickV2 => "MaverickV2",
156 Self::Curve => "Curve",
157 Self::LidoWstEth => "WstEth",
158 Self::LidoStEth => "StEth",
159 Self::RocketEth => "RocketEth",
160 Self::BalancerV1 => "BalancerV1",
161 Self::BalancerV2 => "BalancerV2",
162 Self::Custom(_x) => "Custom",
163 };
164 write!(f, "{protocol_name}")
165 }
166}
167
168pub struct PoolWrapper {
169 pub pool: Arc<dyn Pool>,
170}
171
172impl PartialOrd for PoolWrapper {
173 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
174 Some(self.cmp(other))
175 }
176}
177
178impl Eq for PoolWrapper {}
179
180impl Ord for PoolWrapper {
181 fn cmp(&self, other: &Self) -> Ordering {
182 self.get_pool_id().cmp(&other.get_pool_id())
183 }
184}
185
186impl Display for PoolWrapper {
187 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
188 write!(f, "{}@{}", self.get_protocol(), self.get_pool_id())
189 }
190}
191
192impl Debug for PoolWrapper {
193 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
194 write!(f, "{}@{}", self.get_protocol(), self.get_pool_id())
195 }
196}
197
198impl Hash for PoolWrapper {
199 fn hash<H: Hasher>(&self, state: &mut H) {
200 self.get_pool_id().hash(state)
201 }
202}
203
204impl PartialEq for PoolWrapper {
205 fn eq(&self, other: &Self) -> bool {
206 self.pool.get_pool_id() == other.pool.get_pool_id()
207 }
208}
209
210impl Clone for PoolWrapper {
211 fn clone(&self) -> Self {
212 Self { pool: self.pool.clone() }
213 }
214}
215
216impl Deref for PoolWrapper {
217 type Target = dyn Pool;
218
219 fn deref(&self) -> &Self::Target {
220 self.pool.deref()
221 }
222}
223
224impl AsRef<dyn Pool> for PoolWrapper {
225 fn as_ref(&self) -> &(dyn Pool + 'static) {
226 self.pool.as_ref()
227 }
228}
229
230impl PoolWrapper {
231 pub fn new(pool: Arc<dyn Pool>) -> Self {
232 PoolWrapper { pool }
233 }
234}
235
236impl<T: 'static + Pool> From<T> for PoolWrapper {
237 fn from(pool: T) -> Self {
238 Self { pool: Arc::new(pool) }
239 }
240}
241
242pub trait Pool: Sync + Send {
243 fn as_any(&self) -> &dyn Any;
244
245 fn get_class(&self) -> PoolClass;
246
247 fn get_protocol(&self) -> PoolProtocol;
248
249 fn get_address(&self) -> PoolId;
250
251 fn get_pool_id(&self) -> PoolId;
252
253 fn get_fee(&self) -> U256;
254
255 fn get_tokens(&self) -> Vec<Address>;
256
257 fn get_swap_directions(&self) -> Vec<SwapDirection>;
258
259 fn calculate_out_amount(
260 &self,
261 db: &dyn DatabaseRef<Error = KabuDBError>,
262 evm_env: &EvmEnv,
263 token_address_from: &Address,
264 token_address_to: &Address,
265 in_amount: U256,
266 ) -> Result<(U256, u64), PoolError>;
267
268 fn calculate_in_amount(
270 &self,
271 db: &dyn DatabaseRef<Error = KabuDBError>,
272 evm_env: &EvmEnv,
273 token_address_from: &Address,
274 token_address_to: &Address,
275 out_amount: U256,
276 ) -> Result<(U256, u64), PoolError>;
277
278 fn can_flash_swap(&self) -> bool;
279
280 fn can_calculate_in_amount(&self) -> bool;
281
282 fn get_abi_encoder(&self) -> Option<&dyn PoolAbiEncoder>;
283
284 fn get_read_only_cell_vec(&self) -> Vec<U256>;
285
286 fn get_state_required(&self) -> Result<RequiredState>;
287
288 fn is_native(&self) -> bool;
289
290 fn preswap_requirement(&self) -> PreswapRequirement;
291
292 fn get_pool_manager_cells(&self) -> Vec<(Address, Vec<U256>)> {
293 vec![]
294 }
295}
296
297pub struct DefaultAbiSwapEncoder {}
298
299impl PoolAbiEncoder for DefaultAbiSwapEncoder {}
300
301#[derive(Clone, Debug)]
302pub enum PreswapRequirement {
303 Unknown,
304 Transfer(Address),
305 Allowance,
306 Callback,
307 Base,
308}
309
310impl PartialEq for PreswapRequirement {
311 fn eq(&self, other: &Self) -> bool {
312 match (self, other) {
313 (PreswapRequirement::Unknown, PreswapRequirement::Unknown) => true,
314 (PreswapRequirement::Transfer(addr1), PreswapRequirement::Transfer(addr2)) => addr1 == addr2,
315 (PreswapRequirement::Allowance, PreswapRequirement::Allowance) => true,
316 (PreswapRequirement::Callback, PreswapRequirement::Callback) => true,
317 (PreswapRequirement::Base, PreswapRequirement::Base) => true,
318 _ => false,
319 }
320 }
321}
322
323impl PreswapRequirement {
324 pub fn address_or(&self, default_address: Address) -> Address {
325 match self {
326 PreswapRequirement::Transfer(address) => *address,
327 _ => default_address,
328 }
329 }
330 pub fn address(&self) -> Option<Address> {
331 match self {
332 PreswapRequirement::Transfer(address) => Some(*address),
333 _ => None,
334 }
335 }
336}
337
338pub trait PoolAbiEncoder: Send + Sync {
339 fn encode_swap_in_amount_provided(
340 &self,
341 _token_from_address: Address,
342 _token_to_address: Address,
343 _amount: U256,
344 _recipient: Address,
345 _payload: Bytes,
346 ) -> Result<Bytes> {
347 Err(eyre!("NOT_IMPLEMENTED"))
348 }
349 fn encode_swap_out_amount_provided(
350 &self,
351 _token_from_address: Address,
352 _token_to_address: Address,
353 _amount: U256,
354 _recipient: Address,
355 _payload: Bytes,
356 ) -> Result<Bytes> {
357 Err(eyre!("NOT_IMPLEMENTED"))
358 }
359
360 fn swap_in_amount_offset(&self, _token_from_address: Address, _token_to_address: Address) -> Option<u32> {
361 None
362 }
363 fn swap_out_amount_offset(&self, _token_from_address: Address, _token_to_address: Address) -> Option<u32> {
364 None
365 }
366 fn swap_out_amount_return_offset(&self, _token_from_address: Address, _token_to_address: Address) -> Option<u32> {
367 None
368 }
369 fn swap_in_amount_return_offset(&self, _token_from_address: Address, _token_to_address: Address) -> Option<u32> {
370 None
371 }
372 fn swap_out_amount_return_script(&self, _token_from_address: Address, _token_to_address: Address) -> Option<Bytes> {
373 None
374 }
375 fn swap_in_amount_return_script(&self, _token_from_address: Address, _token_to_address: Address) -> Option<Bytes> {
376 None
377 }
378}
379
380#[cfg(test)]
381mod tests {
382 use crate::PoolClass;
383
384 #[test]
385 fn test_strum() {
386 println!("{}", PoolClass::Unknown);
387 println!("{}", PoolClass::UniswapV2);
388 }
389}