tycho_simulation/evm/protocol/cowamm/
decoder.rs1use std::collections::HashMap;
2
3use alloy::primitives::U256;
4use tycho_client::feed::{synchronizer::ComponentWithState, BlockHeader};
5use tycho_common::{
6 models::{protocol::ProtocolComponent, token::Token},
7 Bytes,
8};
9
10use crate::{
11 evm::protocol::cowamm::state::CowAMMState,
12 protocol::{
13 errors::InvalidSnapshotError,
14 models::{DecoderContext, TryFromWithBlock},
15 },
16};
17
18impl TryFromWithBlock<ComponentWithState, BlockHeader> for CowAMMState {
19 type Error = InvalidSnapshotError;
20
21 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 address = snapshot
29 .component
30 .static_attributes
31 .get("address")
32 .ok_or_else(|| InvalidSnapshotError::MissingAttribute("address".to_string()))?
33 .clone();
34
35 let token_a = snapshot
36 .component
37 .static_attributes
38 .get("token_a")
39 .ok_or_else(|| InvalidSnapshotError::MissingAttribute("token_a".to_string()))?
40 .clone();
41
42 let liquidity_a = U256::from_be_slice(
43 snapshot
44 .state
45 .attributes
46 .get("liquidity_a")
47 .ok_or_else(|| InvalidSnapshotError::MissingAttribute("liquidity_a".to_string()))?
48 .as_ref(),
49 );
50
51 let liquidity_b = U256::from_be_slice(
52 snapshot
53 .state
54 .attributes
55 .get("liquidity_b")
56 .ok_or_else(|| InvalidSnapshotError::MissingAttribute("liquidity_b".to_string()))?
57 .as_ref(),
58 );
59
60 let token_b = snapshot
61 .component
62 .static_attributes
63 .get("token_b")
64 .ok_or_else(|| InvalidSnapshotError::MissingAttribute("token_b".to_string()))?
65 .clone();
66
67 let lp_token = snapshot
68 .component
69 .static_attributes
70 .get("lp_token")
71 .ok_or_else(|| InvalidSnapshotError::MissingAttribute("lp_token".to_string()))?
72 .clone();
73
74 let lp_token_supply = U256::from_be_slice(
75 snapshot
76 .state
77 .attributes
78 .get("lp_token_supply")
79 .ok_or_else(|| {
80 InvalidSnapshotError::MissingAttribute("lp_token_supply".to_string())
81 })?
82 .as_ref(),
83 );
84
85 let fee = 0u64;
86
87 let weight_a = U256::from_be_slice(
91 snapshot
92 .component
93 .static_attributes
94 .get("weight_a")
95 .ok_or_else(|| InvalidSnapshotError::MissingAttribute("weight_a".to_string()))?
96 .as_ref(),
97 );
98
99 let weight_b = U256::from_be_slice(
100 snapshot
101 .component
102 .static_attributes
103 .get("weight_b")
104 .ok_or_else(|| InvalidSnapshotError::MissingAttribute("weight_b".to_string()))?
105 .as_ref(),
106 );
107
108 Ok(Self::new(
109 address,
110 token_a,
111 token_b,
112 liquidity_a,
113 liquidity_b,
114 lp_token,
115 lp_token_supply,
116 weight_a,
117 weight_b,
118 fee,
119 ))
120 }
121}
122
123pub fn attributes() -> HashMap<String, Bytes> {
124 HashMap::from([
125 ("liquidity_a".to_string(), Bytes::from(vec![0; 32])),
126 ("liquidity_b".to_string(), Bytes::from(vec![0; 32])),
127 ("lp_token_supply".to_string(), Bytes::from(vec![0; 32])),
128 ])
129}
130pub fn static_attributes() -> HashMap<String, Bytes> {
131 HashMap::from([
132 ("address".to_string(), Bytes::from(vec![0; 32])),
133 ("weight_a".to_string(), Bytes::from(vec![0; 32])),
134 ("weight_b".to_string(), Bytes::from(vec![0; 32])),
135 ("token_a".to_string(), Bytes::from(vec![0; 32])),
136 ("token_b".to_string(), Bytes::from(vec![0; 32])),
137 ("lp_token".to_string(), Bytes::from(vec![0; 32])),
138 ("fee".to_string(), 0u64.into()),
139 ])
140}
141
142pub fn component() -> ProtocolComponent {
143 ProtocolComponent { static_attributes: static_attributes(), ..Default::default() }
144}
145
146pub fn state() -> CowAMMState {
147 CowAMMState::new(
148 Bytes::from(vec![0; 32]),
149 Bytes::from(vec![0; 32]),
150 Bytes::from(vec![0; 32]),
151 U256::from(0),
152 U256::from(0),
153 Bytes::from(vec![0; 32]),
154 U256::from(0),
155 U256::from(0),
156 U256::from(0),
157 0u64,
158 )
159}
160
161#[cfg(test)]
162mod tests {
163 use rstest::rstest;
164 use tycho_common::models::protocol::ProtocolComponentState;
165
166 use super::*;
167 use crate::evm::protocol::test_utils::try_decode_snapshot_with_defaults;
168
169 #[tokio::test]
170 async fn test_cowamm_try_from_with_block() {
171 let snapshot = ComponentWithState {
172 state: ProtocolComponentState {
173 component_id: String::new(),
174 attributes: attributes(),
175 balances: HashMap::new(),
176 },
177 component: component(),
178 component_tvl: None,
179 entrypoints: Vec::new(),
180 };
181
182 let result = try_decode_snapshot_with_defaults::<CowAMMState>(snapshot)
183 .await
184 .expect("reconstructing state");
185
186 assert_eq!(state(), result);
187 }
188
189 #[tokio::test]
190 #[rstest]
191 #[case::missing_weight_a("address")]
192 #[case::missing_weight_a("weight_a")]
193 #[case::missing_weight_b("weight_b")]
194 #[case::missing_token_a("token_a")]
195 #[case::missing_token_b("token_b")]
196 #[case::missing_liquidity_a("liquidity_a")]
197 #[case::missing_liquidity_b("liquidity_b")]
198 #[case::missing_lp_token("lp_token")]
199 #[case::missing_lp_token_supply("lp_token_supply")]
200
201 async fn test_cowamm_try_from_missing_attribute(#[case] missing_attribute: &str) {
202 let mut component = component();
203 let mut attributes = attributes();
204
205 let _ = match missing_attribute {
206 "liquidity_a" | "liquidity_b" | "lp_token_supply" => {
207 attributes.remove(missing_attribute)
208 }
209 "address" | "weight_a" | "weight_b" | "token_a" | "token_b" | "lp_token" => component
210 .static_attributes
211 .remove(missing_attribute),
212 &_ => None,
213 };
214
215 let snapshot = ComponentWithState {
216 state: ProtocolComponentState {
217 component_id: "State1".to_owned(),
218 attributes,
219 balances: HashMap::new(),
220 },
221 component,
222 component_tvl: None,
223 entrypoints: Vec::new(),
224 };
225
226 let result = try_decode_snapshot_with_defaults::<CowAMMState>(snapshot).await;
227
228 assert!(result.is_err());
229 assert!(matches!(
230 result.unwrap_err(),
231 InvalidSnapshotError::MissingAttribute(ref attr) if attr == missing_attribute
232 ));
233 }
234}