1pub mod error;
2pub mod manager;
3pub mod update;
4
5use std::collections::HashMap;
6use std::fmt;
7use std::str::FromStr;
8
9use bitcoin::{Amount, SignedAmount};
10use chrono::DateTime;
11use serde::{Deserialize, Serialize};
12
13use ark::VtxoId;
14
15const MOVEMENT_PENDING: &'static str = "pending";
16const MOVEMENT_FINISHED: &'static str = "finished";
17const MOVEMENT_FAILED: &'static str = "failed";
18const MOVEMENT_CANCELLED: &'static str = "cancelled";
19
20#[derive(Debug, Clone)]
22pub struct Movement {
23 pub id: MovementId,
25 pub status: MovementStatus,
27 pub subsystem: MovementSubsystem,
30 pub metadata: HashMap<String, serde_json::Value>,
33 pub intended_balance: SignedAmount,
36 pub effective_balance: SignedAmount,
40 pub offchain_fee: Amount,
44 pub sent_to: Vec<MovementDestination>,
46 pub received_on: Vec<MovementDestination>,
49 pub input_vtxos: Vec<VtxoId>,
52 pub output_vtxos: Vec<VtxoId>,
55 pub exited_vtxos: Vec<VtxoId>,
60 pub time: MovementTimestamp,
62}
63
64#[derive(Clone, Copy, Eq, Hash, PartialEq, Deserialize, Serialize)]
66pub struct MovementId(pub u32);
67
68impl MovementId {
69 pub fn new(id: u32) -> Self {
70 Self(id)
71 }
72}
73
74impl fmt::Display for MovementId {
75 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
76 fmt::Display::fmt(&self.0, f)
77 }
78}
79
80impl fmt::Debug for MovementId {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 fmt::Display::fmt(&self, f)
83 }
84}
85
86#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
88pub enum MovementStatus {
89 Pending,
91 Finished,
94 Failed,
97 Cancelled,
100}
101
102impl MovementStatus {
103 pub fn as_str(&self) -> &'static str {
108 match self {
109 Self::Pending => MOVEMENT_PENDING,
110 Self::Finished => MOVEMENT_FINISHED,
111 Self::Failed => MOVEMENT_FAILED,
112 Self::Cancelled => MOVEMENT_CANCELLED,
113 }
114 }
115}
116
117impl fmt::Display for MovementStatus {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 f.write_str(self.as_str())
120 }
121}
122
123impl fmt::Debug for MovementStatus {
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 fmt::Display::fmt(&self, f)
126 }
127}
128
129impl FromStr for MovementStatus {
130 type Err = anyhow::Error;
131
132 fn from_str(s: &str) -> Result<Self, Self::Err> {
134 match s {
135 MOVEMENT_PENDING => Ok(MovementStatus::Pending),
136 MOVEMENT_FINISHED => Ok(MovementStatus::Finished),
137 MOVEMENT_FAILED => Ok(MovementStatus::Failed),
138 MOVEMENT_CANCELLED => Ok(MovementStatus::Cancelled),
139 _ => bail!("Invalid MovementStatus: {}", s),
140 }
141 }
142}
143
144impl Serialize for MovementStatus {
145 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
146 where
147 S: serde::Serializer,
148 {
149 serializer.serialize_str(self.as_str())
150 }
151}
152
153impl<'de> Deserialize<'de> for MovementStatus {
154 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
155 where
156 D: serde::Deserializer<'de>,
157 {
158 let s = String::deserialize(deserializer)?;
159 MovementStatus::from_str(&s).map_err(serde::de::Error::custom)
160 }
161}
162
163#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
166pub struct MovementDestination {
167 pub destination: String,
169 pub amount: Amount,
171}
172
173impl MovementDestination {
174 pub fn new(destination: String, amount: Amount) -> Self {
175 Self { destination, amount }
176 }
177}
178
179#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
182pub struct MovementSubsystem {
183 pub name: String,
185 pub kind: String,
187}
188
189#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
191pub struct MovementTimestamp {
192 pub created_at: DateTime<chrono::Local>,
194 pub updated_at: DateTime<chrono::Local>,
196 pub completed_at: Option<DateTime<chrono::Local>>,
198}