1use cdk::nuts::CurrencyUnit as CdkCurrencyUnit;
4use cdk::Amount as CdkAmount;
5use serde::{Deserialize, Serialize};
6
7use crate::error::FfiError;
8
9#[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(¤t_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(FfiError::AmountOverflow)
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(FfiError::AmountOverflow)
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(FfiError::AmountOverflow)
64 }
65
66 pub fn divide(&self, divisor: u64) -> Result<Amount, FfiError> {
67 if divisor == 0 {
68 return Err(FfiError::DivisionByZero);
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(FfiError::AmountOverflow)
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#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, uniffi::Enum)]
95pub enum CurrencyUnit {
96 Sat,
97 Msat,
98 Usd,
99 Eur,
100 Auth,
101 Custom { unit: String },
102}
103
104impl From<CdkCurrencyUnit> for CurrencyUnit {
105 fn from(unit: CdkCurrencyUnit) -> Self {
106 match unit {
107 CdkCurrencyUnit::Sat => CurrencyUnit::Sat,
108 CdkCurrencyUnit::Msat => CurrencyUnit::Msat,
109 CdkCurrencyUnit::Usd => CurrencyUnit::Usd,
110 CdkCurrencyUnit::Eur => CurrencyUnit::Eur,
111 CdkCurrencyUnit::Auth => CurrencyUnit::Auth,
112 CdkCurrencyUnit::Custom(s) => CurrencyUnit::Custom { unit: s },
113 _ => CurrencyUnit::Sat, }
115 }
116}
117
118impl From<CurrencyUnit> for CdkCurrencyUnit {
119 fn from(unit: CurrencyUnit) -> Self {
120 match unit {
121 CurrencyUnit::Sat => CdkCurrencyUnit::Sat,
122 CurrencyUnit::Msat => CdkCurrencyUnit::Msat,
123 CurrencyUnit::Usd => CdkCurrencyUnit::Usd,
124 CurrencyUnit::Eur => CdkCurrencyUnit::Eur,
125 CurrencyUnit::Auth => CdkCurrencyUnit::Auth,
126 CurrencyUnit::Custom { unit } => CdkCurrencyUnit::Custom(unit),
127 }
128 }
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Enum)]
133pub enum SplitTarget {
134 None,
136 Value { amount: Amount },
138 Values { amounts: Vec<Amount> },
140}
141
142impl From<SplitTarget> for cdk::amount::SplitTarget {
143 fn from(target: SplitTarget) -> Self {
144 match target {
145 SplitTarget::None => cdk::amount::SplitTarget::None,
146 SplitTarget::Value { amount } => cdk::amount::SplitTarget::Value(amount.into()),
147 SplitTarget::Values { amounts } => {
148 cdk::amount::SplitTarget::Values(amounts.into_iter().map(Into::into).collect())
149 }
150 }
151 }
152}
153
154impl From<cdk::amount::SplitTarget> for SplitTarget {
155 fn from(target: cdk::amount::SplitTarget) -> Self {
156 match target {
157 cdk::amount::SplitTarget::None => SplitTarget::None,
158 cdk::amount::SplitTarget::Value(amount) => SplitTarget::Value {
159 amount: amount.into(),
160 },
161 cdk::amount::SplitTarget::Values(amounts) => SplitTarget::Values {
162 amounts: amounts.into_iter().map(Into::into).collect(),
163 },
164 }
165 }
166}