1use std::collections::HashMap;
17
18use derive_builder::Builder;
19use nautilus_model::{
20 data::{
21 Bar, FundingRateUpdate, IndexPriceUpdate, MarkPriceUpdate, OrderBookDeltas, QuoteTick,
22 TradeTick,
23 },
24 reports::{FillReport, OrderStatusReport},
25};
26use serde::{Deserialize, Serialize};
27use ustr::Ustr;
28
29use crate::common::enums::{
30 HyperliquidBarInterval, HyperliquidFillDirection, HyperliquidLiquidationMethod,
31 HyperliquidOrderStatus as HyperliquidOrderStatusEnum, HyperliquidSide, HyperliquidTpSl,
32 HyperliquidTwapStatus,
33};
34
35#[derive(Debug, Clone, Serialize)]
37#[serde(tag = "method")]
38#[serde(rename_all = "lowercase")]
39pub enum HyperliquidWsRequest {
40 Subscribe {
42 subscription: SubscriptionRequest,
44 },
45 Unsubscribe {
47 subscription: SubscriptionRequest,
49 },
50 Post {
52 id: u64,
54 request: PostRequest,
56 },
57 Ping,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
63#[serde(tag = "type")]
64#[serde(rename_all = "camelCase")]
65pub enum SubscriptionRequest {
66 AllMids {
68 #[serde(skip_serializing_if = "Option::is_none")]
69 dex: Option<String>,
70 },
71 Notification { user: String },
73 WebData2 { user: String },
75 Candle {
77 coin: Ustr,
78 interval: HyperliquidBarInterval,
79 },
80 L2Book {
82 coin: Ustr,
83 #[serde(skip_serializing_if = "Option::is_none")]
84 #[serde(rename = "nSigFigs")]
85 n_sig_figs: Option<u32>,
86 #[serde(skip_serializing_if = "Option::is_none")]
87 mantissa: Option<u32>,
88 },
89 Trades { coin: Ustr },
91 OrderUpdates { user: String },
93 UserEvents { user: String },
95 UserFills {
97 user: String,
98 #[serde(skip_serializing_if = "Option::is_none")]
99 #[serde(rename = "aggregateByTime")]
100 aggregate_by_time: Option<bool>,
101 },
102 UserFundings { user: String },
104 UserNonFundingLedgerUpdates { user: String },
106 ActiveAssetCtx { coin: Ustr },
108 ActiveSpotAssetCtx { coin: Ustr },
110 ActiveAssetData { user: String, coin: String },
112 UserTwapSliceFills { user: String },
114 UserTwapHistory { user: String },
116 Bbo { coin: Ustr },
118}
119
120#[derive(Debug, Clone, Serialize)]
122#[serde(tag = "type")]
123#[serde(rename_all = "lowercase")]
124pub enum PostRequest {
125 Info { payload: serde_json::Value },
127 Action { payload: ActionPayload },
129}
130
131#[derive(Debug, Clone, Serialize)]
133pub struct ActionPayload {
134 pub action: ActionRequest,
135 pub nonce: u64,
136 pub signature: SignatureData,
137 #[serde(skip_serializing_if = "Option::is_none")]
138 #[serde(rename = "vaultAddress")]
139 pub vault_address: Option<String>,
140}
141
142#[derive(Debug, Clone, Serialize)]
144pub struct SignatureData {
145 pub r: String,
146 pub s: String,
147 pub v: String,
148}
149
150#[derive(Debug, Clone, Serialize)]
152#[serde(tag = "type")]
153#[serde(rename_all = "lowercase")]
154pub enum ActionRequest {
155 Order {
157 orders: Vec<OrderRequest>,
158 grouping: String,
159 },
160 Cancel { cancels: Vec<CancelRequest> },
162 CancelByCloid { cancels: Vec<CancelByCloidRequest> },
164 Modify { modifies: Vec<ModifyRequest> },
166}
167
168impl ActionRequest {
169 pub fn order(orders: Vec<OrderRequest>, grouping: impl Into<String>) -> Self {
176 Self::Order {
177 orders,
178 grouping: grouping.into(),
179 }
180 }
181
182 pub fn cancel(cancels: Vec<CancelRequest>) -> Self {
192 Self::Cancel { cancels }
193 }
194
195 pub fn cancel_by_cloid(cancels: Vec<CancelByCloidRequest>) -> Self {
204 Self::CancelByCloid { cancels }
205 }
206
207 pub fn modify(modifies: Vec<ModifyRequest>) -> Self {
216 Self::Modify { modifies }
217 }
218}
219
220#[derive(Debug, Clone, Serialize, Builder)]
222pub struct OrderRequest {
223 pub a: u32,
225 pub b: bool,
227 pub p: String,
229 pub s: String,
231 pub r: bool,
233 pub t: OrderTypeRequest,
235 #[serde(skip_serializing_if = "Option::is_none")]
237 pub c: Option<String>,
238}
239
240#[derive(Debug, Clone, Serialize)]
242#[serde(tag = "type")]
243#[serde(rename_all = "lowercase")]
244pub enum OrderTypeRequest {
245 Limit {
246 tif: TimeInForceRequest,
247 },
248 Trigger {
249 #[serde(rename = "isMarket")]
250 is_market: bool,
251 #[serde(rename = "triggerPx")]
252 trigger_px: String,
253 tpsl: TpSlRequest,
254 },
255}
256
257#[derive(Debug, Clone, Serialize)]
259#[serde(rename_all = "PascalCase")]
260pub enum TimeInForceRequest {
261 Alo,
262 Ioc,
263 Gtc,
264}
265
266#[derive(Debug, Clone, Serialize)]
268#[serde(rename_all = "lowercase")]
269pub enum TpSlRequest {
270 Tp,
271 Sl,
272}
273
274#[derive(Debug, Clone, Serialize)]
276pub struct CancelRequest {
277 pub a: u32,
279 pub o: u64,
281}
282
283#[derive(Debug, Clone, Serialize)]
285pub struct CancelByCloidRequest {
286 pub asset: u32,
288 pub cloid: String,
290}
291
292#[derive(Debug, Clone, Serialize)]
294pub struct ModifyRequest {
295 pub oid: u64,
297 pub order: OrderRequest,
299}
300
301#[derive(Debug, Clone, Deserialize)]
303pub struct SubscriptionResponseData {
304 pub method: String,
305 pub subscription: SubscriptionRequest,
306}
307
308#[derive(Debug, Clone, Deserialize)]
310#[serde(tag = "channel")]
311#[serde(rename_all = "camelCase")]
312pub enum HyperliquidWsMessage {
313 SubscriptionResponse { data: SubscriptionResponseData },
315 Post { data: PostResponse },
317 AllMids { data: AllMidsData },
319 Notification { data: NotificationData },
321 WebData2 { data: serde_json::Value },
323 Candle { data: CandleData },
325 L2Book { data: WsBookData },
327 Trades { data: Vec<WsTradeData> },
329 OrderUpdates { data: Vec<WsOrderData> },
331 UserEvents { data: WsUserEventData },
333 UserFills { data: WsUserFillsData },
335 UserFundings { data: WsUserFundingsData },
337 UserNonFundingLedgerUpdates { data: serde_json::Value },
339 ActiveAssetCtx { data: WsActiveAssetCtxData },
341 ActiveSpotAssetCtx { data: WsActiveAssetCtxData },
343 ActiveAssetData { data: WsActiveAssetData },
345 UserTwapSliceFills { data: WsUserTwapSliceFillsData },
347 UserTwapHistory { data: WsUserTwapHistoryData },
349 Bbo { data: WsBboData },
351 Error { data: String },
353 Pong,
355}
356
357#[derive(Debug, Clone, Deserialize)]
359pub struct PostResponse {
360 pub id: u64,
361 pub response: PostResponsePayload,
362}
363
364#[derive(Debug, Clone, Deserialize)]
366#[serde(tag = "type")]
367#[serde(rename_all = "lowercase")]
368pub enum PostResponsePayload {
369 Info { payload: serde_json::Value },
370 Action { payload: serde_json::Value },
371 Error { payload: String },
372}
373
374#[derive(Debug, Clone, Deserialize)]
376pub struct AllMidsData {
377 pub mids: HashMap<String, String>,
378}
379
380#[derive(Debug, Clone, Deserialize)]
382pub struct NotificationData {
383 pub notification: String,
384}
385
386#[derive(Debug, Clone, Deserialize)]
388pub struct CandleData {
389 pub t: u64,
391 #[serde(rename = "T")]
393 pub close_time: u64,
394 pub s: Ustr,
396 pub i: String,
398 pub o: String,
400 pub c: String,
402 pub h: String,
404 pub l: String,
406 pub v: String,
408 pub n: u32,
410}
411
412#[derive(Debug, Clone, Serialize, Deserialize)]
414pub struct WsBookData {
415 pub coin: Ustr,
416 pub levels: [Vec<WsLevelData>; 2], pub time: u64,
418}
419
420#[derive(Debug, Clone, Serialize, Deserialize)]
422pub struct WsLevelData {
423 pub px: String,
425 pub sz: String,
427 pub n: u32,
429}
430
431#[derive(Debug, Clone, Serialize, Deserialize)]
433pub struct WsTradeData {
434 pub coin: Ustr,
435 pub side: HyperliquidSide,
436 pub px: String,
437 pub sz: String,
438 pub hash: String,
439 pub time: u64,
440 pub tid: u64,
441 pub users: [String; 2], }
443
444#[derive(Debug, Clone, Deserialize)]
446pub struct WsOrderData {
447 pub order: WsBasicOrderData,
448 pub status: HyperliquidOrderStatusEnum,
449 #[serde(rename = "statusTimestamp")]
450 pub status_timestamp: u64,
451}
452
453#[derive(Debug, Clone, Deserialize)]
455pub struct WsBasicOrderData {
456 pub coin: Ustr,
457 pub side: HyperliquidSide,
458 #[serde(rename = "limitPx")]
459 pub limit_px: String,
460 pub sz: String,
461 pub oid: u64,
462 pub timestamp: u64,
463 #[serde(rename = "origSz")]
464 pub orig_sz: String,
465 pub cloid: Option<String>,
466 #[serde(rename = "triggerPx")]
468 pub trigger_px: Option<String>,
469 #[serde(rename = "isMarket")]
471 pub is_market: Option<bool>,
472 pub tpsl: Option<HyperliquidTpSl>,
474 #[serde(rename = "triggerActivated")]
476 pub trigger_activated: Option<bool>,
477 #[serde(rename = "trailingStop")]
479 pub trailing_stop: Option<WsTrailingStopData>,
480}
481
482#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
484#[serde(rename_all = "camelCase")]
485pub enum TrailingOffsetType {
486 Price,
488 Percentage,
490 BasisPoints,
492}
493
494impl TrailingOffsetType {
495 pub fn format_offset(&self, offset: &str) -> String {
497 match self {
498 Self::Price => offset.to_string(),
499 Self::Percentage => format!("{offset}%"),
500 Self::BasisPoints => format!("{offset} bps"),
501 }
502 }
503}
504
505#[derive(Debug, Clone, Deserialize)]
507pub struct WsTrailingStopData {
508 pub offset: String,
510 #[serde(rename = "offsetType")]
512 pub offset_type: TrailingOffsetType,
513 #[serde(rename = "callbackPrice")]
515 pub callback_price: Option<String>,
516}
517
518#[derive(Debug, Clone, Deserialize)]
520#[serde(untagged)]
521pub enum WsUserEventData {
522 Fills {
523 fills: Vec<WsFillData>,
524 },
525 Funding {
526 funding: WsUserFundingData,
527 },
528 Liquidation {
529 liquidation: WsLiquidationData,
530 },
531 NonUserCancel {
532 #[serde(rename = "nonUserCancel")]
533 non_user_cancel: Vec<WsNonUserCancelData>,
534 },
535 TriggerActivated {
537 #[serde(rename = "triggerActivated")]
538 trigger_activated: WsTriggerActivatedData,
539 },
540 TriggerTriggered {
542 #[serde(rename = "triggerTriggered")]
543 trigger_triggered: WsTriggerTriggeredData,
544 },
545}
546
547#[derive(Debug, Clone, Deserialize)]
549pub struct WsFillData {
550 pub coin: Ustr,
551 pub px: String,
552 pub sz: String,
553 pub side: HyperliquidSide,
554 pub time: u64,
555 #[serde(rename = "startPosition")]
556 pub start_position: String,
557 pub dir: HyperliquidFillDirection,
558 #[serde(rename = "closedPnl")]
559 pub closed_pnl: String,
560 pub hash: String,
561 pub oid: u64,
562 pub crossed: bool,
563 pub fee: String,
564 pub tid: u64,
565 pub liquidation: Option<FillLiquidationData>,
566 #[serde(rename = "feeToken")]
567 pub fee_token: String,
568 #[serde(rename = "builderFee")]
569 pub builder_fee: Option<String>,
570}
571
572#[derive(Debug, Clone, Deserialize)]
574pub struct FillLiquidationData {
575 #[serde(rename = "liquidatedUser")]
576 pub liquidated_user: Option<String>,
577 #[serde(rename = "markPx")]
578 pub mark_px: f64,
579 pub method: HyperliquidLiquidationMethod,
580}
581
582#[derive(Debug, Clone, Deserialize)]
584pub struct WsUserFundingData {
585 pub time: u64,
586 pub coin: Ustr,
587 pub usdc: String,
588 pub szi: String,
589 #[serde(rename = "fundingRate")]
590 pub funding_rate: String,
591}
592
593#[derive(Debug, Clone, Deserialize)]
595pub struct WsLiquidationData {
596 pub lid: u64,
597 pub liquidator: String,
598 pub liquidated_user: String,
599 pub liquidated_ntl_pos: String,
600 pub liquidated_account_value: String,
601}
602
603#[derive(Debug, Clone, Deserialize)]
605pub struct WsNonUserCancelData {
606 pub coin: Ustr,
607 pub oid: u64,
608}
609
610#[derive(Debug, Clone, Deserialize)]
612pub struct WsTriggerActivatedData {
613 pub coin: Ustr,
614 pub oid: u64,
615 pub time: u64,
616 #[serde(rename = "triggerPx")]
617 pub trigger_px: String,
618 pub tpsl: HyperliquidTpSl,
619}
620
621#[derive(Debug, Clone, Deserialize)]
623pub struct WsTriggerTriggeredData {
624 pub coin: Ustr,
625 pub oid: u64,
626 pub time: u64,
627 #[serde(rename = "triggerPx")]
628 pub trigger_px: String,
629 #[serde(rename = "marketPx")]
630 pub market_px: String,
631 pub tpsl: HyperliquidTpSl,
632 #[serde(rename = "resultingOid")]
634 pub resulting_oid: Option<u64>,
635}
636
637#[derive(Debug, Clone, Deserialize)]
639pub struct WsUserFillsData {
640 #[serde(rename = "isSnapshot")]
641 pub is_snapshot: Option<bool>,
642 pub user: String,
643 pub fills: Vec<WsFillData>,
644}
645
646#[derive(Debug, Clone, Deserialize)]
648pub struct WsUserFundingsData {
649 #[serde(rename = "isSnapshot")]
650 pub is_snapshot: Option<bool>,
651 pub user: String,
652 pub fundings: Vec<WsUserFundingData>,
653}
654
655#[derive(Debug, Clone, Deserialize)]
657#[serde(untagged)]
658pub enum WsActiveAssetCtxData {
659 Perp { coin: Ustr, ctx: PerpsAssetCtx },
660 Spot { coin: Ustr, ctx: SpotAssetCtx },
661}
662
663#[derive(Debug, Clone, Deserialize)]
665pub struct SharedAssetCtx {
666 #[serde(rename = "dayNtlVlm")]
667 pub day_ntl_vlm: String,
668 #[serde(rename = "prevDayPx")]
669 pub prev_day_px: String,
670 #[serde(rename = "markPx")]
671 pub mark_px: String,
672 #[serde(rename = "midPx")]
673 pub mid_px: Option<String>,
674 #[serde(rename = "impactPxs")]
675 pub impact_pxs: Option<Vec<String>>,
676 #[serde(rename = "dayBaseVlm")]
677 pub day_base_vlm: Option<String>,
678}
679
680#[derive(Debug, Clone, Deserialize)]
682pub struct PerpsAssetCtx {
683 #[serde(flatten)]
684 pub shared: SharedAssetCtx,
685 pub funding: String,
686 #[serde(rename = "openInterest")]
687 pub open_interest: String,
688 #[serde(rename = "oraclePx")]
689 pub oracle_px: String,
690 pub premium: Option<String>,
691}
692
693#[derive(Debug, Clone, Deserialize)]
695pub struct SpotAssetCtx {
696 #[serde(flatten)]
697 pub shared: SharedAssetCtx,
698 #[serde(rename = "circulatingSupply")]
699 pub circulating_supply: String,
700}
701
702#[derive(Debug, Clone, Deserialize)]
704pub struct WsActiveAssetData {
705 pub user: String,
706 pub coin: Ustr,
707 pub leverage: LeverageData,
708 #[serde(rename = "maxTradeSzs")]
709 pub max_trade_szs: [f64; 2],
710 #[serde(rename = "availableToTrade")]
711 pub available_to_trade: [f64; 2],
712}
713
714#[derive(Debug, Clone, Deserialize)]
716pub struct LeverageData {
717 pub value: f64,
718 pub type_: String,
719}
720
721#[derive(Debug, Clone, Deserialize)]
723pub struct WsUserTwapSliceFillsData {
724 #[serde(rename = "isSnapshot")]
725 pub is_snapshot: Option<bool>,
726 pub user: String,
727 #[serde(rename = "twapSliceFills")]
728 pub twap_slice_fills: Vec<WsTwapSliceFillData>,
729}
730
731#[derive(Debug, Clone, Deserialize)]
733pub struct WsTwapSliceFillData {
734 pub fill: WsFillData,
735 #[serde(rename = "twapId")]
736 pub twap_id: u64,
737}
738
739#[derive(Debug, Clone, Deserialize)]
741pub struct WsUserTwapHistoryData {
742 #[serde(rename = "isSnapshot")]
743 pub is_snapshot: Option<bool>,
744 pub user: String,
745 pub history: Vec<WsTwapHistoryData>,
746}
747
748#[derive(Debug, Clone, Deserialize)]
750pub struct WsTwapHistoryData {
751 pub state: TwapStateData,
752 pub status: TwapStatusData,
753 pub time: u64,
754}
755
756#[derive(Debug, Clone, Deserialize)]
758pub struct TwapStateData {
759 pub coin: Ustr,
760 pub user: String,
761 pub side: HyperliquidSide,
762 pub sz: f64,
763 #[serde(rename = "executedSz")]
764 pub executed_sz: f64,
765 #[serde(rename = "executedNtl")]
766 pub executed_ntl: f64,
767 pub minutes: u32,
768 #[serde(rename = "reduceOnly")]
769 pub reduce_only: bool,
770 pub randomize: bool,
771 pub timestamp: u64,
772}
773
774#[derive(Debug, Clone, Deserialize)]
776pub struct TwapStatusData {
777 pub status: HyperliquidTwapStatus,
778 pub description: String,
779}
780
781#[derive(Debug, Clone, Deserialize)]
783pub struct WsBboData {
784 pub coin: Ustr,
785 pub time: u64,
786 pub bbo: [Option<WsLevelData>; 2], }
788
789#[cfg(test)]
794mod tests {
795 use rstest::rstest;
796 use serde_json;
797
798 use super::*;
799
800 #[rstest]
801 fn test_subscription_request_serialization() {
802 let sub = SubscriptionRequest::L2Book {
803 coin: Ustr::from("BTC"),
804 n_sig_figs: Some(5),
805 mantissa: None,
806 };
807
808 let json = serde_json::to_string(&sub).unwrap();
809 assert!(json.contains(r#""type":"l2Book""#));
810 assert!(json.contains(r#""coin":"BTC""#));
811 }
812
813 #[rstest]
814 fn test_hyperliquid_ws_request_serialization() {
815 let req = HyperliquidWsRequest::Subscribe {
816 subscription: SubscriptionRequest::Trades {
817 coin: Ustr::from("ETH"),
818 },
819 };
820
821 let json = serde_json::to_string(&req).unwrap();
822 assert!(json.contains(r#""method":"subscribe""#));
823 assert!(json.contains(r#""type":"trades""#));
824 }
825
826 #[rstest]
827 fn test_order_request_serialization() {
828 let order = OrderRequest {
829 a: 0, b: true, p: "50000.0".to_string(),
832 s: "0.1".to_string(),
833 r: false,
834 t: OrderTypeRequest::Limit {
835 tif: TimeInForceRequest::Gtc,
836 },
837 c: Some("client-123".to_string()),
838 };
839
840 let json = serde_json::to_string(&order).unwrap();
841 assert!(json.contains(r#""a":0"#));
842 assert!(json.contains(r#""b":true"#));
843 assert!(json.contains(r#""p":"50000.0""#));
844 }
845
846 #[rstest]
847 fn test_ws_trade_data_deserialization() {
848 let json = r#"{
849 "coin": "BTC",
850 "side": "B",
851 "px": "50000.0",
852 "sz": "0.1",
853 "hash": "0x123",
854 "time": 1234567890,
855 "tid": 12345,
856 "users": ["0xabc", "0xdef"]
857 }"#;
858
859 let trade: WsTradeData = serde_json::from_str(json).unwrap();
860 assert_eq!(trade.coin, "BTC");
861 assert_eq!(trade.side, HyperliquidSide::Buy);
862 assert_eq!(trade.px, "50000.0");
863 }
864
865 #[rstest]
866 fn test_ws_book_data_deserialization() {
867 let json = r#"{
868 "coin": "ETH",
869 "levels": [
870 [{"px": "3000.0", "sz": "1.0", "n": 1}],
871 [{"px": "3001.0", "sz": "2.0", "n": 2}]
872 ],
873 "time": 1234567890
874 }"#;
875
876 let book: WsBookData = serde_json::from_str(json).unwrap();
877 assert_eq!(book.coin, "ETH");
878 assert_eq!(book.levels[0].len(), 1);
879 assert_eq!(book.levels[1].len(), 1);
880 }
881
882 #[rstest]
887 fn test_ws_trailing_stop_data_deserialization() {
888 let json = r#"{
889 "offset": "100.0",
890 "offsetType": "price",
891 "callbackPrice": "50000.0"
892 }"#;
893
894 let data: WsTrailingStopData = serde_json::from_str(json).unwrap();
895 assert_eq!(data.offset, "100.0");
896 assert_eq!(data.offset_type, TrailingOffsetType::Price);
897 assert_eq!(data.callback_price.unwrap(), "50000.0");
898 }
899
900 #[rstest]
901 fn test_ws_trigger_activated_data_deserialization() {
902 let json = r#"{
903 "coin": "BTC",
904 "oid": 12345,
905 "time": 1704470400000,
906 "triggerPx": "50000.0",
907 "tpsl": "sl"
908 }"#;
909
910 let data: WsTriggerActivatedData = serde_json::from_str(json).unwrap();
911 assert_eq!(data.coin, Ustr::from("BTC"));
912 assert_eq!(data.oid, 12345);
913 assert_eq!(data.trigger_px, "50000.0");
914 assert_eq!(data.tpsl, HyperliquidTpSl::Sl);
915 assert_eq!(data.time, 1704470400000);
916 }
917
918 #[rstest]
919 fn test_ws_trigger_triggered_data_deserialization() {
920 let json = r#"{
921 "coin": "ETH",
922 "oid": 67890,
923 "time": 1704470500000,
924 "triggerPx": "3000.0",
925 "marketPx": "3001.0",
926 "tpsl": "tp",
927 "resultingOid": 99999
928 }"#;
929
930 let data: WsTriggerTriggeredData = serde_json::from_str(json).unwrap();
931 assert_eq!(data.coin, Ustr::from("ETH"));
932 assert_eq!(data.oid, 67890);
933 assert_eq!(data.trigger_px, "3000.0");
934 assert_eq!(data.market_px, "3001.0");
935 assert_eq!(data.tpsl, HyperliquidTpSl::Tp);
936 assert_eq!(data.resulting_oid, Some(99999));
937 }
938}
939
940#[derive(Debug, Clone)]
947pub enum NautilusWsMessage {
948 ExecutionReports(Vec<ExecutionReport>),
950 Trades(Vec<TradeTick>),
952 Quote(QuoteTick),
954 Deltas(OrderBookDeltas),
956 Candle(Bar),
958 MarkPrice(MarkPriceUpdate),
960 IndexPrice(IndexPriceUpdate),
962 FundingRate(FundingRateUpdate),
964 Error(String),
966 Reconnected,
968}
969
970#[derive(Debug, Clone)]
975#[allow(clippy::large_enum_variant)]
976pub enum ExecutionReport {
977 Order(OrderStatusReport),
979 Fill(FillReport),
981}