1
2
3pub mod error;
4pub mod manager;
5pub mod update;
6mod payment_method;
7
8pub use self::payment_method::PaymentMethod;
9
10use std::collections::HashMap;
11use std::fmt;
12use std::str::FromStr;
13
14use bitcoin::{Amount, SignedAmount};
15use chrono::DateTime;
16use lightning::offers::offer::Offer;
17use lnurllib::lightning_address::LightningAddress;
18use serde::{Deserialize, Serialize};
19
20use ark::VtxoId;
21use ark::lightning::Invoice;
22
23const MOVEMENT_PENDING: &'static str = "pending";
24const MOVEMENT_SUCCESSFUL: &'static str = "successful";
25const MOVEMENT_FAILED: &'static str = "failed";
26const MOVEMENT_CANCELED: &'static str = "canceled";
27
28#[derive(Debug, Clone)]
30pub struct Movement {
31 pub id: MovementId,
33 pub status: MovementStatus,
35 pub subsystem: MovementSubsystem,
38 pub metadata: HashMap<String, serde_json::Value>,
41 pub intended_balance: SignedAmount,
44 pub effective_balance: SignedAmount,
48 pub offchain_fee: Amount,
52 pub sent_to: Vec<MovementDestination>,
54 pub received_on: Vec<MovementDestination>,
57 pub input_vtxos: Vec<VtxoId>,
60 pub output_vtxos: Vec<VtxoId>,
63 pub exited_vtxos: Vec<VtxoId>,
68 pub time: MovementTimestamp,
70}
71
72#[derive(Clone, Copy, Eq, Hash, PartialEq, Deserialize, Serialize)]
74pub struct MovementId(pub u32);
75
76impl MovementId {
77 pub fn new(id: u32) -> Self {
78 Self(id)
79 }
80}
81
82impl fmt::Display for MovementId {
83 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
84 fmt::Display::fmt(&self.0, f)
85 }
86}
87
88impl fmt::Debug for MovementId {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 fmt::Display::fmt(&self, f)
91 }
92}
93
94#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
99pub enum MovementStatus {
100 Pending,
102 Successful,
105 Failed,
108 Canceled,
111}
112
113impl MovementStatus {
114 pub fn as_str(&self) -> &'static str {
119 match self {
120 Self::Pending => MOVEMENT_PENDING,
121 Self::Successful => MOVEMENT_SUCCESSFUL,
122 Self::Failed => MOVEMENT_FAILED,
123 Self::Canceled => MOVEMENT_CANCELED,
124 }
125 }
126}
127
128impl fmt::Display for MovementStatus {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 f.write_str(self.as_str())
131 }
132}
133
134impl fmt::Debug for MovementStatus {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 fmt::Display::fmt(&self, f)
137 }
138}
139
140impl FromStr for MovementStatus {
141 type Err = anyhow::Error;
142
143 fn from_str(s: &str) -> Result<Self, Self::Err> {
145 match s {
146 MOVEMENT_PENDING => Ok(MovementStatus::Pending),
147 MOVEMENT_SUCCESSFUL => Ok(MovementStatus::Successful),
148 MOVEMENT_FAILED => Ok(MovementStatus::Failed),
149 MOVEMENT_CANCELED => Ok(MovementStatus::Canceled),
150 _ => bail!("Invalid MovementStatus: {}", s),
151 }
152 }
153}
154
155impl Serialize for MovementStatus {
156 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
157 where
158 S: serde::Serializer,
159 {
160 serializer.serialize_str(self.as_str())
161 }
162}
163
164impl<'de> Deserialize<'de> for MovementStatus {
165 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
166 where
167 D: serde::Deserializer<'de>,
168 {
169 let s = String::deserialize(deserializer)?;
170 MovementStatus::from_str(&s).map_err(serde::de::Error::custom)
171 }
172}
173
174#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
177pub struct MovementDestination {
178 pub destination: PaymentMethod,
180 pub amount: Amount,
182}
183
184impl MovementDestination {
185 pub fn new(payment_method: PaymentMethod, amount: Amount) -> Self {
186 Self { destination: payment_method, amount }
187 }
188
189 pub fn ark(address: ark::Address, amount: Amount) -> Self {
190 Self::new(address.into(), amount)
191 }
192
193 pub fn bitcoin(address: bitcoin::Address, amount: Amount) -> Self {
194 Self::new(address.into(), amount)
195 }
196
197 pub fn invoice(invoice: Invoice, amount: Amount) -> Self {
198 Self::new(invoice.into(), amount)
199 }
200
201 pub fn offer(offer: Offer, amount: Amount) -> Self {
202 Self::new(offer.into(), amount)
203 }
204
205 pub fn lightning_address(address: LightningAddress, amount: Amount) -> Self {
206 Self::new(address.into(), amount)
207 }
208
209 pub fn custom(destination: String, amount: Amount) -> Self {
210 Self::new(PaymentMethod::Custom(destination), amount)
211 }
212}
213
214#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
217pub struct MovementSubsystem {
218 pub name: String,
220 pub kind: String,
222}
223
224#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
226pub struct MovementTimestamp {
227 pub created_at: DateTime<chrono::Local>,
229 pub updated_at: DateTime<chrono::Local>,
231 pub completed_at: Option<DateTime<chrono::Local>>,
233}