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