bark/movement/
mod.rs

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/// Describes an attempted movement of offchain funds within the Bark [Wallet].
21#[derive(Debug, Clone)]
22pub struct Movement {
23	/// The internal ID of the movement.
24	pub id: MovementId,
25	/// The status of the movement.
26	pub status: MovementStatus,
27	/// Contains information about the subsystem that created the movement as well as the purpose
28	/// of the movement.
29	pub subsystem: MovementSubsystem,
30	/// Miscellaneous metadata for the movement. This is JSON containing arbitrary information as
31	/// defined by the subsystem that created the movement.
32	pub metadata: HashMap<String, serde_json::Value>,
33	/// How much the movement was expected to increase or decrease the balance by. This is always an
34	/// estimate and often discounts any applicable fees.
35	pub intended_balance: SignedAmount,
36	/// How much the wallet balance actually changed by. Positive numbers indicate an increase and
37	/// negative numbers indicate a decrease. This is often inclusive of applicable fees, and it
38	/// should be the most accurate number.
39	pub effective_balance: SignedAmount,
40	/// How much the movement cost the user in offchain fees. If there are applicable onchain fees
41	/// they will not be included in this value but, depending on the subsystem, could be found in
42	/// the metadata.
43	pub offchain_fee: Amount,
44	/// A list of external recipients that received funds from this movement.
45	pub sent_to: Vec<MovementDestination>,
46	/// Describes the means by which the wallet received funds in this movement. This could include
47	/// BOLT11 invoices or other useful data.
48	pub received_on: Vec<MovementDestination>,
49	/// A list of [Vtxo] IDs that were consumed by this movement and are either locked or
50	/// unavailable.
51	pub input_vtxos: Vec<VtxoId>,
52	/// A list of IDs for new VTXOs that were produced as a result of this movement. Often change
53	/// VTXOs will be found here for outbound actions unless this was an inbound action.
54	pub output_vtxos: Vec<VtxoId>,
55	/// A list of IDs for VTXOs that were marked for unilateral exit as a result of this movement.
56	/// This could happen for many reasons, e.g. an unsuccessful lightning payment which can't be
57	/// revoked but is about to expire. VTXOs listed here will result in a reduction of spendable
58	/// balance due to the VTXOs being managed by the [crate::Exit] system.
59	pub exited_vtxos: Vec<VtxoId>,
60	/// Contains the times at which the movement was created, updated and completed.
61	pub time: MovementTimestamp,
62}
63
64/// A unique identifier for a movement.
65#[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/// Represents the current status of a [Movement].
87#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
88pub enum MovementStatus {
89	/// The default status of a new [Movement]. Should be treated as in-progress.
90	Pending,
91	/// The [Movement] has completed with changes. Note; this does not necessarily mean the [Movement]
92	/// completed successfully, e.g., VTXOs may be consumed and new ones produced.
93	Finished,
94	/// The [Movement] failed to complete due to an error. This should result in changes in user
95	/// funds.
96	Failed,
97	/// A [Movement] was cancelled, either by the protocol (e.g., lightning payments) or by the
98	/// user.
99	Cancelled,
100}
101
102impl MovementStatus {
103	/// Returns the canonical stable string for this status.
104	///
105	/// The returned value is intended for persistence and interoperability.
106	/// Use [`MovementStatus::from_str`] to parse it back.
107	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	/// Formats the kind as its canonical string (same as [`MovementStatus::as_str`]).
133	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/// Describes a recipient of a movement. This could either be an external recipient in send actions
164/// or it could be the bark wallet itself.
165#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
166pub struct MovementDestination {
167	/// An address, invoice or any other identifier to distinguish the recipient.
168	pub destination: String,
169	/// How many sats the recipient received.
170	pub amount: Amount,
171}
172
173impl MovementDestination {
174	pub fn new(destination: String, amount: Amount) -> Self {
175		Self { destination, amount }
176	}
177}
178
179/// Contains information about the subsystem that created the movement as well as the purpose
180/// of the movement.
181#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
182pub struct MovementSubsystem {
183	/// The name of the subsystem that created and manages the movement.
184	pub name: String,
185	/// The action responsible for registering the movement.
186	pub kind: String,
187}
188
189/// Contains the times at which the movement was created, updated and completed.
190#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
191pub struct MovementTimestamp {
192	/// When the movement was first created.
193	pub created_at: DateTime<chrono::Local>,
194	/// When the movement was last updated.
195	pub updated_at: DateTime<chrono::Local>,
196	/// The action responsible for registering the movement.
197	pub completed_at: Option<DateTime<chrono::Local>>,
198}