vertex_sdk/vertex_utils/
subaccount_info.rs1use std::collections::HashMap;
2
3use eyre::{eyre, Result};
4
5use crate::bindings::querier::{HealthInfo, PerpBalance, PerpProduct, SpotBalance};
6use crate::engine::{AllProductsResponse, SpotProduct, SubaccountInfoResponse};
7
8impl SubaccountInfoResponse {
9 pub fn get_spot_balance(&self, product_id: u32) -> Result<&SpotBalance> {
10 let balance = self
11 .spot_balances
12 .iter()
13 .find(|&balance| balance.product_id == product_id)
14 .ok_or(eyre!(
15 "spot balance not found for product_id: {}",
16 product_id
17 ))?;
18 Ok(balance)
19 }
20
21 pub fn get_perp_balance(&self, product_id: u32) -> Result<&PerpBalance> {
22 let balance = self
23 .perp_balances
24 .iter()
25 .find(|&balance| balance.product_id == product_id)
26 .ok_or(eyre!(
27 "spot balance not found for product_id: {}",
28 product_id
29 ))?;
30 Ok(balance)
31 }
32
33 pub fn get_spot_product(&self, product_id: u32) -> Result<&SpotProduct> {
34 let product = self
35 .spot_products
36 .iter()
37 .find(|&product| product.product_id == product_id)
38 .ok_or(eyre!(
39 "spot product not found for product_id: {}",
40 product_id
41 ))?;
42 Ok(product)
43 }
44
45 pub fn get_perp_product(&self, product_id: u32) -> Result<&PerpProduct> {
46 let product = self
47 .perp_products
48 .iter()
49 .find(|&product| product.product_id == product_id)
50 .ok_or(eyre!(
51 "perp product not found for product_id: {}",
52 product_id
53 ))?;
54 Ok(product)
55 }
56
57 pub fn get_product_balances(&self, product_ids: Vec<u32>) -> Result<Vec<i128>> {
58 let mut ret = vec![];
59 for product_id in &product_ids {
60 if *product_id != 0 && *product_id % 2 == 0 {
61 let balance = self.get_perp_balance(*product_id)?;
62 ret.push(balance.balance.amount);
63 } else {
64 let balance = self.get_spot_balance(*product_id)?;
65 ret.push(balance.balance.amount);
66 }
67 }
68 let mut quote_bias = 0;
69 for product_id in [2, 4, 6] {
70 let balance = self.get_perp_balance(product_id)?;
71 quote_bias += balance.balance.v_quote_balance;
72 }
73 for index in 0..product_ids.len() {
74 if product_ids[index] == 0 {
75 ret[index] += quote_bias;
76 }
77 }
78 Ok(ret)
79 }
80
81 pub fn get_lp_balances(&self, product_ids: Vec<u32>) -> Result<Vec<i128>> {
82 let mut ret = vec![];
83 for product_id in &product_ids {
84 if *product_id != 0 && *product_id % 2 == 0 {
85 let balance = self.get_perp_balance(*product_id)?;
86 ret.push(balance.lp_balance.amount);
87 } else {
88 let balance = self.get_spot_balance(*product_id)?;
89 ret.push(balance.lp_balance.amount);
90 }
91 }
92 Ok(ret)
93 }
94
95 pub fn with_corrected_fees(&mut self, all_products: AllProductsResponse) -> Self {
96 let mut subaccount_info = self.clone();
97
98 let mut spot_products_without_collected_fees = all_products.spot_products.clone();
99 let mut perp_products_without_collected_fees = all_products.perp_products.clone();
100 for spot_product in &mut spot_products_without_collected_fees {
101 spot_product.book_info.collected_fees = 0;
102 }
103 for perp_product in &mut perp_products_without_collected_fees {
104 perp_product.book_info.collected_fees = 0;
105 }
106
107 let mut subaccount_info_clone = subaccount_info.clone();
108
109 for spot_product in subaccount_info_clone.spot_products.iter_mut() {
110 spot_product.book_info.price_increment_x18 = 0;
111 }
112 for perp_product in subaccount_info_clone.perp_products.iter_mut() {
113 perp_product.book_info.price_increment_x18 = 0;
114 }
115
116 assert_eq!(
117 subaccount_info_clone.spot_products,
118 spot_products_without_collected_fees
119 );
120 assert_eq!(
121 subaccount_info_clone.perp_products,
122 perp_products_without_collected_fees
123 );
124 subaccount_info.spot_products = all_products.spot_products;
125 subaccount_info.perp_products = all_products.perp_products;
126 subaccount_info
127 }
128
129 pub fn validate_size_increments(&self) {
130 let mut size_increments: HashMap<u32, i128> = HashMap::new();
131 for perp_product in self.perp_products.iter() {
132 if perp_product.book_info.size_increment == 0
133 && perp_product.risk.long_weight_initial_x18 == 0
134 && perp_product.oracle_price_x18 == 0
135 {
136 continue;
138 }
139 let open_interest = perp_product.state.open_interest;
140 let size_increment = perp_product.book_info.size_increment;
141 size_increments.insert(perp_product.product_id, size_increment);
142 assert_eq!(open_interest % size_increment, 0);
143 }
144 for perp_balance in self.perp_balances.iter() {
145 if !size_increments.contains_key(&perp_balance.product_id) {
146 continue;
147 }
148 let balance = perp_balance.balance.amount;
149 let size_increment = size_increments.get(&perp_balance.product_id).unwrap();
150 assert_eq!(balance % size_increment, 0);
151 }
152 }
153
154 pub fn get_states(&self, product_ids: Vec<u32>) -> Result<Vec<Vec<i128>>> {
155 let mut ret = vec![];
156 for product_id in product_ids {
157 let mut state = vec![];
158 if product_id != 0 && product_id % 2 == 0 {
159 let perp = self.get_perp_product(product_id)?;
160 state.push(perp.state.cumulative_funding_long_x18);
161 state.push(perp.state.cumulative_funding_short_x18);
162 state.push(perp.state.open_interest);
163 } else {
164 let spot = self.get_spot_product(product_id)?;
165 state.push(spot.state.cumulative_deposits_multiplier_x18);
166 state.push(spot.state.cumulative_borrows_multiplier_x18);
167 state.push(spot.state.total_deposits_normalized);
168 state.push(spot.state.total_borrows_normalized);
169 }
170 ret.push(state);
171 }
172 Ok(ret)
173 }
174
175 pub fn get_lp_states(&self, product_ids: Vec<u32>) -> Result<Vec<Vec<i128>>> {
176 let mut ret = vec![];
177 for product_id in product_ids {
178 let mut lp_state = vec![];
179 if product_id != 0 && product_id % 2 == 0 {
180 let perp = self.get_perp_product(product_id)?;
181 lp_state.push(perp.lp_state.supply);
182 lp_state.push(perp.lp_state.base);
183 lp_state.push(perp.lp_state.quote);
184 } else {
185 let spot = self.get_spot_product(product_id)?;
186 lp_state.push(spot.lp_state.supply);
187 lp_state.push(spot.lp_state.base.amount);
188 lp_state.push(spot.lp_state.quote.amount);
189 }
190 ret.push(lp_state)
191 }
192 Ok(ret)
193 }
194
195 pub fn get_health_info(&self) -> (HealthInfo, HealthInfo, HealthInfo) {
196 (
197 self.healths[0].clone(),
198 self.healths[1].clone(),
199 self.healths[2].clone(),
200 )
201 }
202}