diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index c5b12996..1ed74d5f 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -7,7 +7,6 @@ pub mod errors; pub mod events; pub mod models; pub mod state; -pub mod tycho; pub mod uniswap_v2; pub mod uniswap_v3; pub mod vm; diff --git a/src/protocol/uniswap_v2/mod.rs b/src/protocol/uniswap_v2/mod.rs index 931e5aaf..b9a3ca9c 100644 --- a/src/protocol/uniswap_v2/mod.rs +++ b/src/protocol/uniswap_v2/mod.rs @@ -2,3 +2,4 @@ pub mod events; pub mod reserve_price; pub mod state; +pub mod tycho_decoder; diff --git a/src/protocol/uniswap_v2/tycho_decoder.rs b/src/protocol/uniswap_v2/tycho_decoder.rs new file mode 100644 index 00000000..a67d3788 --- /dev/null +++ b/src/protocol/uniswap_v2/tycho_decoder.rs @@ -0,0 +1,118 @@ +use ethers::types::U256; + +use tycho_client::feed::synchronizer::ComponentWithState; + +use crate::protocol::{ + errors::InvalidSnapshotError, uniswap_v2::state::UniswapV2State, BytesConvertible, +}; + +impl TryFrom for UniswapV2State { + type Error = InvalidSnapshotError; + + /// Decodes a `ComponentWithState` into a `UniswapV2State`. Errors with a `InvalidSnapshotError` + /// if either reserve0 or reserve1 attributes are missing. + fn try_from(snapshot: ComponentWithState) -> Result { + let reserve0 = U256::from_bytes( + snapshot + .state + .attributes + .get("reserve0") + .ok_or(InvalidSnapshotError::MissingAttribute("reserve0".to_string()))?, + ); + + let reserve1 = U256::from_bytes( + snapshot + .state + .attributes + .get("reserve1") + .ok_or(InvalidSnapshotError::MissingAttribute("reserve1".to_string()))?, + ); + + Ok(UniswapV2State::new(reserve0, reserve1)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use chrono::DateTime; + use std::{collections::HashMap, str::FromStr}; + + use tycho_core::{ + dto::{Chain, ChangeType, ProtocolComponent, ResponseProtocolState}, + hex_bytes::Bytes, + }; + + fn usv2_component() -> ProtocolComponent { + let creation_time = DateTime::from_timestamp(1622526000, 0) + .unwrap() + .naive_utc(); //Sample timestamp + + let mut static_attributes: HashMap = HashMap::new(); + static_attributes.insert("attr1".to_string(), "0x000012".into()); + static_attributes.insert("attr2".to_string(), "0x000005".into()); + + ProtocolComponent { + id: "State1".to_string(), + protocol_system: "system1".to_string(), + protocol_type_name: "typename1".to_string(), + chain: Chain::Ethereum, + tokens: Vec::new(), + contract_ids: Vec::new(), + static_attributes: HashMap::new(), + change: ChangeType::Creation, + creation_tx: Bytes::from_str("0x0000").unwrap(), + created_at: creation_time, + } + } + + #[test] + fn test_usv2_try_from() { + let attributes: HashMap = vec![ + ("reserve0".to_string(), Bytes::from(100_u64.to_le_bytes().to_vec())), + ("reserve1".to_string(), Bytes::from(200_u64.to_le_bytes().to_vec())), + ] + .into_iter() + .collect(); + let snapshot = ComponentWithState { + state: ResponseProtocolState { + component_id: "State1".to_owned(), + attributes, + balances: HashMap::new(), + }, + component: usv2_component(), + }; + + let result = UniswapV2State::try_from(snapshot); + + assert!(result.is_ok()); + let res = result.unwrap(); + assert_eq!(res.reserve0, 100.into()); + assert_eq!(res.reserve1, 200.into()); + } + + #[test] + fn test_usv2_try_from_invalid() { + let attributes: HashMap = + vec![("reserve0".to_string(), Bytes::from(100_u64.to_le_bytes().to_vec()))] + .into_iter() + .collect(); + let snapshot = ComponentWithState { + state: ResponseProtocolState { + component_id: "State1".to_owned(), + attributes, + balances: HashMap::new(), + }, + component: usv2_component(), + }; + + let result = UniswapV2State::try_from(snapshot); + + assert!(result.is_err()); + assert_eq!( + result.err().unwrap(), + InvalidSnapshotError::MissingAttribute("reserve1".to_string()) + ); + } +} diff --git a/src/protocol/uniswap_v3/mod.rs b/src/protocol/uniswap_v3/mod.rs index 9a36bfa4..f34dcdf2 100644 --- a/src/protocol/uniswap_v3/mod.rs +++ b/src/protocol/uniswap_v3/mod.rs @@ -8,3 +8,4 @@ pub mod state; mod swap_math; pub mod tick_list; mod tick_math; +pub mod tycho_decoder; diff --git a/src/protocol/uniswap_v3/state.rs b/src/protocol/uniswap_v3/state.rs index d268639c..39a0ce67 100644 --- a/src/protocol/uniswap_v3/state.rs +++ b/src/protocol/uniswap_v3/state.rs @@ -11,7 +11,6 @@ use crate::{ events::{check_log_idx, EVMLogMeta, LogIndex}, models::GetAmountOutResult, state::{ProtocolEvent, ProtocolSim}, - tycho::i24_le_bytes_to_i32, BytesConvertible, }, safe_math::{safe_add_u256, safe_sub_u256}, @@ -25,6 +24,7 @@ use super::{ swap_math, tick_list::{TickInfo, TickList}, tick_math, + tycho_decoder::i24_le_bytes_to_i32, }; #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/src/protocol/tycho.rs b/src/protocol/uniswap_v3/tycho_decoder.rs similarity index 75% rename from src/protocol/tycho.rs rename to src/protocol/uniswap_v3/tycho_decoder.rs index c36d20ff..93675bf8 100644 --- a/src/protocol/tycho.rs +++ b/src/protocol/uniswap_v3/tycho_decoder.rs @@ -1,41 +1,14 @@ use ethers::types::U256; + use tycho_client::feed::synchronizer::ComponentWithState; use tycho_core::Bytes; use crate::protocol::{ errors::InvalidSnapshotError, - uniswap_v2::state::UniswapV2State, - uniswap_v3::{enums::FeeAmount, state::UniswapV3State}, + uniswap_v3::{enums::FeeAmount, state::UniswapV3State, tick_list::TickInfo}, + BytesConvertible, }; -use super::{uniswap_v3::tick_list::TickInfo, BytesConvertible}; - -impl TryFrom for UniswapV2State { - type Error = InvalidSnapshotError; - - /// Decodes a `ComponentWithState` into a `UniswapV2State`. Errors with a `InvalidSnapshotError` - /// if either reserve0 or reserve1 attributes are missing. - fn try_from(snapshot: ComponentWithState) -> Result { - let reserve0 = U256::from_bytes( - snapshot - .state - .attributes - .get("reserve0") - .ok_or(InvalidSnapshotError::MissingAttribute("reserve0".to_string()))?, - ); - - let reserve1 = U256::from_bytes( - snapshot - .state - .attributes - .get("reserve1") - .ok_or(InvalidSnapshotError::MissingAttribute("reserve1".to_string()))?, - ); - - Ok(UniswapV2State::new(reserve0, reserve1)) - } -} - impl TryFrom for UniswapV3State { type Error = InvalidSnapshotError; @@ -200,78 +173,6 @@ mod tests { use super::*; - fn usv2_component() -> ProtocolComponent { - let creation_time = DateTime::from_timestamp(1622526000, 0) - .unwrap() - .naive_utc(); //Sample timestamp - - let mut static_attributes: HashMap = HashMap::new(); - static_attributes.insert("attr1".to_string(), "0x000012".into()); - static_attributes.insert("attr2".to_string(), "0x000005".into()); - - ProtocolComponent { - id: "State1".to_string(), - protocol_system: "system1".to_string(), - protocol_type_name: "typename1".to_string(), - chain: Chain::Ethereum, - tokens: Vec::new(), - contract_ids: Vec::new(), - static_attributes: HashMap::new(), - change: ChangeType::Creation, - creation_tx: Bytes::from_str("0x0000").unwrap(), - created_at: creation_time, - } - } - - #[test] - fn test_usv2_try_from() { - let attributes: HashMap = vec![ - ("reserve0".to_string(), Bytes::from(100_u64.to_le_bytes().to_vec())), - ("reserve1".to_string(), Bytes::from(200_u64.to_le_bytes().to_vec())), - ] - .into_iter() - .collect(); - let snapshot = ComponentWithState { - state: ResponseProtocolState { - component_id: "State1".to_owned(), - attributes, - balances: HashMap::new(), - }, - component: usv2_component(), - }; - - let result = UniswapV2State::try_from(snapshot); - - assert!(result.is_ok()); - let res = result.unwrap(); - assert_eq!(res.reserve0, 100.into()); - assert_eq!(res.reserve1, 200.into()); - } - - #[test] - fn test_usv2_try_from_invalid() { - let attributes: HashMap = - vec![("reserve0".to_string(), Bytes::from(100_u64.to_le_bytes().to_vec()))] - .into_iter() - .collect(); - let snapshot = ComponentWithState { - state: ResponseProtocolState { - component_id: "State1".to_owned(), - attributes, - balances: HashMap::new(), - }, - component: usv2_component(), - }; - - let result = UniswapV2State::try_from(snapshot); - - assert!(result.is_err()); - assert_eq!( - result.err().unwrap(), - InvalidSnapshotError::MissingAttribute("reserve1".to_string()) - ); - } - fn usv3_component() -> ProtocolComponent { let creation_time = DateTime::from_timestamp(1622526000, 0) .unwrap()