af_iperps/event_ext/
apply.rs

1//! Helpers for updating off-chain data with event content
2use af_move_type::otw::Otw;
3use af_utilities::types::IFixed;
4
5use crate::account::Account;
6use crate::clearing_house::{ClearingHouse, Vault};
7use crate::events;
8use crate::orderbook::Order;
9use crate::position::Position;
10
11/// Intended for defining how to update off-chain data with event information.
12pub trait Apply<T> {
13    /// Use the contents of `self` to (possibly) mutate data in `target`.
14    fn apply(&self, target: &mut T);
15}
16
17/// Convenience tool for implementing [`Apply`] for events that contain the values of attributes to
18/// set in an object.
19///
20/// The implementations here don't handle how to fetch each object, that is up to the application.
21///
22/// For instance, one database might store only a single [`Position`] and ignore the `ch_id` and
23/// `account_id` fields of the relevant events because those are already filtered for in the
24/// WebSocket event subscriber.
25///
26/// On the other hand, another database might store several positions in a `HashMap` and use the
27/// `account_id` field of the relevant events to fetch the [`Position`] from the map before passing
28/// it to `.apply()`.
29macro_rules! set_fields {
30    (
31        $(
32            $event_type:ty {
33                $(
34                    $object_type:ty {
35                        $(
36                            $event_field:ident => $($object_field:ident).+
37                        ),+ $(,)?
38                    }
39                )+
40            }
41        )*
42    ) => {
43        $(
44            $(
45                impl Apply<$object_type> for $event_type {
46                    fn apply(&self, target: &mut $object_type) {
47                        let Self {
48                            $($event_field,)+
49                            ..
50                        } = self;
51                        $(
52                            target.$($object_field).+ = $event_field.clone();
53                        )+
54                    }
55                }
56            )+
57        )*
58    };
59}
60
61set_fields! {
62    events::DepositedCollateral<Otw> {
63        Account<Otw> {
64            account_collateral_after => collateral.value
65        }
66    }
67
68    events::AllocatedCollateral {
69        Position {
70            position_collateral_after => collateral
71        }
72        Account<Otw> {
73            account_collateral_after => collateral.value
74        }
75        Vault<Otw> {
76            vault_balance_after => collateral_balance.value
77        }
78    }
79
80    events::WithdrewCollateral<Otw> {
81        Account<Otw> {
82            account_collateral_after => collateral.value
83        }
84    }
85
86    events::DeallocatedCollateral {
87        Account<Otw> {
88            account_collateral_after => collateral.value
89        }
90        Position {
91            position_collateral_after => collateral
92        }
93        Vault<Otw> {
94            vault_balance_after => collateral_balance.value
95        }
96    }
97
98    events::UpdatedPremiumTwap {
99        ClearingHouse<Otw> {
100            premium_twap => market_state.premium_twap,
101            premium_twap_last_upd_ms => market_state.premium_twap_last_upd_ms,
102        }
103    }
104
105    events::UpdatedSpreadTwap {
106        ClearingHouse<Otw> {
107            spread_twap => market_state.spread_twap,
108            spread_twap_last_upd_ms => market_state.spread_twap_last_upd_ms,
109        }
110    }
111
112    events::UpdatedFunding {
113        ClearingHouse<Otw> {
114            cum_funding_rate_long => market_state.cum_funding_rate_long,
115            cum_funding_rate_short => market_state.cum_funding_rate_short,
116            funding_last_upd_ms => market_state.funding_last_upd_ms,
117        }
118    }
119
120    events::UpdatedOpenInterestAndFeesAccrued {
121        ClearingHouse<Otw> {
122            open_interest => market_state.open_interest,
123            fees_accrued => market_state.fees_accrued,
124        }
125    }
126
127    events::SettledFunding {
128        Position {
129            collateral_after => collateral,
130            mkt_funding_rate_long => cum_funding_rate_long,
131            mkt_funding_rate_short => cum_funding_rate_short,
132        }
133    }
134
135    events::FilledMakerOrder {
136        Position {
137            maker_collateral => collateral,
138            maker_base_amount => base_asset_amount,
139            maker_quote_amount => quote_asset_notional_amount,
140            maker_pending_asks_quantity => asks_quantity,
141            maker_pending_bids_quantity => bids_quantity,
142        }
143    }
144
145    events::FilledTakerOrder {
146        Position {
147            taker_collateral => collateral,
148            taker_base_amount => base_asset_amount,
149            taker_quote_amount => quote_asset_notional_amount,
150        }
151    }
152
153    events::PostedOrder {
154        Position {
155            pending_asks => asks_quantity,
156            pending_bids => bids_quantity,
157            pending_orders => pending_orders,
158        }
159    }
160
161    events::CanceledOrders {
162        Position {
163            asks_quantity => asks_quantity,
164            bids_quantity => bids_quantity,
165            pending_orders => pending_orders,
166        }
167    }
168
169    events::UpdatedCumFundings {
170        ClearingHouse<Otw> {
171            cum_funding_rate_long => market_state.cum_funding_rate_long,
172            cum_funding_rate_short => market_state.cum_funding_rate_short,
173        }
174    }
175
176    events::UpdatedMarginRatios {
177        ClearingHouse<Otw> {
178            margin_ratio_initial => market_params.margin_ratio_initial,
179            margin_ratio_maintenance => market_params.margin_ratio_maintenance,
180        }
181    }
182
183    events::AcceptedPositionFeesProposal {
184        Position {
185            maker_fee => maker_fee,
186            taker_fee => taker_fee,
187        }
188    }
189
190    events::UpdatedFees {
191        ClearingHouse<Otw> {
192            maker_fee => market_params.maker_fee,
193            taker_fee => market_params.taker_fee,
194            liquidation_fee => market_params.liquidation_fee,
195            force_cancel_fee => market_params.force_cancel_fee,
196            insurance_fund_fee => market_params.insurance_fund_fee,
197        }
198    }
199
200    events::UpdatedFundingParameters {
201        ClearingHouse<Otw> {
202            funding_frequency_ms => market_params.funding_frequency_ms,
203            funding_period_ms => market_params.funding_period_ms,
204            premium_twap_frequency_ms => market_params.premium_twap_frequency_ms,
205            premium_twap_period_ms => market_params.premium_twap_period_ms,
206        }
207    }
208
209    events::UpdatedSpreadTwapParameters {
210        ClearingHouse<Otw> {
211            spread_twap_frequency_ms => market_params.spread_twap_frequency_ms,
212            spread_twap_period_ms => market_params.spread_twap_period_ms,
213        }
214    }
215
216    events::UpdatedMinOrderUsdValue {
217        ClearingHouse<Otw> {
218            min_order_usd_value => market_params.min_order_usd_value,
219        }
220    }
221
222    events::UpdatedLiquidationTolerance {
223        ClearingHouse<Otw> {
224            liquidation_tolerance => market_params.liquidation_tolerance,
225        }
226    }
227
228    events::UpdatedBaseOracleTolerance {
229        ClearingHouse<Otw> {
230            oracle_tolerance => market_params.base_oracle_tolerance,
231        }
232    }
233
234    events::UpdatedCollateralOracleTolerance {
235        ClearingHouse<Otw> {
236            oracle_tolerance => market_params.collateral_oracle_tolerance,
237        }
238    }
239
240    events::UpdatedMaxPendingOrders {
241        ClearingHouse<Otw> {
242            max_pending_orders => market_params.max_pending_orders,
243        }
244    }
245
246    events::DonatedToInsuranceFund {
247        Vault<Otw> {
248            new_balance => insurance_fund_balance.value,
249        }
250    }
251
252    events::WithdrewFees {
253        Vault<Otw> {
254            vault_balance_after => collateral_balance.value,
255        }
256    }
257
258    events::WithdrewInsuranceFund {
259        Vault<Otw> {
260            insurance_fund_balance_after => insurance_fund_balance.value,
261        }
262    }
263}
264
265impl Apply<ClearingHouse<Otw>> for events::WithdrewFees {
266    fn apply(&self, target: &mut ClearingHouse<Otw>) {
267        target.market_state.fees_accrued = IFixed::zero();
268    }
269}
270
271// When you reset fees you set at a constant value which is used as a "null" value. It's in the
272// constants module of the contracts.
273impl Apply<Position> for events::ResettedPositionFees {
274    fn apply(&self, target: &mut Position) {
275        target.maker_fee = 1.into();
276        target.taker_fee = 1.into();
277    }
278}
279
280impl Apply<Position> for events::LiquidatedPosition {
281    fn apply(&self, target: &mut Position) {
282        let Self {
283            liqee_collateral,
284            liqee_base_amount,
285            liqee_quote_amount,
286            ..
287        } = *self;
288        target.collateral = liqee_collateral;
289        target.base_asset_amount = liqee_base_amount;
290        target.quote_asset_notional_amount = liqee_quote_amount;
291        // All pending orders are force canceled upon liquidation
292        target.asks_quantity = IFixed::zero();
293        target.bids_quantity = IFixed::zero();
294        target.pending_orders = 0;
295    }
296}
297
298/// General interface to help apply orderbook-related events to a database.
299///
300/// The methods here don't have to be used as an interface for other applications, they're only
301/// defined for conveniently calling `event.apply(&mut database)` on whatever the `database` type
302/// is.
303pub trait Orderbook {
304    /// To use with `OrderbookPostReceipt` event.
305    fn insert_order(&mut self, order_id: u128, order: Order);
306
307    /// To use with `CanceledOrder` or `FilledMakerOrder`
308    /// in which maker order was fully filled.
309    fn remove_order(&mut self, order_id: u128);
310
311    /// To use with `FilledMakerOrder` in which
312    /// maker order was not fully filled.
313    fn reduce_order_size(&mut self, order_id: u128, size_to_sub: u64);
314}
315
316impl<T: Orderbook> Apply<T> for events::OrderbookPostReceipt {
317    fn apply(&self, target: &mut T) {
318        let Self {
319            order_id,
320            order_size: size,
321            account_id,
322            ..
323        } = *self;
324        let order = Order { account_id, size };
325        target.insert_order(order_id, order);
326    }
327}
328
329impl<T: Orderbook> Apply<T> for events::CanceledOrder {
330    fn apply(&self, target: &mut T) {
331        let Self { order_id, .. } = *self;
332        target.remove_order(order_id);
333    }
334}
335
336impl<T: Orderbook> Apply<T> for events::FilledMakerOrder {
337    fn apply(&self, target: &mut T) {
338        let Self {
339            order_id,
340            maker_size,
341            maker_final_size,
342            ..
343        } = *self;
344        if maker_final_size > 0 {
345            target.reduce_order_size(order_id, maker_size)
346        } else {
347            target.remove_order(order_id);
348        }
349    }
350}