tycho_simulation/evm/protocol/pancakeswap_v2/
decoder.rs1use std::collections::HashMap;
2
3use tycho_client::feed::{synchronizer::ComponentWithState, BlockHeader};
4use tycho_common::{models::token::Token, Bytes};
5
6use crate::{
7 evm::protocol::{
8 cpmm::protocol::cpmm_try_from_with_header, pancakeswap_v2::state::PancakeswapV2State,
9 },
10 protocol::{
11 errors::InvalidSnapshotError,
12 models::{DecoderContext, TryFromWithBlock},
13 },
14};
15
16impl TryFromWithBlock<ComponentWithState, BlockHeader> for PancakeswapV2State {
17 type Error = InvalidSnapshotError;
18
19 async fn try_from_with_header(
22 snapshot: ComponentWithState,
23 _block: BlockHeader,
24 _account_balances: &HashMap<Bytes, HashMap<Bytes, Bytes>>,
25 _all_tokens: &HashMap<Bytes, Token>,
26 _decoder_context: &DecoderContext,
27 ) -> Result<Self, Self::Error> {
28 let (reserve0, reserve1) = cpmm_try_from_with_header(snapshot)?;
29 Ok(Self::new(reserve0, reserve1))
30 }
31}
32
33#[cfg(test)]
34mod tests {
35 use std::collections::HashMap;
36
37 use alloy::primitives::U256;
38 use rstest::rstest;
39 use tycho_client::feed::synchronizer::ComponentWithState;
40 use tycho_common::{dto::ResponseProtocolState, Bytes};
41
42 use super::super::state::PancakeswapV2State;
43 use crate::{
44 evm::protocol::test_utils::try_decode_snapshot_with_defaults,
45 protocol::errors::InvalidSnapshotError,
46 };
47
48 #[tokio::test]
49 async fn test_pancakeswap_v2_try_from() {
50 let snapshot = ComponentWithState {
51 state: ResponseProtocolState {
52 component_id: "State1".to_owned(),
53 attributes: HashMap::from([
54 ("reserve0".to_string(), Bytes::from(vec![0; 32])),
55 ("reserve1".to_string(), Bytes::from(vec![0; 32])),
56 ]),
57 balances: HashMap::new(),
58 },
59 component: Default::default(),
60 component_tvl: None,
61 entrypoints: Vec::new(),
62 };
63
64 let result = try_decode_snapshot_with_defaults::<PancakeswapV2State>(snapshot).await;
65
66 assert!(result.is_ok());
67 assert_eq!(result.unwrap(), PancakeswapV2State::new(U256::from(0u64), U256::from(0u64)));
68 }
69
70 #[tokio::test]
71 #[rstest]
72 #[case::missing_reserve0("reserve0")]
73 #[case::missing_reserve1("reserve1")]
74 async fn test_pancakeswap_v2_try_from_missing_attribute(#[case] missing_attribute: &str) {
75 let mut attributes = HashMap::from([
76 ("reserve0".to_string(), Bytes::from(vec![0; 32])),
77 ("reserve1".to_string(), Bytes::from(vec![0; 32])),
78 ]);
79 attributes.remove(missing_attribute);
80
81 let snapshot = ComponentWithState {
82 state: ResponseProtocolState {
83 component_id: "State1".to_owned(),
84 attributes,
85 balances: HashMap::new(),
86 },
87 component: Default::default(),
88 component_tvl: None,
89 entrypoints: Vec::new(),
90 };
91
92 let result = try_decode_snapshot_with_defaults::<PancakeswapV2State>(snapshot).await;
93
94 assert!(result.is_err());
95 assert!(matches!(
96 result.unwrap_err(),
97 InvalidSnapshotError::MissingAttribute(ref x) if x == missing_attribute
98 ));
99 }
100}