1use std::fmt;
2use std::str::FromStr;
3
4use super::{
5 HC_ACTION_ID_TRANSFER_OPTION, HC_ACTION_ID_UPDATE_API_WALLET, HC_ACTION_VERSION,
6 HL_ACTION_ID_CANCEL_BY_CLOID, HL_ACTION_ID_CANCEL_BY_OID, HL_ACTION_ID_LIMIT_ORDER,
7 HL_ACTION_ID_SEND_ASSET, HL_ACTION_VERSION, SYSTEM_ACTION_ID_CREDIT_OPTION,
8 SYSTEM_ACTION_ID_CREDIT_TOKEN, SYSTEM_ACTION_ID_START_LIQUIDATION,
9 SYSTEM_ACTION_ID_STOP_LIQUIDATION, SYSTEM_ACTION_ID_WITHDRAW_TOKEN, SYSTEM_ACTION_VERSION,
10};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum SignerType {
14 ApiWallet,
15 Manager,
16 Rsm,
17}
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum DomainKind {
21 Api,
22 Manager,
23 Rsm,
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
27#[non_exhaustive]
28pub enum ActionKey {
29 HlLimitOrder,
30 HlCancelByOid,
31 HlCancelByCloid,
32 HcUpdateApiWallet,
33 HlSendAsset,
34 HcTransferOption,
35 RsmHlLimitOrder,
36 RsmHlCancelByOid,
37 RsmHlCancelByCloid,
38 RsmHlSendAsset,
39 SystemCreditToken,
40 SystemCreditOption,
41 SystemStartLiquidation,
42 SystemStopLiquidation,
43 SystemWithdrawToken,
44}
45
46#[derive(Debug, Clone, Copy)]
47pub struct ActionSpec {
48 pub action_key: &'static str,
49 pub version: u8,
50 pub id: u32,
51 pub primary_type: &'static str,
52 pub signer_type: SignerType,
53 pub domain: DomainKind,
54 pub supported: bool,
55 pub typed_data: Option<TypedDataSpec>,
56}
57
58#[derive(Debug, Clone, Copy)]
59pub struct TypeFieldSpec {
60 pub name: &'static str,
61 pub kind: &'static str,
62}
63
64#[derive(Debug, Clone, Copy)]
65pub struct TypedDataSpec {
66 pub inner_type: &'static str,
67 pub inner_fields: &'static [TypeFieldSpec],
68}
69
70#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct ParseActionKeyError {
72 value: String,
73}
74
75impl ParseActionKeyError {
76 pub fn new(value: impl Into<String>) -> Self {
77 Self {
78 value: value.into(),
79 }
80 }
81
82 pub fn value(&self) -> &str {
83 &self.value
84 }
85}
86
87impl fmt::Display for ParseActionKeyError {
88 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89 write!(f, "Unsupported action key: {}", self.value)
90 }
91}
92
93impl std::error::Error for ParseActionKeyError {}
94
95const HL_LIMIT_ORDER_FIELDS: &[TypeFieldSpec] = &[
96 TypeFieldSpec {
97 name: "asset",
98 kind: "uint32",
99 },
100 TypeFieldSpec {
101 name: "isBuy",
102 kind: "bool",
103 },
104 TypeFieldSpec {
105 name: "limitPx",
106 kind: "uint64",
107 },
108 TypeFieldSpec {
109 name: "sz",
110 kind: "uint64",
111 },
112 TypeFieldSpec {
113 name: "reduceOnly",
114 kind: "bool",
115 },
116 TypeFieldSpec {
117 name: "encodedTif",
118 kind: "uint8",
119 },
120 TypeFieldSpec {
121 name: "cloid",
122 kind: "uint128",
123 },
124];
125
126const HL_CANCEL_BY_OID_FIELDS: &[TypeFieldSpec] = &[
127 TypeFieldSpec {
128 name: "asset",
129 kind: "uint32",
130 },
131 TypeFieldSpec {
132 name: "oid",
133 kind: "uint64",
134 },
135];
136
137const HL_CANCEL_BY_CLOID_FIELDS: &[TypeFieldSpec] = &[
138 TypeFieldSpec {
139 name: "asset",
140 kind: "uint32",
141 },
142 TypeFieldSpec {
143 name: "cloid",
144 kind: "uint128",
145 },
146];
147
148const HL_SEND_ASSET_FIELDS: &[TypeFieldSpec] = &[
149 TypeFieldSpec {
150 name: "destination",
151 kind: "address",
152 },
153 TypeFieldSpec {
154 name: "subAccount",
155 kind: "address",
156 },
157 TypeFieldSpec {
158 name: "srcDex",
159 kind: "uint32",
160 },
161 TypeFieldSpec {
162 name: "dstDex",
163 kind: "uint32",
164 },
165 TypeFieldSpec {
166 name: "token",
167 kind: "uint64",
168 },
169 TypeFieldSpec {
170 name: "amountWei",
171 kind: "uint64",
172 },
173];
174
175const HC_UPDATE_API_WALLET_FIELDS: &[TypeFieldSpec] = &[
176 TypeFieldSpec {
177 name: "name",
178 kind: "bytes32",
179 },
180 TypeFieldSpec {
181 name: "addr",
182 kind: "address",
183 },
184];
185
186const SYSTEM_CREDIT_TOKEN_FIELDS: &[TypeFieldSpec] = &[
187 TypeFieldSpec {
188 name: "srcDex",
189 kind: "uint32",
190 },
191 TypeFieldSpec {
192 name: "dstDex",
193 kind: "uint32",
194 },
195 TypeFieldSpec {
196 name: "token",
197 kind: "uint64",
198 },
199 TypeFieldSpec {
200 name: "amountWei",
201 kind: "uint64",
202 },
203];
204
205const SYSTEM_CREDIT_OPTION_FIELDS: &[TypeFieldSpec] = &[
206 TypeFieldSpec {
207 name: "underlying",
208 kind: "bytes32",
209 },
210 TypeFieldSpec {
211 name: "expiry",
212 kind: "uint256",
213 },
214 TypeFieldSpec {
215 name: "strike",
216 kind: "uint256",
217 },
218 TypeFieldSpec {
219 name: "isCall",
220 kind: "bool",
221 },
222 TypeFieldSpec {
223 name: "amountWei",
224 kind: "uint256",
225 },
226];
227
228const SYSTEM_START_LIQUIDATION_FIELDS: &[TypeFieldSpec] = &[
229 TypeFieldSpec {
230 name: "equity",
231 kind: "int256",
232 },
233 TypeFieldSpec {
234 name: "marginNeeded",
235 kind: "uint256",
236 },
237];
238
239const SYSTEM_STOP_LIQUIDATION_FIELDS: &[TypeFieldSpec] = &[TypeFieldSpec {
240 name: "startTime",
241 kind: "uint256",
242}];
243
244const SYSTEM_WITHDRAW_TOKEN_FIELDS: &[TypeFieldSpec] = &[
245 TypeFieldSpec {
246 name: "destination",
247 kind: "address",
248 },
249 TypeFieldSpec {
250 name: "subAccount",
251 kind: "address",
252 },
253 TypeFieldSpec {
254 name: "srcDex",
255 kind: "uint32",
256 },
257 TypeFieldSpec {
258 name: "dstDex",
259 kind: "uint32",
260 },
261 TypeFieldSpec {
262 name: "token",
263 kind: "uint64",
264 },
265 TypeFieldSpec {
266 name: "amountWei",
267 kind: "uint64",
268 },
269];
270
271const HL_LIMIT_ORDER_TYPED_DATA: TypedDataSpec = TypedDataSpec {
272 inner_type: "LimitOrder",
273 inner_fields: HL_LIMIT_ORDER_FIELDS,
274};
275
276const HL_CANCEL_BY_OID_TYPED_DATA: TypedDataSpec = TypedDataSpec {
277 inner_type: "CancelOrderByOid",
278 inner_fields: HL_CANCEL_BY_OID_FIELDS,
279};
280
281const HL_CANCEL_BY_CLOID_TYPED_DATA: TypedDataSpec = TypedDataSpec {
282 inner_type: "CancelOrderByCloid",
283 inner_fields: HL_CANCEL_BY_CLOID_FIELDS,
284};
285
286const HL_SEND_ASSET_TYPED_DATA: TypedDataSpec = TypedDataSpec {
287 inner_type: "SendAsset",
288 inner_fields: HL_SEND_ASSET_FIELDS,
289};
290
291const HC_UPDATE_API_WALLET_TYPED_DATA: TypedDataSpec = TypedDataSpec {
292 inner_type: "UpdateApiWallet",
293 inner_fields: HC_UPDATE_API_WALLET_FIELDS,
294};
295
296const SYSTEM_CREDIT_TOKEN_TYPED_DATA: TypedDataSpec = TypedDataSpec {
297 inner_type: "CreditToken",
298 inner_fields: SYSTEM_CREDIT_TOKEN_FIELDS,
299};
300
301const SYSTEM_CREDIT_OPTION_TYPED_DATA: TypedDataSpec = TypedDataSpec {
302 inner_type: "CreditOption",
303 inner_fields: SYSTEM_CREDIT_OPTION_FIELDS,
304};
305
306const SYSTEM_START_LIQUIDATION_TYPED_DATA: TypedDataSpec = TypedDataSpec {
307 inner_type: "StartLiquidation",
308 inner_fields: SYSTEM_START_LIQUIDATION_FIELDS,
309};
310
311const SYSTEM_STOP_LIQUIDATION_TYPED_DATA: TypedDataSpec = TypedDataSpec {
312 inner_type: "StopLiquidation",
313 inner_fields: SYSTEM_STOP_LIQUIDATION_FIELDS,
314};
315
316const SYSTEM_WITHDRAW_TOKEN_TYPED_DATA: TypedDataSpec = TypedDataSpec {
317 inner_type: "WithdrawToken",
318 inner_fields: SYSTEM_WITHDRAW_TOKEN_FIELDS,
319};
320
321const HL_LIMIT_ORDER_SPEC: ActionSpec = ActionSpec {
322 action_key: "hl_limit_order",
323 version: HL_ACTION_VERSION,
324 id: HL_ACTION_ID_LIMIT_ORDER,
325 primary_type: "HLOrder",
326 signer_type: SignerType::ApiWallet,
327 domain: DomainKind::Api,
328 supported: true,
329 typed_data: Some(HL_LIMIT_ORDER_TYPED_DATA),
330};
331
332const HL_CANCEL_BY_OID_SPEC: ActionSpec = ActionSpec {
333 action_key: "hl_cancel_by_oid",
334 version: HL_ACTION_VERSION,
335 id: HL_ACTION_ID_CANCEL_BY_OID,
336 primary_type: "HLCancel",
337 signer_type: SignerType::ApiWallet,
338 domain: DomainKind::Api,
339 supported: true,
340 typed_data: Some(HL_CANCEL_BY_OID_TYPED_DATA),
341};
342
343const HL_CANCEL_BY_CLOID_SPEC: ActionSpec = ActionSpec {
344 action_key: "hl_cancel_by_cloid",
345 version: HL_ACTION_VERSION,
346 id: HL_ACTION_ID_CANCEL_BY_CLOID,
347 primary_type: "HLCancelByCloid",
348 signer_type: SignerType::ApiWallet,
349 domain: DomainKind::Api,
350 supported: true,
351 typed_data: Some(HL_CANCEL_BY_CLOID_TYPED_DATA),
352};
353
354const HC_UPDATE_API_WALLET_SPEC: ActionSpec = ActionSpec {
355 action_key: "hc_update_api_wallet",
356 version: HC_ACTION_VERSION,
357 id: HC_ACTION_ID_UPDATE_API_WALLET,
358 primary_type: "HCUpdateApiWallet",
359 signer_type: SignerType::Manager,
360 domain: DomainKind::Manager,
361 supported: true,
362 typed_data: Some(HC_UPDATE_API_WALLET_TYPED_DATA),
363};
364
365const HL_SEND_ASSET_SPEC: ActionSpec = ActionSpec {
366 action_key: "hl_send_asset",
367 version: HL_ACTION_VERSION,
368 id: HL_ACTION_ID_SEND_ASSET,
369 primary_type: "HLSendAsset",
370 signer_type: SignerType::Manager,
371 domain: DomainKind::Manager,
372 supported: false,
373 typed_data: Some(HL_SEND_ASSET_TYPED_DATA),
374};
375
376const HC_TRANSFER_OPTION_SPEC: ActionSpec = ActionSpec {
377 action_key: "hc_transfer_option",
378 version: HC_ACTION_VERSION,
379 id: HC_ACTION_ID_TRANSFER_OPTION,
380 primary_type: "HCTransferOption",
381 signer_type: SignerType::Manager,
382 domain: DomainKind::Manager,
383 supported: false,
384 typed_data: None,
385};
386
387const RSM_HL_LIMIT_ORDER_SPEC: ActionSpec = ActionSpec {
388 action_key: "rsm_hl_limit_order",
389 version: HL_ACTION_VERSION,
390 id: HL_ACTION_ID_LIMIT_ORDER,
391 primary_type: "HLOrder",
392 signer_type: SignerType::Rsm,
393 domain: DomainKind::Rsm,
394 supported: false,
395 typed_data: Some(HL_LIMIT_ORDER_TYPED_DATA),
396};
397
398const RSM_HL_CANCEL_BY_OID_SPEC: ActionSpec = ActionSpec {
399 action_key: "rsm_hl_cancel_by_oid",
400 version: HL_ACTION_VERSION,
401 id: HL_ACTION_ID_CANCEL_BY_OID,
402 primary_type: "HLCancel",
403 signer_type: SignerType::Rsm,
404 domain: DomainKind::Rsm,
405 supported: false,
406 typed_data: Some(HL_CANCEL_BY_OID_TYPED_DATA),
407};
408
409const RSM_HL_CANCEL_BY_CLOID_SPEC: ActionSpec = ActionSpec {
410 action_key: "rsm_hl_cancel_by_cloid",
411 version: HL_ACTION_VERSION,
412 id: HL_ACTION_ID_CANCEL_BY_CLOID,
413 primary_type: "HLCancelByCloid",
414 signer_type: SignerType::Rsm,
415 domain: DomainKind::Rsm,
416 supported: false,
417 typed_data: Some(HL_CANCEL_BY_CLOID_TYPED_DATA),
418};
419
420const RSM_HL_SEND_ASSET_SPEC: ActionSpec = ActionSpec {
421 action_key: "rsm_hl_send_asset",
422 version: HL_ACTION_VERSION,
423 id: HL_ACTION_ID_SEND_ASSET,
424 primary_type: "HLSendAsset",
425 signer_type: SignerType::Rsm,
426 domain: DomainKind::Rsm,
427 supported: false,
428 typed_data: Some(HL_SEND_ASSET_TYPED_DATA),
429};
430
431const SYSTEM_CREDIT_TOKEN_SPEC: ActionSpec = ActionSpec {
432 action_key: "system_credit_token",
433 version: SYSTEM_ACTION_VERSION,
434 id: SYSTEM_ACTION_ID_CREDIT_TOKEN,
435 primary_type: "SystemCreditToken",
436 signer_type: SignerType::Rsm,
437 domain: DomainKind::Rsm,
438 supported: false,
439 typed_data: Some(SYSTEM_CREDIT_TOKEN_TYPED_DATA),
440};
441
442const SYSTEM_CREDIT_OPTION_SPEC: ActionSpec = ActionSpec {
443 action_key: "system_credit_option",
444 version: SYSTEM_ACTION_VERSION,
445 id: SYSTEM_ACTION_ID_CREDIT_OPTION,
446 primary_type: "SystemCreditOption",
447 signer_type: SignerType::Rsm,
448 domain: DomainKind::Rsm,
449 supported: false,
450 typed_data: Some(SYSTEM_CREDIT_OPTION_TYPED_DATA),
451};
452
453const SYSTEM_START_LIQUIDATION_SPEC: ActionSpec = ActionSpec {
454 action_key: "system_start_liquidation",
455 version: SYSTEM_ACTION_VERSION,
456 id: SYSTEM_ACTION_ID_START_LIQUIDATION,
457 primary_type: "SystemStartLiquidation",
458 signer_type: SignerType::Rsm,
459 domain: DomainKind::Rsm,
460 supported: false,
461 typed_data: Some(SYSTEM_START_LIQUIDATION_TYPED_DATA),
462};
463
464const SYSTEM_STOP_LIQUIDATION_SPEC: ActionSpec = ActionSpec {
465 action_key: "system_stop_liquidation",
466 version: SYSTEM_ACTION_VERSION,
467 id: SYSTEM_ACTION_ID_STOP_LIQUIDATION,
468 primary_type: "SystemStopLiquidation",
469 signer_type: SignerType::Rsm,
470 domain: DomainKind::Rsm,
471 supported: false,
472 typed_data: Some(SYSTEM_STOP_LIQUIDATION_TYPED_DATA),
473};
474
475const SYSTEM_WITHDRAW_TOKEN_SPEC: ActionSpec = ActionSpec {
476 action_key: "system_withdraw_token",
477 version: SYSTEM_ACTION_VERSION,
478 id: SYSTEM_ACTION_ID_WITHDRAW_TOKEN,
479 primary_type: "SystemWithdrawToken",
480 signer_type: SignerType::Rsm,
481 domain: DomainKind::Rsm,
482 supported: false,
483 typed_data: Some(SYSTEM_WITHDRAW_TOKEN_TYPED_DATA),
484};
485
486impl ActionKey {
487 pub fn parse(value: &str) -> Result<Self, ParseActionKeyError> {
488 match value {
489 "hl_limit_order" => Ok(Self::HlLimitOrder),
490 "hl_cancel_by_oid" => Ok(Self::HlCancelByOid),
491 "hl_cancel_by_cloid" => Ok(Self::HlCancelByCloid),
492 "hc_update_api_wallet" => Ok(Self::HcUpdateApiWallet),
493 "hl_send_asset" => Ok(Self::HlSendAsset),
494 "hc_transfer_option" => Ok(Self::HcTransferOption),
495 "rsm_hl_limit_order" => Ok(Self::RsmHlLimitOrder),
496 "rsm_hl_cancel_by_oid" => Ok(Self::RsmHlCancelByOid),
497 "rsm_hl_cancel_by_cloid" => Ok(Self::RsmHlCancelByCloid),
498 "rsm_hl_send_asset" => Ok(Self::RsmHlSendAsset),
499 "system_credit_token" => Ok(Self::SystemCreditToken),
500 "system_credit_option" => Ok(Self::SystemCreditOption),
501 "system_start_liquidation" => Ok(Self::SystemStartLiquidation),
502 "system_stop_liquidation" => Ok(Self::SystemStopLiquidation),
503 "system_withdraw_token" => Ok(Self::SystemWithdrawToken),
504 _ => Err(ParseActionKeyError::new(value)),
505 }
506 }
507
508 pub const fn as_str(self) -> &'static str {
509 self.spec().action_key
510 }
511
512 pub const fn spec(self) -> &'static ActionSpec {
513 match self {
514 Self::HlLimitOrder => &HL_LIMIT_ORDER_SPEC,
515 Self::HlCancelByOid => &HL_CANCEL_BY_OID_SPEC,
516 Self::HlCancelByCloid => &HL_CANCEL_BY_CLOID_SPEC,
517 Self::HcUpdateApiWallet => &HC_UPDATE_API_WALLET_SPEC,
518 Self::HlSendAsset => &HL_SEND_ASSET_SPEC,
519 Self::HcTransferOption => &HC_TRANSFER_OPTION_SPEC,
520 Self::RsmHlLimitOrder => &RSM_HL_LIMIT_ORDER_SPEC,
521 Self::RsmHlCancelByOid => &RSM_HL_CANCEL_BY_OID_SPEC,
522 Self::RsmHlCancelByCloid => &RSM_HL_CANCEL_BY_CLOID_SPEC,
523 Self::RsmHlSendAsset => &RSM_HL_SEND_ASSET_SPEC,
524 Self::SystemCreditToken => &SYSTEM_CREDIT_TOKEN_SPEC,
525 Self::SystemCreditOption => &SYSTEM_CREDIT_OPTION_SPEC,
526 Self::SystemStartLiquidation => &SYSTEM_START_LIQUIDATION_SPEC,
527 Self::SystemStopLiquidation => &SYSTEM_STOP_LIQUIDATION_SPEC,
528 Self::SystemWithdrawToken => &SYSTEM_WITHDRAW_TOKEN_SPEC,
529 }
530 }
531
532 pub const fn from_rsm_action_parts(version: u8, id: u32) -> Option<Self> {
533 match (version, id) {
534 (SYSTEM_ACTION_VERSION, SYSTEM_ACTION_ID_CREDIT_TOKEN) => Some(Self::SystemCreditToken),
535 (SYSTEM_ACTION_VERSION, SYSTEM_ACTION_ID_CREDIT_OPTION) => {
536 Some(Self::SystemCreditOption)
537 }
538 (SYSTEM_ACTION_VERSION, SYSTEM_ACTION_ID_START_LIQUIDATION) => {
539 Some(Self::SystemStartLiquidation)
540 }
541 (SYSTEM_ACTION_VERSION, SYSTEM_ACTION_ID_STOP_LIQUIDATION) => {
542 Some(Self::SystemStopLiquidation)
543 }
544 (SYSTEM_ACTION_VERSION, SYSTEM_ACTION_ID_WITHDRAW_TOKEN) => {
545 Some(Self::SystemWithdrawToken)
546 }
547 (HL_ACTION_VERSION, HL_ACTION_ID_LIMIT_ORDER) => Some(Self::RsmHlLimitOrder),
548 (HL_ACTION_VERSION, HL_ACTION_ID_CANCEL_BY_OID) => Some(Self::RsmHlCancelByOid),
549 (HL_ACTION_VERSION, HL_ACTION_ID_CANCEL_BY_CLOID) => Some(Self::RsmHlCancelByCloid),
550 (HL_ACTION_VERSION, HL_ACTION_ID_SEND_ASSET) => Some(Self::RsmHlSendAsset),
551 _ => None,
552 }
553 }
554}
555
556impl FromStr for ActionKey {
557 type Err = ParseActionKeyError;
558
559 fn from_str(s: &str) -> Result<Self, Self::Err> {
560 Self::parse(s)
561 }
562}
563
564impl fmt::Display for ActionKey {
565 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
566 write!(f, "{}", self.as_str())
567 }
568}
569
570#[cfg(test)]
571mod tests {
572 use super::ActionKey;
573 use crate::directives::{
574 HL_ACTION_ID_CANCEL_BY_CLOID, HL_ACTION_ID_CANCEL_BY_OID, HL_ACTION_ID_LIMIT_ORDER,
575 HL_ACTION_ID_SEND_ASSET, HL_ACTION_VERSION, SYSTEM_ACTION_ID_CREDIT_OPTION,
576 SYSTEM_ACTION_ID_CREDIT_TOKEN, SYSTEM_ACTION_ID_START_LIQUIDATION,
577 SYSTEM_ACTION_ID_STOP_LIQUIDATION, SYSTEM_ACTION_ID_WITHDRAW_TOKEN, SYSTEM_ACTION_VERSION,
578 };
579 use std::str::FromStr;
580
581 #[test]
582 fn action_key_round_trip_string_mappings() {
583 let cases = [
584 (ActionKey::HlLimitOrder, "hl_limit_order"),
585 (ActionKey::HlCancelByOid, "hl_cancel_by_oid"),
586 (ActionKey::HlCancelByCloid, "hl_cancel_by_cloid"),
587 (ActionKey::HcUpdateApiWallet, "hc_update_api_wallet"),
588 (ActionKey::HlSendAsset, "hl_send_asset"),
589 (ActionKey::HcTransferOption, "hc_transfer_option"),
590 (ActionKey::RsmHlLimitOrder, "rsm_hl_limit_order"),
591 (ActionKey::RsmHlCancelByOid, "rsm_hl_cancel_by_oid"),
592 (ActionKey::RsmHlCancelByCloid, "rsm_hl_cancel_by_cloid"),
593 (ActionKey::RsmHlSendAsset, "rsm_hl_send_asset"),
594 (ActionKey::SystemCreditToken, "system_credit_token"),
595 (ActionKey::SystemCreditOption, "system_credit_option"),
596 (
597 ActionKey::SystemStartLiquidation,
598 "system_start_liquidation",
599 ),
600 (ActionKey::SystemStopLiquidation, "system_stop_liquidation"),
601 (ActionKey::SystemWithdrawToken, "system_withdraw_token"),
602 ];
603
604 for (action_key, expected) in cases {
605 assert_eq!(action_key.as_str(), expected);
606 assert_eq!(action_key.to_string(), expected);
607 assert_eq!(ActionKey::from_str(expected).unwrap(), action_key);
608 }
609 }
610
611 #[test]
612 fn parse_rejects_unknown_action_key() {
613 let err = ActionKey::from_str("not_real").unwrap_err();
614 assert_eq!(err.to_string(), "Unsupported action key: not_real");
615 }
616
617 #[test]
618 fn action_key_serde_preserves_persisted_variant_names() {
619 assert_eq!(
620 serde_json::to_string(&ActionKey::HlLimitOrder).unwrap(),
621 "\"HlLimitOrder\""
622 );
623 assert_eq!(
624 serde_json::from_str::<ActionKey>("\"HlLimitOrder\"").unwrap(),
625 ActionKey::HlLimitOrder
626 );
627 assert!(serde_json::from_str::<ActionKey>("\"hl_limit_order\"").is_err());
628 }
629
630 #[test]
631 fn maps_rsm_version_and_action_id_to_action_key() {
632 let cases = [
633 (
634 SYSTEM_ACTION_VERSION,
635 SYSTEM_ACTION_ID_CREDIT_TOKEN,
636 ActionKey::SystemCreditToken,
637 ),
638 (
639 SYSTEM_ACTION_VERSION,
640 SYSTEM_ACTION_ID_CREDIT_OPTION,
641 ActionKey::SystemCreditOption,
642 ),
643 (
644 SYSTEM_ACTION_VERSION,
645 SYSTEM_ACTION_ID_START_LIQUIDATION,
646 ActionKey::SystemStartLiquidation,
647 ),
648 (
649 SYSTEM_ACTION_VERSION,
650 SYSTEM_ACTION_ID_STOP_LIQUIDATION,
651 ActionKey::SystemStopLiquidation,
652 ),
653 (
654 SYSTEM_ACTION_VERSION,
655 SYSTEM_ACTION_ID_WITHDRAW_TOKEN,
656 ActionKey::SystemWithdrawToken,
657 ),
658 (
659 HL_ACTION_VERSION,
660 HL_ACTION_ID_LIMIT_ORDER,
661 ActionKey::RsmHlLimitOrder,
662 ),
663 (
664 HL_ACTION_VERSION,
665 HL_ACTION_ID_CANCEL_BY_OID,
666 ActionKey::RsmHlCancelByOid,
667 ),
668 (
669 HL_ACTION_VERSION,
670 HL_ACTION_ID_CANCEL_BY_CLOID,
671 ActionKey::RsmHlCancelByCloid,
672 ),
673 (
674 HL_ACTION_VERSION,
675 HL_ACTION_ID_SEND_ASSET,
676 ActionKey::RsmHlSendAsset,
677 ),
678 ];
679
680 for (version, id, expected) in cases {
681 assert_eq!(
682 ActionKey::from_rsm_action_parts(version, id),
683 Some(expected)
684 );
685 }
686
687 assert_eq!(ActionKey::from_rsm_action_parts(42, 42), None);
688 }
689}