tycho_simulation/evm/protocol/etherfi/
decoder.rs1use std::collections::HashMap;
2
3use alloy::primitives::U256;
4use tycho_client::feed::{synchronizer::ComponentWithState, BlockHeader};
5use tycho_common::{models::token::Token, Bytes};
6
7use crate::{
8 evm::protocol::etherfi::state::{BucketLimit, EtherfiState, RedemptionInfo, EETH_ADDRESS},
9 protocol::{
10 errors::InvalidSnapshotError,
11 models::{DecoderContext, TryFromWithBlock},
12 },
13};
14
15impl TryFromWithBlock<ComponentWithState, BlockHeader> for EtherfiState {
16 type Error = InvalidSnapshotError;
17
18 async fn try_from_with_header(
19 snapshot: ComponentWithState,
20 block: BlockHeader,
21 _account_balances: &HashMap<Bytes, HashMap<Bytes, Bytes>>,
22 _all_tokens: &HashMap<Bytes, Token>,
23 _decoder_context: &DecoderContext,
24 ) -> Result<Self, Self::Error> {
25 let total_value_out_of_lp = U256::from_be_slice(
26 snapshot
27 .state
28 .attributes
29 .get("totalValueOutOfLp")
30 .ok_or_else(|| {
31 InvalidSnapshotError::MissingAttribute("totalValueOutOfLp".to_string())
32 })?,
33 );
34
35 let total_value_in_lp = U256::from_be_slice(
36 snapshot
37 .state
38 .attributes
39 .get("totalValueInLp")
40 .ok_or_else(|| {
41 InvalidSnapshotError::MissingAttribute("totalValueInLp".to_string())
42 })?,
43 );
44
45 let total_shares = U256::from_be_slice(
46 snapshot
47 .state
48 .attributes
49 .get("totalShares")
50 .ok_or_else(|| InvalidSnapshotError::MissingAttribute("totalShares".to_string()))?,
51 );
52
53 let mut liquidity_pool_native_balance: Option<U256> = None;
54 let mut eth_amount_locked_for_withdrawl: Option<U256> = None;
55 let mut eth_redemption_info: Option<RedemptionInfo> = None;
56
57 if snapshot.component.id == format!("0x{}", hex::encode(EETH_ADDRESS)) {
58 liquidity_pool_native_balance = Some(U256::from_be_slice(
59 snapshot
60 .state
61 .attributes
62 .get("liquidityPoolNativeBalance")
63 .ok_or_else(|| {
64 InvalidSnapshotError::MissingAttribute(
65 "liquidityPoolNativeBalance".to_string(),
66 )
67 })?,
68 ));
69 eth_amount_locked_for_withdrawl = Some(U256::from_be_slice(
70 snapshot
71 .state
72 .attributes
73 .get("ethAmountLockedForWithdrawl")
74 .ok_or_else(|| {
75 InvalidSnapshotError::MissingAttribute(
76 "ethAmountLockedForWithdrawl".to_string(),
77 )
78 })?,
79 ));
80
81 let eth_bucket_limiter_raw = snapshot
82 .state
83 .attributes
84 .get("ethBucketLimiter")
85 .ok_or_else(|| {
86 InvalidSnapshotError::MissingAttribute("ethBucketLimiter".to_string())
87 })?;
88 let eth_bucket_limiter_value = U256::from_be_slice(eth_bucket_limiter_raw);
89
90 let eth_redemption_info_raw = snapshot
91 .state
92 .attributes
93 .get("ethRedemptionInfo")
94 .ok_or_else(|| {
95 InvalidSnapshotError::MissingAttribute("ethRedemptionInfo".to_string())
96 })?;
97 let eth_redemption_info_value = U256::from_be_slice(eth_redemption_info_raw);
98
99 eth_redemption_info = Some(RedemptionInfo::from_u256(
100 BucketLimit::from_u256(eth_bucket_limiter_value),
101 eth_redemption_info_value,
102 ));
103 }
104
105 Ok(EtherfiState::new(
106 block.timestamp,
107 total_value_out_of_lp,
108 total_value_in_lp,
109 total_shares,
110 eth_amount_locked_for_withdrawl,
111 eth_redemption_info,
112 liquidity_pool_native_balance,
113 ))
114 }
115}