evm_dex_pool/erc4626/
standard.rs1use crate::contracts::IERC4626;
2use crate::pool::base::{EventApplicable, TopicList};
3use alloy::sol_types::SolEvent;
4use alloy::{
5 primitives::{Address, FixedBytes, U256},
6 rpc::types::Log,
7};
8use anyhow::{anyhow, Result};
9use serde::{Deserialize, Serialize};
10use std::any::Any;
11use std::fmt;
12
13const FEE_DENOMINATOR: u128 = 1000000;
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct ERC4626Standard {
17 pub address: Address,
19 pub vault_token: Address,
21 pub asset_token: Address,
23 pub vault_reserve: U256,
25 pub asset_reserve: U256,
27 pub deposit_fee: u32,
29 pub withdraw_fee: u32,
31}
32
33impl ERC4626Standard {
34 pub fn new(
35 address: Address,
36 vault_token: Address,
37 asset_token: Address,
38 vault_reserve: U256,
39 asset_reserve: U256,
40 deposit_fee: u32,
41 withdraw_fee: u32,
42 ) -> Self {
43 Self {
44 address,
45 vault_token,
46 asset_token,
47 vault_reserve,
48 asset_reserve,
49 deposit_fee,
50 withdraw_fee,
51 }
52 }
53
54 pub fn address(&self) -> Address {
55 self.address
56 }
57
58 pub fn calculate_output(&self, token_in: &Address, amount_in: U256) -> Result<U256> {
60 if amount_in.is_zero() {
61 return Ok(U256::ZERO);
62 }
63
64 if self.vault_reserve.is_zero() {
65 return Ok(amount_in);
66 }
67
68 let (fee, reserve_in, reserve_out) = if token_in.eq(&self.vault_token) {
69 (self.withdraw_fee, self.vault_reserve, self.asset_reserve)
70 } else {
71 (self.deposit_fee, self.asset_reserve, self.vault_reserve)
72 };
73
74 Ok(
75 amount_in * reserve_out / reserve_in * U256::from(FEE_DENOMINATOR - fee as u128)
76 / U256::from(FEE_DENOMINATOR),
77 )
78 }
79
80 pub fn calculate_input(&self, token_out: &Address, amount_out: U256) -> Result<U256> {
82 if amount_out.is_zero() {
83 return Ok(U256::ZERO);
84 }
85
86 if self.asset_reserve.is_zero() {
87 return Ok(amount_out);
88 }
89
90 let (fee, reserve_in, reserve_out) = if token_out.eq(&self.vault_token) {
91 (self.withdraw_fee, self.vault_reserve, self.asset_reserve)
92 } else {
93 (self.deposit_fee, self.asset_reserve, self.vault_reserve)
94 };
95
96 Ok(
97 amount_out * reserve_in / reserve_out * U256::from(FEE_DENOMINATOR - fee as u128)
98 / U256::from(FEE_DENOMINATOR),
99 )
100 }
101
102 pub fn apply_swap(
104 &mut self,
105 _token_in: &Address,
106 _amount_in: U256,
107 _amount_out: U256,
108 ) -> Result<()> {
109 Err(anyhow!("Not implemented"))
110 }
111
112 pub fn tokens(&self) -> (Address, Address) {
114 (self.vault_token, self.asset_token)
115 }
116
117 pub fn fee(&self) -> f64 {
119 self.deposit_fee as f64 / FEE_DENOMINATOR as f64
120 }
121
122 pub fn fee_raw(&self) -> u64 {
123 self.deposit_fee as u64
124 }
125
126 pub fn id(&self) -> String {
128 self.address.to_string()
129 }
130
131 pub fn contains_token(&self, token: &Address) -> bool {
133 *token == self.vault_token || *token == self.asset_token
134 }
135
136 pub fn log_summary(&self) -> String {
138 format!(
139 "ERC4626 Standard Pool {} - {} (reserves: {}, {})",
140 self.vault_token, self.asset_token, self.vault_reserve, self.asset_reserve
141 )
142 }
143
144 pub fn as_any(&self) -> &dyn Any {
145 self
146 }
147
148 pub fn as_any_mut(&mut self) -> &mut dyn Any {
149 self
150 }
151}
152
153impl EventApplicable for ERC4626Standard {
154 fn apply_log(&mut self, log: &Log) -> Result<()> {
155 match log.topic0() {
156 Some(&IERC4626::Deposit::SIGNATURE_HASH) => {
157 let deposit_data: IERC4626::Deposit = log.log_decode()?.inner.data;
158 self.vault_reserve += deposit_data.shares;
159 self.asset_reserve += deposit_data.assets;
160 }
161 Some(&IERC4626::Withdraw::SIGNATURE_HASH) => {
162 let withdraw_data: IERC4626::Withdraw = log.log_decode()?.inner.data;
163 self.vault_reserve -= withdraw_data.shares;
164 self.asset_reserve -= withdraw_data.assets;
165 }
166 _ => return Ok(()),
167 }
168 Ok(())
169 }
170}
171
172impl TopicList for ERC4626Standard {
173 fn topics() -> Vec<FixedBytes<32>> {
174 vec![
175 IERC4626::Deposit::SIGNATURE_HASH,
176 IERC4626::Withdraw::SIGNATURE_HASH,
177 ]
178 }
179
180 fn profitable_topics() -> Vec<FixedBytes<32>> {
181 vec![
182 IERC4626::Deposit::SIGNATURE_HASH,
183 IERC4626::Withdraw::SIGNATURE_HASH,
184 ]
185 }
186}
187
188impl fmt::Display for ERC4626Standard {
189 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190 write!(
191 f,
192 "ERC4626 Standard Pool {} - {} (reserves: {}, {})",
193 self.vault_token, self.asset_token, self.vault_reserve, self.asset_reserve
194 )
195 }
196}