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 Duplicate,
49 FabricationUnavailable,
50 InvalidLedgerBlockIndex,
51 InvalidTransaction,
52 LedgerTransferFailed,
53 NotifyFailed,
54 NotifyMaxAttempts,
55 Processing,
56 RateGateDenied,
57 Refunded,
58 RequestDenied,
59 TransactionTooOld,
60 TransferWindowStale,
61}
62
63#[must_use]
65pub const fn icp_refill_outcome_is_resumable(
66 status: IcpRefillStatus,
67 error_code: Option<IcpRefillErrorCode>,
68 ledger_block_recorded: bool,
69) -> bool {
70 matches!(
71 status,
72 IcpRefillStatus::Requested
73 | IcpRefillStatus::Transferred
74 | IcpRefillStatus::NotifyProcessing
75 ) || matches!(
76 (status, error_code, ledger_block_recorded),
77 (
78 IcpRefillStatus::Failed,
79 Some(IcpRefillErrorCode::NotifyFailed),
80 true
81 ) | (
82 IcpRefillStatus::Failed,
83 Some(IcpRefillErrorCode::BadFee),
84 false
85 )
86 )
87}
88
89#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn resumable_outcome_requires_active_or_retryable_state() {
99 assert!(icp_refill_outcome_is_resumable(
100 IcpRefillStatus::Requested,
101 None,
102 false
103 ));
104 assert!(icp_refill_outcome_is_resumable(
105 IcpRefillStatus::Transferred,
106 None,
107 true
108 ));
109 assert!(icp_refill_outcome_is_resumable(
110 IcpRefillStatus::NotifyProcessing,
111 Some(IcpRefillErrorCode::Processing),
112 true
113 ));
114 assert!(icp_refill_outcome_is_resumable(
115 IcpRefillStatus::Failed,
116 Some(IcpRefillErrorCode::BadFee),
117 false
118 ));
119 assert!(icp_refill_outcome_is_resumable(
120 IcpRefillStatus::Failed,
121 Some(IcpRefillErrorCode::NotifyFailed),
122 true
123 ));
124
125 assert!(!icp_refill_outcome_is_resumable(
126 IcpRefillStatus::Completed,
127 None,
128 true
129 ));
130 assert!(!icp_refill_outcome_is_resumable(
131 IcpRefillStatus::Failed,
132 Some(IcpRefillErrorCode::NotifyMaxAttempts),
133 true
134 ));
135 assert!(!icp_refill_outcome_is_resumable(
136 IcpRefillStatus::Failed,
137 Some(IcpRefillErrorCode::NotifyFailed),
138 false
139 ));
140 assert!(!icp_refill_outcome_is_resumable(
141 IcpRefillStatus::Failed,
142 Some(IcpRefillErrorCode::BadFee),
143 true
144 ));
145 }
146}