1- use crate :: models:: {
2- order:: { FillDirection , UserFill } ,
3- transaction_id:: HyperCoreActionId ,
4- user:: { DelegatorHistoryDelta , DelegatorHistoryUpdate , LedgerDelta , LedgerUpdate } ,
5- } ;
61use number_formatter:: BigNumberFormatter ;
72use primitives:: {
83 PerpetualDirection , PerpetualProvider , TransactionChange , TransactionMetadata , TransactionPerpetualMetadata , TransactionState , TransactionType , TransactionUpdate ,
94 known_assets:: HYPERCORE_HYPE ,
105} ;
116
7+ use crate :: models:: {
8+ order:: { FillDirection , UserFill } ,
9+ transaction_id:: HyperCoreActionId ,
10+ user:: { DelegatorHistoryDelta , DelegatorHistoryUpdate , LedgerDelta , LedgerUpdate } ,
11+ } ;
12+ use crate :: perpetual_formatter:: usdc_value;
13+
1214pub const ACTION_HISTORY_QUERY_LOOKBACK_MS : u64 = 5_000 ;
1315const ACTION_HISTORY_MATCH_WINDOW_MS : u64 = 5 * 60 * 1_000 ;
1416const DELEGATOR_WITHDRAWAL_INITIATED : & str = "initiated" ;
@@ -53,8 +55,9 @@ pub fn map_transaction_state_order(fills: Vec<UserFill>, oid: u64, request_id: S
5355 match & last_fill. dir {
5456 FillDirection :: Buy | FillDirection :: Sell => { }
5557 FillDirection :: OpenLong | FillDirection :: OpenShort | FillDirection :: CloseLong | FillDirection :: CloseShort => {
56- let ( _, metadata) = prepare_perpetual_fill ( & matching_fills, last_fill) . unwrap ( ) ;
57- update. changes . push ( TransactionChange :: Metadata ( TransactionMetadata :: Perpetual ( metadata) ) ) ;
58+ if let Some ( changes) = perpetual_fill_changes ( & matching_fills, last_fill) {
59+ update. changes . extend ( changes) ;
60+ }
5861 }
5962 FillDirection :: Other ( _) => return TransactionUpdate :: new_state ( TransactionState :: Pending ) ,
6063 }
@@ -70,15 +73,29 @@ pub fn map_transaction_state_order(fills: Vec<UserFill>, oid: u64, request_id: S
7073}
7174
7275pub fn map_transaction_state_order_action ( fills : Vec < UserFill > , nonce : u64 , request_id : String ) -> TransactionUpdate {
73- transaction_update_from_hash ( order_action_hash ( & fills, nonce) , request_id)
76+ let Some ( fill) = order_action_fill ( & fills, nonce) else {
77+ return TransactionUpdate :: new_state ( TransactionState :: Pending ) ;
78+ } ;
79+
80+ let hash = fill. hash . clone ( ) ;
81+ let matching_fills: Vec < _ > = fills. iter ( ) . filter ( |item| item. oid == fill. oid ) . collect ( ) ;
82+ let mut update = TransactionUpdate :: new ( TransactionState :: Confirmed , vec ! [ TransactionChange :: HashChange { old: request_id, new: hash } ] ) ;
83+
84+ if let Some ( last_fill) = matching_fills. iter ( ) . max_by_key ( |fill| fill. time )
85+ && let Some ( changes) = perpetual_fill_changes ( & matching_fills, last_fill)
86+ {
87+ update. changes . extend ( changes) ;
88+ }
89+
90+ update
7491}
7592
76- pub fn order_action_hash ( fills : & [ UserFill ] , nonce : u64 ) -> Option < String > {
93+ pub ( crate ) fn order_action_fill ( fills : & [ UserFill ] , nonce : u64 ) -> Option < & UserFill > {
7794 fills
7895 . iter ( )
7996 . filter_map ( |fill| action_history_time_delta ( fill. time , nonce) . filter ( |_| !fill. hash . is_empty ( ) ) . map ( |delta| ( delta, fill) ) )
8097 . min_by_key ( |( delta, _) | * delta)
81- . map ( |( _, fill) | fill. hash . clone ( ) )
98+ . map ( |( _, fill) | fill)
8299}
83100
84101pub fn map_transaction_state_action ( updates : Vec < LedgerUpdate > , action_id : HyperCoreActionId , request_id : String ) -> TransactionUpdate {
@@ -162,10 +179,22 @@ fn transaction_update_from_hash(hash: Option<String>, request_id: String) -> Tra
162179 }
163180}
164181
182+ fn perpetual_fill_changes ( matching_fills : & [ & UserFill ] , last_fill : & UserFill ) -> Option < Vec < TransactionChange > > {
183+ let ( _, metadata) = prepare_perpetual_fill ( matching_fills, last_fill) ?;
184+ let fee: f64 = matching_fills. iter ( ) . map ( |fill| fill. fee + fill. builder_fee . unwrap_or ( 0.0 ) ) . sum ( ) ;
185+ let network_fee = usdc_value ( fee) . parse ( ) . ok ( ) ?;
186+
187+ Some ( vec ! [
188+ TransactionChange :: Metadata ( TransactionMetadata :: Perpetual ( metadata) ) ,
189+ TransactionChange :: NetworkFee ( network_fee) ,
190+ ] )
191+ }
192+
165193#[ cfg( test) ]
166194mod tests {
167195 use super :: * ;
168196 use crate :: models:: order:: { FillDirection , UserFill } ;
197+ use num_bigint:: BigInt ;
169198
170199 #[ test]
171200 fn test_map_transaction_state_order ( ) {
@@ -176,7 +205,7 @@ mod tests {
176205 let update = map_transaction_state_order ( fills, oid, request_id. clone ( ) ) ;
177206
178207 assert_eq ! ( update. state, TransactionState :: Confirmed ) ;
179- assert_eq ! ( update. changes. len( ) , 2 ) ;
208+ assert_eq ! ( update. changes. len( ) , 3 ) ;
180209
181210 let metadata_change = update. changes . iter ( ) . find_map ( |change| {
182211 if let TransactionChange :: Metadata ( TransactionMetadata :: Perpetual ( metadata) ) = change {
@@ -192,6 +221,12 @@ mod tests {
192221 assert_eq ! ( metadata. is_liquidation, Some ( false ) ) ;
193222 assert_eq ! ( metadata. provider, Some ( PerpetualProvider :: Hypercore ) ) ;
194223
224+ let network_fee_change = update
225+ . changes
226+ . iter ( )
227+ . find_map ( |change| if let TransactionChange :: NetworkFee ( fee) = change { Some ( fee) } else { None } ) ;
228+ assert_eq ! ( network_fee_change, Some ( & BigInt :: from( 666786 ) ) ) ;
229+
195230 let hash_change = update. changes . iter ( ) . find_map ( |change| {
196231 if let TransactionChange :: HashChange { old, new } = change {
197232 Some ( ( old, new) )
@@ -254,6 +289,27 @@ mod tests {
254289 ) ;
255290 }
256291
292+ #[ test]
293+ fn test_map_transaction_state_order_action_includes_perpetual_fee ( ) {
294+ let fills: Vec < UserFill > = serde_json:: from_str ( include_str ! ( "../../testdata/user_fills_multiple.json" ) ) . unwrap ( ) ;
295+ let request_id = "action:order:1759700579000" . to_string ( ) ;
296+ let update = map_transaction_state_order_action ( fills, 1759700579000 , request_id. clone ( ) ) ;
297+
298+ assert_eq ! ( update. state, TransactionState :: Confirmed ) ;
299+ assert_eq ! (
300+ update. changes[ 0 ] ,
301+ TransactionChange :: HashChange {
302+ old: request_id,
303+ new: "0x9b4d63110c57f2e19cc7042ce90e300202f500f6a75b11b33f160e63cb5bcccc" . to_string( ) ,
304+ }
305+ ) ;
306+ let network_fee_change = update
307+ . changes
308+ . iter ( )
309+ . find_map ( |change| if let TransactionChange :: NetworkFee ( fee) = change { Some ( fee) } else { None } ) ;
310+ assert_eq ! ( network_fee_change, Some ( & BigInt :: from( 666786 ) ) ) ;
311+ }
312+
257313 #[ test]
258314 fn test_map_transaction_state_order_action_confirms_closest_fill ( ) {
259315 let fills: Vec < UserFill > = serde_json:: from_str ( include_str ! ( "../../testdata/user_fills_spot_swap.json" ) ) . unwrap ( ) ;
0 commit comments