bark/movement/
mod.rs

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/// Describes an attempted movement of offchain funds within the [Wallet](crate::Wallet).
29#[derive(Debug, Clone)]
30pub struct Movement {
31	/// The internal ID of the movement.
32	pub id: MovementId,
33	/// The status of the movement.
34	pub status: MovementStatus,
35	/// Contains information about the subsystem that created the movement as well as the purpose
36	/// of the movement.
37	pub subsystem: MovementSubsystem,
38	/// Miscellaneous metadata for the movement. This is JSON containing arbitrary information as
39	/// defined by the subsystem that created the movement.
40	pub metadata: HashMap<String, serde_json::Value>,
41	/// How much the movement was expected to increase or decrease the balance by. This is always an
42	/// estimate and often discounts any applicable fees.
43	pub intended_balance: SignedAmount,
44	/// How much the wallet balance actually changed by. Positive numbers indicate an increase and
45	/// negative numbers indicate a decrease. This is often inclusive of applicable fees, and it
46	/// should be the most accurate number.
47	pub effective_balance: SignedAmount,
48	/// How much the movement cost the user in offchain fees. If there are applicable onchain fees
49	/// they will not be included in this value but, depending on the subsystem, could be found in
50	/// the metadata.
51	pub offchain_fee: Amount,
52	/// A list of external recipients that received funds from this movement.
53	pub sent_to: Vec<MovementDestination>,
54	/// Describes the means by which the wallet received funds in this movement. This could include
55	/// BOLT11 invoices or other useful data.
56	pub received_on: Vec<MovementDestination>,
57	/// A list of [Vtxo](ark::Vtxo) IDs that were consumed by this movement and are either locked or
58	/// unavailable.
59	pub input_vtxos: Vec<VtxoId>,
60	/// A list of IDs for new VTXOs that were produced as a result of this movement. Often change
61	/// VTXOs will be found here for outbound actions unless this was an inbound action.
62	pub output_vtxos: Vec<VtxoId>,
63	/// A list of IDs for VTXOs that were marked for unilateral exit as a result of this movement.
64	/// This could happen for many reasons, e.g. an unsuccessful lightning payment which can't be
65	/// revoked but is about to expire. VTXOs listed here will result in a reduction of spendable
66	/// balance due to the VTXOs being managed by the [crate::Exit] system.
67	pub exited_vtxos: Vec<VtxoId>,
68	/// Contains the times at which the movement was created, updated and completed.
69	pub time: MovementTimestamp,
70}
71
72/// A unique identifier for a movement.
73#[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/// Represents the current status of a [Movement]. It's important to note that each status can
95/// result in fund changes. As an example, a lightning payment could fail but this will still result
96/// in a change of VTXOs. You can't assume that [MovementStatus::Failed] means that user funds
97/// didn't change.
98#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
99pub enum MovementStatus {
100	/// The default status of a new [Movement]. Should be treated as in-progress.
101	Pending,
102	/// The [Movement] has completed with changes. Note; this does not necessarily mean the [Movement]
103	/// completed successfully, e.g., VTXOs may be consumed and new ones produced.
104	Successful,
105	/// The [Movement] failed to complete due to an error. This should result in changes in user
106	/// funds.
107	Failed,
108	/// A [Movement] was canceled, either by the protocol (e.g., lightning payments) or by the
109	/// user.
110	Canceled,
111}
112
113impl MovementStatus {
114	/// Returns the canonical stable string for this status.
115	///
116	/// The returned value is intended for persistence and interoperability.
117	/// Use [`MovementStatus::from_str`] to parse it back.
118	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	/// Formats the kind as its canonical string (same as [`MovementStatus::as_str`]).
144	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/// Describes a recipient of a movement. This could either be an external recipient in send actions
175/// or it could be the bark wallet itself.
176#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
177pub struct MovementDestination {
178	/// An address, invoice or any other identifier to distinguish the recipient.
179	pub destination: PaymentMethod,
180	/// How many sats the recipient received.
181	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/// Contains information about the subsystem that created the movement as well as the purpose
215/// of the movement.
216#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
217pub struct MovementSubsystem {
218	/// The name of the subsystem that created and manages the movement.
219	pub name: String,
220	/// The action responsible for registering the movement.
221	pub kind: String,
222}
223
224/// Contains the times at which the movement was created, updated and completed.
225#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
226pub struct MovementTimestamp {
227	/// When the movement was first created.
228	pub created_at: DateTime<chrono::Local>,
229	/// When the movement was last updated.
230	pub updated_at: DateTime<chrono::Local>,
231	/// The action responsible for registering the movement.
232	pub completed_at: Option<DateTime<chrono::Local>>,
233}