canic_core/domain/
icp_refill.rs1use candid::CandidType;
11use serde::{Deserialize, Serialize};
12
13#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
18#[remain::sorted]
19pub enum IcpRefillStatus {
20 Completed,
21 Failed,
22 InvalidTransaction,
23 NotifyProcessing,
24 Refunded,
25 Requested,
26 TransactionTooOld,
27 Transferred,
28}
29
30#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
34#[remain::sorted]
35pub enum IcpRefillErrorCode {
36 BadFee,
37 CyclesSentOverflow,
38 Duplicate,
39 InvalidLedgerBlockIndex,
40 InvalidTransaction,
41 LedgerTransferFailed,
42 NotifyFailed,
43 NotifyMaxAttempts,
44 Processing,
45 Refunded,
46 TransactionTooOld,
47 TransferWindowStale,
48}
49
50#[must_use]
52pub const fn icp_refill_outcome_is_resumable(
53 status: IcpRefillStatus,
54 error_code: Option<IcpRefillErrorCode>,
55 ledger_block_recorded: bool,
56) -> bool {
57 matches!(
58 status,
59 IcpRefillStatus::Requested
60 | IcpRefillStatus::Transferred
61 | IcpRefillStatus::NotifyProcessing
62 ) || matches!(
63 (status, error_code, ledger_block_recorded),
64 (
65 IcpRefillStatus::Failed,
66 Some(IcpRefillErrorCode::NotifyFailed),
67 true
68 ) | (
69 IcpRefillStatus::Failed,
70 Some(IcpRefillErrorCode::BadFee),
71 false
72 )
73 )
74}
75
76#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn resumable_outcome_requires_active_or_retryable_state() {
86 assert!(icp_refill_outcome_is_resumable(
87 IcpRefillStatus::Requested,
88 None,
89 false
90 ));
91 assert!(icp_refill_outcome_is_resumable(
92 IcpRefillStatus::Transferred,
93 None,
94 true
95 ));
96 assert!(icp_refill_outcome_is_resumable(
97 IcpRefillStatus::NotifyProcessing,
98 Some(IcpRefillErrorCode::Processing),
99 true
100 ));
101 assert!(icp_refill_outcome_is_resumable(
102 IcpRefillStatus::Failed,
103 Some(IcpRefillErrorCode::BadFee),
104 false
105 ));
106 assert!(icp_refill_outcome_is_resumable(
107 IcpRefillStatus::Failed,
108 Some(IcpRefillErrorCode::NotifyFailed),
109 true
110 ));
111
112 assert!(!icp_refill_outcome_is_resumable(
113 IcpRefillStatus::Completed,
114 None,
115 true
116 ));
117 assert!(!icp_refill_outcome_is_resumable(
118 IcpRefillStatus::Failed,
119 Some(IcpRefillErrorCode::NotifyMaxAttempts),
120 true
121 ));
122 assert!(!icp_refill_outcome_is_resumable(
123 IcpRefillStatus::Failed,
124 Some(IcpRefillErrorCode::NotifyFailed),
125 false
126 ));
127 assert!(!icp_refill_outcome_is_resumable(
128 IcpRefillStatus::Failed,
129 Some(IcpRefillErrorCode::BadFee),
130 true
131 ));
132 }
133}