kabu_defi_pools/state_readers/
uniswapv2.rs

1use 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        //state_db.apply_geth_update(state_update);
88        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}