Skip to main content

cdk_ffi/types/
amount.rs

1//! Amount and currency related types
2
3use cdk::nuts::CurrencyUnit as CdkCurrencyUnit;
4use cdk::Amount as CdkAmount;
5use serde::{Deserialize, Serialize};
6
7use crate::error::FfiError;
8
9/// FFI-compatible Amount type
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, uniffi::Record)]
11#[serde(transparent)]
12pub struct Amount {
13    pub value: u64,
14}
15
16impl Amount {
17    pub fn new(value: u64) -> Self {
18        Self { value }
19    }
20
21    pub fn zero() -> Self {
22        Self { value: 0 }
23    }
24
25    pub fn is_zero(&self) -> bool {
26        self.value == 0
27    }
28
29    pub fn convert_unit(
30        &self,
31        current_unit: CurrencyUnit,
32        target_unit: CurrencyUnit,
33    ) -> Result<Amount, FfiError> {
34        Ok(CdkAmount::from(self.value)
35            .convert_unit(&current_unit.into(), &target_unit.into())
36            .map(Into::into)?)
37    }
38
39    pub fn add(&self, other: Amount) -> Result<Amount, FfiError> {
40        let self_amount = CdkAmount::from(self.value);
41        let other_amount = CdkAmount::from(other.value);
42        self_amount
43            .checked_add(other_amount)
44            .map(Into::into)
45            .ok_or_else(|| FfiError::internal("Amount overflow"))
46    }
47
48    pub fn subtract(&self, other: Amount) -> Result<Amount, FfiError> {
49        let self_amount = CdkAmount::from(self.value);
50        let other_amount = CdkAmount::from(other.value);
51        self_amount
52            .checked_sub(other_amount)
53            .map(Into::into)
54            .ok_or_else(|| FfiError::internal("Amount overflow"))
55    }
56
57    pub fn multiply(&self, factor: u64) -> Result<Amount, FfiError> {
58        let self_amount = CdkAmount::from(self.value);
59        let factor_amount = CdkAmount::from(factor);
60        self_amount
61            .checked_mul(factor_amount)
62            .map(Into::into)
63            .ok_or_else(|| FfiError::internal("Amount overflow"))
64    }
65
66    pub fn divide(&self, divisor: u64) -> Result<Amount, FfiError> {
67        if divisor == 0 {
68            return Err(FfiError::internal("Division by zero"));
69        }
70        let self_amount = CdkAmount::from(self.value);
71        let divisor_amount = CdkAmount::from(divisor);
72        self_amount
73            .checked_div(divisor_amount)
74            .map(Into::into)
75            .ok_or_else(|| FfiError::internal("Amount overflow"))
76    }
77}
78
79impl From<CdkAmount> for Amount {
80    fn from(amount: CdkAmount) -> Self {
81        Self {
82            value: u64::from(amount),
83        }
84    }
85}
86
87impl From<Amount> for CdkAmount {
88    fn from(amount: Amount) -> Self {
89        CdkAmount::from(amount.value)
90    }
91}
92
93/// FFI-compatible FeeAndAmounts
94#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)]
95pub struct FeeAndAmounts {
96    /// Input fee per thousand (ppk)
97    pub fee: u64,
98    /// Available amounts for this keyset
99    pub amounts: Vec<u64>,
100}
101
102impl From<cdk_common::amount::FeeAndAmounts> for FeeAndAmounts {
103    fn from(fa: cdk_common::amount::FeeAndAmounts) -> Self {
104        Self {
105            fee: fa.fee(),
106            amounts: fa.amounts().to_vec(),
107        }
108    }
109}
110
111/// FFI-compatible Currency Unit
112#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, uniffi::Enum)]
113pub enum CurrencyUnit {
114    Sat,
115    Msat,
116    Usd,
117    Eur,
118    Auth,
119    Custom { unit: String },
120}
121
122impl From<CdkCurrencyUnit> for CurrencyUnit {
123    fn from(unit: CdkCurrencyUnit) -> Self {
124        match unit {
125            CdkCurrencyUnit::Sat => CurrencyUnit::Sat,
126            CdkCurrencyUnit::Msat => CurrencyUnit::Msat,
127            CdkCurrencyUnit::Usd => CurrencyUnit::Usd,
128            CdkCurrencyUnit::Eur => CurrencyUnit::Eur,
129            CdkCurrencyUnit::Auth => CurrencyUnit::Auth,
130            CdkCurrencyUnit::Custom(s) => CurrencyUnit::Custom { unit: s },
131            _ => CurrencyUnit::Sat, // Default for unknown units
132        }
133    }
134}
135
136impl From<CurrencyUnit> for CdkCurrencyUnit {
137    fn from(unit: CurrencyUnit) -> Self {
138        match unit {
139            CurrencyUnit::Sat => CdkCurrencyUnit::Sat,
140            CurrencyUnit::Msat => CdkCurrencyUnit::Msat,
141            CurrencyUnit::Usd => CdkCurrencyUnit::Usd,
142            CurrencyUnit::Eur => CdkCurrencyUnit::Eur,
143            CurrencyUnit::Auth => CdkCurrencyUnit::Auth,
144            CurrencyUnit::Custom { unit } => CdkCurrencyUnit::Custom(unit),
145        }
146    }
147}
148
149/// FFI-compatible SplitTarget
150#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Enum)]
151pub enum SplitTarget {
152    /// Default target; least amount of proofs
153    None,
154    /// Target amount for wallet to have most proofs that add up to value
155    Value { amount: Amount },
156    /// Specific amounts to split into (must equal amount being split)
157    Values { amounts: Vec<Amount> },
158}
159
160impl From<SplitTarget> for cdk::amount::SplitTarget {
161    fn from(target: SplitTarget) -> Self {
162        match target {
163            SplitTarget::None => cdk::amount::SplitTarget::None,
164            SplitTarget::Value { amount } => cdk::amount::SplitTarget::Value(amount.into()),
165            SplitTarget::Values { amounts } => {
166                cdk::amount::SplitTarget::Values(amounts.into_iter().map(Into::into).collect())
167            }
168        }
169    }
170}
171
172impl From<cdk::amount::SplitTarget> for SplitTarget {
173    fn from(target: cdk::amount::SplitTarget) -> Self {
174        match target {
175            cdk::amount::SplitTarget::None => SplitTarget::None,
176            cdk::amount::SplitTarget::Value(amount) => SplitTarget::Value {
177                amount: amount.into(),
178            },
179            cdk::amount::SplitTarget::Values(amounts) => SplitTarget::Values {
180                amounts: amounts.into_iter().map(Into::into).collect(),
181            },
182        }
183    }
184}