1use std::{
2 collections::{HashMap, HashSet},
3 sync::Arc,
4};
5
6use chrono::NaiveDateTime;
7use deepsize::{Context, DeepSizeOf};
8use num_bigint::BigUint;
9use serde::{Deserialize, Serialize};
10
11use crate::{
12 dto,
13 models::{
14 token::Token, Address, AttrStoreKey, Balance, Chain, ChangeType, ComponentId, MergeError,
15 StoreVal, TxHash,
16 },
17 Bytes,
18};
19
20#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
32pub struct ProtocolComponent<Token: Into<Address> + Clone = Address> {
33 pub id: ComponentId,
34 pub protocol_system: String,
35 pub protocol_type_name: String,
36 pub chain: Chain,
37 pub tokens: Vec<Token>,
38 pub contract_addresses: Vec<Address>,
39 pub static_attributes: HashMap<AttrStoreKey, StoreVal>,
40 pub change: ChangeType,
41 pub creation_tx: TxHash,
42 pub created_at: NaiveDateTime,
43}
44
45impl<T> ProtocolComponent<T>
46where
47 T: Into<Address> + Clone,
48{
49 #[allow(clippy::too_many_arguments)]
50 pub fn new(
51 id: &str,
52 protocol_system: &str,
53 protocol_type_name: &str,
54 chain: Chain,
55 tokens: Vec<T>,
56 contract_addresses: Vec<Address>,
57 static_attributes: HashMap<AttrStoreKey, StoreVal>,
58 change: ChangeType,
59 creation_tx: TxHash,
60 created_at: NaiveDateTime,
61 ) -> Self {
62 Self {
63 id: id.to_string(),
64 protocol_system: protocol_system.to_string(),
65 protocol_type_name: protocol_type_name.to_string(),
66 chain,
67 tokens,
68 contract_addresses,
69 static_attributes,
70 change,
71 creation_tx,
72 created_at,
73 }
74 }
75}
76
77impl ProtocolComponent<Arc<Token>> {
78 pub fn get_token(&self, address: &Address) -> Option<Arc<Token>> {
79 self.tokens
80 .iter()
81 .find(|t| &t.address == address)
82 .map(Arc::clone)
83 }
84}
85
86impl DeepSizeOf for ProtocolComponent {
87 fn deep_size_of_children(&self, ctx: &mut Context) -> usize {
88 self.id.deep_size_of_children(ctx) +
89 self.protocol_system
90 .deep_size_of_children(ctx) +
91 self.protocol_type_name
92 .deep_size_of_children(ctx) +
93 self.chain.deep_size_of_children(ctx) +
94 self.tokens.deep_size_of_children(ctx) +
95 self.contract_addresses
96 .deep_size_of_children(ctx) +
97 self.static_attributes
98 .deep_size_of_children(ctx) +
99 self.change.deep_size_of_children(ctx) +
100 self.creation_tx
101 .deep_size_of_children(ctx)
102 }
103}
104
105#[derive(Debug, Clone, PartialEq)]
106pub struct ProtocolComponentState {
107 pub component_id: ComponentId,
108 pub attributes: HashMap<AttrStoreKey, StoreVal>,
109 pub balances: HashMap<Address, Balance>,
111}
112
113impl ProtocolComponentState {
114 pub fn new(
115 component_id: &str,
116 attributes: HashMap<AttrStoreKey, StoreVal>,
117 balances: HashMap<Address, Balance>,
118 ) -> Self {
119 Self { component_id: component_id.to_string(), attributes, balances }
120 }
121
122 pub fn apply_state_delta(
126 &mut self,
127 delta: &ProtocolComponentStateDelta,
128 ) -> Result<(), MergeError> {
129 if self.component_id != delta.component_id {
130 return Err(MergeError::IdMismatch(
131 "ProtocolComponentStates".to_string(),
132 self.component_id.clone(),
133 delta.component_id.clone(),
134 ));
135 }
136 self.attributes
137 .extend(delta.updated_attributes.clone());
138
139 self.attributes
140 .retain(|attr, _| !delta.deleted_attributes.contains(attr));
141
142 Ok(())
143 }
144
145 pub fn apply_balance_delta(
149 &mut self,
150 delta: &HashMap<Bytes, ComponentBalance>,
151 ) -> Result<(), MergeError> {
152 self.balances.extend(
153 delta
154 .iter()
155 .map(|(k, v)| (k.clone(), v.balance.clone())),
156 );
157
158 Ok(())
159 }
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, DeepSizeOf)]
163pub struct ProtocolComponentStateDelta {
164 pub component_id: ComponentId,
165 pub updated_attributes: HashMap<AttrStoreKey, StoreVal>,
166 pub deleted_attributes: HashSet<AttrStoreKey>,
167}
168
169impl ProtocolComponentStateDelta {
170 pub fn new(
171 component_id: &str,
172 updated_attributes: HashMap<AttrStoreKey, StoreVal>,
173 deleted_attributes: HashSet<AttrStoreKey>,
174 ) -> Self {
175 Self { component_id: component_id.to_string(), updated_attributes, deleted_attributes }
176 }
177
178 pub fn merge(&mut self, other: ProtocolComponentStateDelta) -> Result<(), MergeError> {
190 if self.component_id != other.component_id {
191 return Err(MergeError::IdMismatch(
192 "ProtocolComponentStateDeltas".to_string(),
193 self.component_id.clone(),
194 other.component_id.clone(),
195 ));
196 }
197 for attr in &other.deleted_attributes {
198 self.updated_attributes.remove(attr);
199 }
200 for attr in other.updated_attributes.keys() {
201 self.deleted_attributes.remove(attr);
202 }
203 self.updated_attributes
204 .extend(other.updated_attributes);
205 self.deleted_attributes
206 .extend(other.deleted_attributes);
207 Ok(())
208 }
209}
210
211#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, DeepSizeOf)]
212pub struct ComponentBalance {
213 pub token: Address,
214 pub balance: Balance,
215 pub balance_float: f64,
216 pub modify_tx: TxHash,
217 pub component_id: ComponentId,
218}
219
220impl ComponentBalance {
221 pub fn new(
222 token: Address,
223 new_balance: Balance,
224 balance_float: f64,
225 modify_tx: TxHash,
226 component_id: &str,
227 ) -> Self {
228 Self {
229 token,
230 balance: new_balance,
231 balance_float,
232 modify_tx,
233 component_id: component_id.to_string(),
234 }
235 }
236}
237
238#[derive(Debug, Clone)]
242pub struct QualityRange {
243 pub min: Option<i32>,
244 pub max: Option<i32>,
245}
246
247impl QualityRange {
248 pub fn new(min: i32, max: i32) -> Self {
249 Self { min: Some(min), max: Some(max) }
250 }
251
252 pub fn min_only(min: i32) -> Self {
253 Self { min: Some(min), max: None }
254 }
255
256 #[allow(non_snake_case)]
257 pub fn None() -> Self {
258 Self { min: None, max: None }
259 }
260}
261
262pub struct GetAmountOutParams {
263 pub amount_in: BigUint,
264 pub token_in: Bytes,
265 pub token_out: Bytes,
266 pub sender: Bytes,
267 pub receiver: Bytes,
268}
269
270impl From<dto::ProtocolStateDelta> for ProtocolComponentStateDelta {
271 fn from(value: dto::ProtocolStateDelta) -> Self {
272 Self {
273 component_id: value.component_id,
274 updated_attributes: value.updated_attributes,
275 deleted_attributes: value.deleted_attributes,
276 }
277 }
278}
279
280impl From<dto::ComponentBalance> for ComponentBalance {
281 fn from(value: dto::ComponentBalance) -> Self {
282 Self {
283 token: value.token,
284 balance: value.balance,
285 balance_float: value.balance_float,
286 modify_tx: value.modify_tx,
287 component_id: value.component_id,
288 }
289 }
290}
291
292impl From<dto::ProtocolComponent> for ProtocolComponent {
293 fn from(value: dto::ProtocolComponent) -> Self {
294 Self {
295 id: value.id,
296 protocol_system: value.protocol_system,
297 protocol_type_name: value.protocol_type_name,
298 chain: value.chain.into(),
299 tokens: value.tokens,
300 contract_addresses: value.contract_ids,
301 static_attributes: value.static_attributes,
302 change: value.change.into(),
303 creation_tx: value.creation_tx,
304 created_at: value.created_at,
305 }
306 }
307}
308
309impl From<dto::ResponseProtocolState> for ProtocolComponentState {
310 fn from(value: dto::ResponseProtocolState) -> Self {
311 Self {
312 component_id: value.component_id,
313 attributes: value.attributes,
314 balances: value.balances,
315 }
316 }
317}
318
319#[cfg(test)]
320mod test {
321 use super::*;
322
323 fn create_state(id: String) -> ProtocolComponentStateDelta {
324 let attributes1: HashMap<String, Bytes> = vec![
325 ("reserve1".to_owned(), Bytes::from(1000u64).lpad(32, 0)),
326 ("reserve2".to_owned(), Bytes::from(500u64).lpad(32, 0)),
327 ("static_attribute".to_owned(), Bytes::from(1u64).lpad(32, 0)),
328 ]
329 .into_iter()
330 .collect();
331 ProtocolComponentStateDelta {
332 component_id: id,
333 updated_attributes: attributes1,
334 deleted_attributes: HashSet::new(),
335 }
336 }
337
338 #[test]
339 fn test_merge_protocol_state_updates() {
340 let mut state_1 = create_state("State1".to_owned());
341 state_1
342 .updated_attributes
343 .insert("to_be_removed".to_owned(), Bytes::from(1u64).lpad(32, 0));
344 state_1.deleted_attributes = vec!["to_add_back".to_owned()]
345 .into_iter()
346 .collect();
347
348 let attributes2: HashMap<String, Bytes> = vec![
349 ("reserve1".to_owned(), Bytes::from(900u64).lpad(32, 0)),
350 ("reserve2".to_owned(), Bytes::from(550u64).lpad(32, 0)),
351 ("new_attribute".to_owned(), Bytes::from(1u64).lpad(32, 0)),
352 ("to_add_back".to_owned(), Bytes::from(200u64).lpad(32, 0)),
353 ]
354 .into_iter()
355 .collect();
356 let del_attributes2: HashSet<String> = vec!["to_be_removed".to_owned()]
357 .into_iter()
358 .collect();
359 let mut state_2 = create_state("State1".to_owned());
360 state_2.updated_attributes = attributes2;
361 state_2.deleted_attributes = del_attributes2;
362
363 let res = state_1.merge(state_2);
364
365 assert!(res.is_ok());
366 let expected_attributes: HashMap<String, Bytes> = vec![
367 ("reserve1".to_owned(), Bytes::from(900u64).lpad(32, 0)),
368 ("reserve2".to_owned(), Bytes::from(550u64).lpad(32, 0)),
369 ("static_attribute".to_owned(), Bytes::from(1u64).lpad(32, 0)),
370 ("new_attribute".to_owned(), Bytes::from(1u64).lpad(32, 0)),
371 ("to_add_back".to_owned(), Bytes::from(200u64).lpad(32, 0)),
372 ]
373 .into_iter()
374 .collect();
375 assert_eq!(state_1.updated_attributes, expected_attributes);
376 let expected_del_attributes: HashSet<String> = vec!["to_be_removed".to_owned()]
377 .into_iter()
378 .collect();
379 assert_eq!(state_1.deleted_attributes, expected_del_attributes);
380 }
381
382 #[test]
383 fn test_merge_protocol_state_update_wrong_id() {
384 let mut state1 = create_state("State1".to_owned());
385 let state2 = create_state("State2".to_owned());
386
387 let res = state1.merge(state2);
388
389 assert_eq!(
390 res,
391 Err(MergeError::IdMismatch(
392 "ProtocolComponentStateDeltas".to_string(),
393 "State1".to_string(),
394 "State2".to_string(),
395 ))
396 );
397 }
398}