bark/movement/mod.rs
1pub mod manager;
2pub mod update;
3
4use std::collections::HashMap;
5use std::fmt;
6use std::str::FromStr;
7
8use bitcoin::{Amount, SignedAmount};
9use chrono::DateTime;
10use serde::{Deserialize, Serialize};
11
12use ark::VtxoId;
13
14const MOVEMENT_PENDING: &'static str = "pending";
15const MOVEMENT_FINISHED: &'static str = "finished";
16const MOVEMENT_FAILED: &'static str = "failed";
17const MOVEMENT_CANCELLED: &'static str = "cancelled";
18
19/// Describes an attempted movement of offchain funds within the Bark [Wallet].
20#[derive(Debug, Clone)]
21pub struct Movement {
22 /// The internal ID of the movement.
23 pub id: MovementId,
24 /// The status of the movement.
25 pub status: MovementStatus,
26 /// Contains information about the subsystem that created the movement as well as the purpose
27 /// of the movement.
28 pub subsystem: MovementSubsystem,
29 /// Miscellaneous metadata for the movement. This is JSON containing arbitrary information as
30 /// defined by the subsystem that created the movement.
31 pub metadata: HashMap<String, serde_json::Value>,
32 /// How much the movement was expected to increase or decrease the balance by. This is always an
33 /// estimate and often discounts any applicable fees.
34 pub intended_balance: SignedAmount,
35 /// How much the wallet balance actually changed by. Positive numbers indicate an increase and
36 /// negative numbers indicate a decrease. This is often inclusive of applicable fees, and it
37 /// should be the most accurate number.
38 pub effective_balance: SignedAmount,
39 /// How much the movement cost the user in offchain fees. If there are applicable onchain fees
40 /// they will not be included in this value but, depending on the subsystem, could be found in
41 /// the metadata.
42 pub offchain_fee: Amount,
43 /// A list of external recipients that received funds from this movement.
44 pub sent_to: Vec<MovementDestination>,
45 /// Describes the means by which the wallet received funds in this movement. This could include
46 /// BOLT11 invoices or other useful data.
47 pub received_on: Vec<MovementDestination>,
48 /// A list of [Vtxo] IDs that were consumed by this movement and are either locked or
49 /// unavailable.
50 pub input_vtxos: Vec<VtxoId>,
51 /// A list of IDs for new VTXOs that were produced as a result of this movement. Often change
52 /// VTXOs will be found here for outbound actions unless this was an inbound action.
53 pub output_vtxos: Vec<VtxoId>,
54 /// A list of IDs for VTXOs that were marked for unilateral exit as a result of this movement.
55 /// This could happen for many reasons, e.g. an unsuccessful lightning payment which can't be
56 /// revoked but is about to expire. VTXOs listed here will result in a reduction of spendable
57 /// balance due to the VTXOs being managed by the [crate::Exit] system.
58 pub exited_vtxos: Vec<VtxoId>,
59 /// Contains the times at which the movement was created, updated and completed.
60 pub time: MovementTimestamp,
61}
62
63/// A unique identifier for a movement.
64#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Deserialize, Serialize)]
65pub struct MovementId(u32);
66
67impl MovementId {
68 pub fn new(id: u32) -> Self {
69 Self(id)
70 }
71
72 pub fn inner(&self) -> u32 {
73 self.0
74 }
75}
76
77impl fmt::Display for MovementId {
78 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79 write!(f, "{}", self.0.to_string())
80 }
81}
82
83/// Represents the current status of a [Movement].
84#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
85pub enum MovementStatus {
86 /// The default status of a new [Movement]. Should be treated as in-progress.
87 Pending,
88 /// The [Movement] has completed with changes. Note; this does not necessarily mean the [Movement]
89 /// completed successfully, e.g., VTXOs may be consumed and new ones produced.
90 Finished,
91 /// The [Movement] failed to complete due to an error. This should result in changes in user
92 /// funds.
93 Failed,
94 /// A [Movement] was cancelled, either by the protocol (e.g., lightning payments) or by the
95 /// user.
96 Cancelled,
97}
98
99impl MovementStatus {
100 /// Returns the canonical stable string for this status.
101 ///
102 /// The returned value is intended for persistence and interoperability.
103 /// Use [`MovementStatus::from_str`] to parse it back.
104 pub fn as_str(&self) -> &'static str {
105 match self {
106 Self::Pending => MOVEMENT_PENDING,
107 Self::Finished => MOVEMENT_FINISHED,
108 Self::Failed => MOVEMENT_FAILED,
109 Self::Cancelled => MOVEMENT_CANCELLED,
110 }
111 }
112}
113
114impl FromStr for MovementStatus {
115 type Err = anyhow::Error;
116
117 /// Formats the kind as its canonical string (same as [`MovementStatus::as_str`]).
118 fn from_str(s: &str) -> Result<Self, Self::Err> {
119 match s {
120 MOVEMENT_PENDING => Ok(MovementStatus::Pending),
121 MOVEMENT_FINISHED => Ok(MovementStatus::Finished),
122 MOVEMENT_FAILED => Ok(MovementStatus::Failed),
123 MOVEMENT_CANCELLED => Ok(MovementStatus::Cancelled),
124 _ => bail!("Invalid MovementStatus: {}", s),
125 }
126 }
127}
128
129impl Serialize for MovementStatus {
130 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
131 where
132 S: serde::Serializer,
133 {
134 serializer.serialize_str(self.as_str())
135 }
136}
137
138impl<'de> Deserialize<'de> for MovementStatus {
139 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
140 where
141 D: serde::Deserializer<'de>,
142 {
143 let s = String::deserialize(deserializer)?;
144 MovementStatus::from_str(&s).map_err(serde::de::Error::custom)
145 }
146}
147
148/// Describes a recipient of a movement. This could either be an external recipient in send actions
149/// or it could be the bark wallet itself.
150#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
151pub struct MovementDestination {
152 /// An address, invoice or any other identifier to distinguish the recipient.
153 pub destination: String,
154 /// How many sats the recipient received.
155 pub amount: Amount,
156}
157
158impl MovementDestination {
159 pub fn new(destination: String, amount: Amount) -> Self {
160 Self { destination, amount }
161 }
162}
163
164/// Contains information about the subsystem that created the movement as well as the purpose
165/// of the movement.
166#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
167pub struct MovementSubsystem {
168 /// The name of the subsystem that created and manages the movement.
169 pub name: String,
170 /// The action responsible for registering the movement.
171 pub kind: String,
172}
173
174/// Contains the times at which the movement was created, updated and completed.
175#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
176pub struct MovementTimestamp {
177 /// When the movement was first created.
178 pub created_at: DateTime<chrono::Utc>,
179 /// When the movement was last updated.
180 pub updated_at: DateTime<chrono::Utc>,
181 /// The action responsible for registering the movement.
182 pub completed_at: Option<DateTime<chrono::Utc>>,
183}