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 IcpRefillMode {
20 Canister,
21 Fabricate,
22}
23
24#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
29#[remain::sorted]
30pub enum IcpRefillStatus {
31 Completed,
32 Failed,
33 InvalidTransaction,
34 NotifyProcessing,
35 Refunded,
36 Requested,
37 TransactionTooOld,
38 Transferred,
39}
40
41#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
45#[remain::sorted]
46pub enum IcpRefillErrorCode {
47 BadFee,
48 CyclesSentOverflow,
49 Duplicate,
50 FabricationUnavailable,
51 InvalidLedgerBlockIndex,
52 InvalidTransaction,
53 LedgerTransferFailed,
54 NotifyFailed,
55 NotifyMaxAttempts,
56 Processing,
57 RateGateDenied,
58 Refunded,
59 RequestDenied,
60 TransactionTooOld,
61 TransferWindowStale,
62}
63
64#[must_use]
66pub const fn icp_refill_outcome_is_resumable(
67 status: IcpRefillStatus,
68 error_code: Option<IcpRefillErrorCode>,
69 ledger_block_recorded: bool,
70) -> bool {
71 matches!(
72 status,
73 IcpRefillStatus::Requested
74 | IcpRefillStatus::Transferred
75 | IcpRefillStatus::NotifyProcessing
76 ) || matches!(
77 (status, error_code, ledger_block_recorded),
78 (
79 IcpRefillStatus::Failed,
80 Some(IcpRefillErrorCode::NotifyFailed),
81 true
82 ) | (
83 IcpRefillStatus::Failed,
84 Some(IcpRefillErrorCode::BadFee),
85 false
86 )
87 )
88}
89
90#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn resumable_outcome_requires_active_or_retryable_state() {
100 assert!(icp_refill_outcome_is_resumable(
101 IcpRefillStatus::Requested,
102 None,
103 false
104 ));
105 assert!(icp_refill_outcome_is_resumable(
106 IcpRefillStatus::Transferred,
107 None,
108 true
109 ));
110 assert!(icp_refill_outcome_is_resumable(
111 IcpRefillStatus::NotifyProcessing,
112 Some(IcpRefillErrorCode::Processing),
113 true
114 ));
115 assert!(icp_refill_outcome_is_resumable(
116 IcpRefillStatus::Failed,
117 Some(IcpRefillErrorCode::BadFee),
118 false
119 ));
120 assert!(icp_refill_outcome_is_resumable(
121 IcpRefillStatus::Failed,
122 Some(IcpRefillErrorCode::NotifyFailed),
123 true
124 ));
125
126 assert!(!icp_refill_outcome_is_resumable(
127 IcpRefillStatus::Completed,
128 None,
129 true
130 ));
131 assert!(!icp_refill_outcome_is_resumable(
132 IcpRefillStatus::Failed,
133 Some(IcpRefillErrorCode::NotifyMaxAttempts),
134 true
135 ));
136 assert!(!icp_refill_outcome_is_resumable(
137 IcpRefillStatus::Failed,
138 Some(IcpRefillErrorCode::NotifyFailed),
139 false
140 ));
141 assert!(!icp_refill_outcome_is_resumable(
142 IcpRefillStatus::Failed,
143 Some(IcpRefillErrorCode::BadFee),
144 true
145 ));
146 }
147}