use candid::CandidType;
use serde::{Deserialize, Serialize};
#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[remain::sorted]
pub enum IcpRefillMode {
Canister,
Fabricate,
}
#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[remain::sorted]
pub enum IcpRefillStatus {
Completed,
Failed,
InvalidTransaction,
NotifyProcessing,
Refunded,
Requested,
TransactionTooOld,
Transferred,
}
#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[remain::sorted]
pub enum IcpRefillErrorCode {
BadFee,
Duplicate,
FabricationUnavailable,
InvalidLedgerBlockIndex,
InvalidTransaction,
LedgerTransferFailed,
NotifyFailed,
NotifyMaxAttempts,
Processing,
RateGateDenied,
Refunded,
RequestDenied,
TransactionTooOld,
TransferWindowStale,
}
#[must_use]
pub const fn icp_refill_outcome_is_resumable(
status: IcpRefillStatus,
error_code: Option<IcpRefillErrorCode>,
ledger_block_recorded: bool,
) -> bool {
matches!(
status,
IcpRefillStatus::Requested
| IcpRefillStatus::Transferred
| IcpRefillStatus::NotifyProcessing
) || matches!(
(status, error_code, ledger_block_recorded),
(
IcpRefillStatus::Failed,
Some(IcpRefillErrorCode::NotifyFailed),
true
) | (
IcpRefillStatus::Failed,
Some(IcpRefillErrorCode::BadFee),
false
)
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn resumable_outcome_requires_active_or_retryable_state() {
assert!(icp_refill_outcome_is_resumable(
IcpRefillStatus::Requested,
None,
false
));
assert!(icp_refill_outcome_is_resumable(
IcpRefillStatus::Transferred,
None,
true
));
assert!(icp_refill_outcome_is_resumable(
IcpRefillStatus::NotifyProcessing,
Some(IcpRefillErrorCode::Processing),
true
));
assert!(icp_refill_outcome_is_resumable(
IcpRefillStatus::Failed,
Some(IcpRefillErrorCode::BadFee),
false
));
assert!(icp_refill_outcome_is_resumable(
IcpRefillStatus::Failed,
Some(IcpRefillErrorCode::NotifyFailed),
true
));
assert!(!icp_refill_outcome_is_resumable(
IcpRefillStatus::Completed,
None,
true
));
assert!(!icp_refill_outcome_is_resumable(
IcpRefillStatus::Failed,
Some(IcpRefillErrorCode::NotifyMaxAttempts),
true
));
assert!(!icp_refill_outcome_is_resumable(
IcpRefillStatus::Failed,
Some(IcpRefillErrorCode::NotifyFailed),
false
));
assert!(!icp_refill_outcome_is_resumable(
IcpRefillStatus::Failed,
Some(IcpRefillErrorCode::BadFee),
true
));
}
}