nautilus_blockchain/exchanges/ethereum/
uniswap_v3.rs1use std::sync::LazyLock;
17
18use alloy::primitives::{Address, U256};
19use hypersync_client::simple_types::Log;
20use nautilus_model::defi::{
21 chain::chains,
22 dex::{AmmType, Dex},
23};
24
25use crate::{events::pool_created::PoolCreated, exchanges::extended::DexExtended};
26
27pub static UNISWAP_V3: LazyLock<DexExtended> = LazyLock::new(|| {
29 let mut dex = DexExtended::new(Dex::new(
30 chains::ETHEREUM.clone(),
31 "Uniswap V3",
32 "0x1F98431c8aD98523631AE4a59f267346ea31F984",
33 AmmType::CLAMM,
34 "PoolCreated(address,address,uint24,int24,address)",
35 ));
36 dex.set_pool_created_event_parsing(parse_pool_created_event);
37 dex
38});
39
40fn parse_pool_created_event(log: Log) -> anyhow::Result<PoolCreated> {
41 let block_number = log
42 .block_number
43 .expect("Block number should be set in logs");
44 let token = if let Some(topic) = log.topics.get(1).and_then(|t| t.as_ref()) {
45 Address::from_slice(&topic.as_ref()[12..32])
47 } else {
48 anyhow::bail!("Missing token0 address in topic1");
49 };
50
51 let token1 = if let Some(topic) = log.topics.get(2).and_then(|t| t.as_ref()) {
52 Address::from_slice(&topic.as_ref()[12..32])
53 } else {
54 anyhow::bail!("Missing token1 address in topic2");
55 };
56
57 let fee = if let Some(topic) = log.topics.get(3).and_then(|t| t.as_ref()) {
58 U256::from_be_slice(topic.as_ref()).as_limbs()[0] as u32
59 } else {
60 anyhow::bail!("Missing fee in topic3");
61 };
62
63 if let Some(data) = log.data {
64 let data_bytes = data.as_ref();
66
67 let tick_spacing_bytes: [u8; 32] = data_bytes[0..32].try_into()?;
69 let tick_spacing = u32::from_be_bytes(tick_spacing_bytes[28..32].try_into()?);
70
71 let pool_address_bytes: [u8; 32] = data_bytes[32..64].try_into()?;
73 let pool_address = Address::from_slice(&pool_address_bytes[12..32]);
74
75 Ok(PoolCreated::new(
76 block_number.into(),
77 token,
78 token1,
79 fee,
80 tick_spacing,
81 pool_address,
82 ))
83 } else {
84 Err(anyhow::anyhow!("Missing data in log"))
85 }
86}