kabu_defi_pools/state_readers/
uniswapv2.rs1use alloy::primitives::{Address, U256};
2use alloy::sol_types::{SolCall, SolInterface};
3use alloy_evm::EvmEnv;
4use eyre::Result;
5use kabu_defi_abi::uniswap2::IUniswapV2Pair;
6use kabu_evm_db::KabuDBError;
7use kabu_evm_utils::evm_call;
8use kabu_types_market::PoolError;
9use revm::DatabaseRef;
10use tracing::error;
11
12pub struct UniswapV2EVMStateReader {}
13
14impl UniswapV2EVMStateReader {
15 pub fn factory<DB: DatabaseRef<Error = KabuDBError> + ?Sized>(db: &DB, evm_env: &EvmEnv, pool: Address) -> Result<Address, PoolError> {
16 let input = IUniswapV2Pair::IUniswapV2PairCalls::factory(IUniswapV2Pair::factoryCall {}).abi_encode();
17 let (call_data_result, _, _) = evm_call(db, evm_env.clone(), pool, input)?;
18
19 let call_return = IUniswapV2Pair::factoryCall::abi_decode_returns(&call_data_result)
20 .map_err(|e| PoolError::AbiDecodingError { method: "factory", source: e })?;
21 Ok(call_return)
22 }
23
24 pub fn token0<DB: DatabaseRef<Error = KabuDBError> + ?Sized>(db: &DB, evm_env: &EvmEnv, pool: Address) -> Result<Address, PoolError> {
25 let input = IUniswapV2Pair::IUniswapV2PairCalls::token0(IUniswapV2Pair::token0Call {}).abi_encode();
26 let (call_data_result, _, _) = evm_call(db, evm_env.clone(), pool, input)?;
27
28 let call_return = IUniswapV2Pair::token0Call::abi_decode_returns(&call_data_result)
29 .map_err(|e| PoolError::AbiDecodingError { method: "token0", source: e })?;
30 Ok(call_return)
31 }
32
33 pub fn token1<DB: DatabaseRef<Error = KabuDBError> + ?Sized>(db: &DB, evm_env: &EvmEnv, pool: Address) -> Result<Address, PoolError> {
34 let input = IUniswapV2Pair::IUniswapV2PairCalls::token1(IUniswapV2Pair::token1Call {}).abi_encode();
35 let (call_data_result, _, _) = evm_call(db, evm_env.clone(), pool, input)?;
36
37 let call_return = IUniswapV2Pair::token1Call::abi_decode_returns(&call_data_result)
38 .map_err(|e| PoolError::AbiDecodingError { method: "token1", source: e })?;
39 Ok(call_return)
40 }
41
42 pub fn get_reserves<DB: DatabaseRef<Error = KabuDBError> + ?Sized>(
43 db: &DB,
44 evm_env: EvmEnv,
45 pool: Address,
46 ) -> Result<(U256, U256), PoolError> {
47 let input = IUniswapV2Pair::IUniswapV2PairCalls::getReserves(IUniswapV2Pair::getReservesCall {}).abi_encode();
48 let call_data_result = match evm_call(db, evm_env, pool, input) {
49 Ok((call_data, _, _)) => call_data,
50 Err(error) => {
51 error!(%error,"get_reserves");
52 return Err(error.into());
53 }
54 };
55
56 let call_return = IUniswapV2Pair::getReservesCall::abi_decode_returns(&call_data_result)
57 .map_err(|e| PoolError::AbiDecodingError { method: "getReserves", source: e })?;
58 Ok((U256::from(call_return.reserve0), U256::from(call_return.reserve1)))
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65 use crate::UniswapV2Pool;
66 use alloy::primitives::address;
67 use alloy_evm::EvmEnv;
68 use kabu_evm_db::{DatabaseHelpers, KabuDBType};
69 use kabu_node_debug_provider::AnvilDebugProviderFactory;
70 use kabu_types_market::Pool;
71 use kabu_types_market::RequiredStateReader;
72 use std::env;
73
74 #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
75 async fn test_uniswap_v2_state_reader_get_reserves() -> Result<()> {
76 dotenvy::from_filename(".env.test").ok();
77 let node_url = env::var("MAINNET_WS")?;
78
79 let client = AnvilDebugProviderFactory::from_node_on_block(node_url, 22952705).await?;
80
81 let pool_address = address!("10ef7f8833ea986109abc6ef2ac379bf4baf2801");
82 let pool = UniswapV2Pool::fetch_pool_data(client.clone(), pool_address).await?;
83 let state_required = pool.get_state_required()?;
84 let state_update = RequiredStateReader::fetch_calls_and_slots(client.clone(), state_required, None).await?;
85
86 let mut state_db = KabuDBType::default();
87 DatabaseHelpers::apply_geth_state_update(&mut state_db, state_update);
89
90 let evm_env = EvmEnv::default();
91 let (reserve0, reserve1) = UniswapV2EVMStateReader::get_reserves(&state_db, evm_env, pool_address)?;
92
93 assert_eq!(reserve0, U256::from(356862508671847911238069u128));
94 assert_eq!(reserve1, U256::from(11007058744278921557u128));
95
96 Ok(())
97 }
98}