Skip to main content

bark_json/
primitives.rs

1
2use std::ops::Deref;
3use std::sync::Arc;
4
5use bitcoin::{Amount, OutPoint, Transaction, Txid};
6use bitcoin::secp256k1::PublicKey;
7#[cfg(feature = "utoipa")]
8use utoipa::ToSchema;
9
10use ark::{Vtxo, VtxoId};
11use ark::vtxo::{Bare, Full, VtxoPolicyKind};
12use bark::movement::MovementId;
13use bark::vtxo::VtxoState;
14use bitcoin_ext::{BlockDelta, BlockHeight};
15
16/// Reference to a block in the blockchain.
17///
18/// Contains the block height and hash. Serializes as an object with `height` and `hash` fields.
19#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
20#[cfg_attr(feature = "utoipa", derive(ToSchema))]
21pub struct BlockRef {
22	pub height: BlockHeight,
23	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
24	pub hash: bitcoin::BlockHash,
25}
26
27impl From<bitcoin_ext::BlockRef> for BlockRef {
28	fn from(v: bitcoin_ext::BlockRef) -> Self {
29		BlockRef {
30			height: v.height,
31			hash: v.hash,
32		}
33	}
34}
35
36impl From<BlockRef> for bitcoin_ext::BlockRef {
37	fn from(v: BlockRef) -> Self {
38		bitcoin_ext::BlockRef {
39			height: v.height,
40			hash: v.hash,
41		}
42	}
43}
44
45/// Struct representing information about an Unspent Transaction Output (UTXO).
46///
47/// This structure provides details about a UTXO, which includes the outpoint (transaction ID and
48/// index), the associated amount in satoshis, and the block height at which the transaction was
49/// confirmed (if available).
50///
51/// # Serde Behavior
52///
53/// * The `amount` field is serialized and deserialized with a custom function from the `bitcoin`
54///   crate that ensures the value is interpreted as satoshis with the name `amount_sat`.
55#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
56#[cfg_attr(feature = "utoipa", derive(ToSchema))]
57pub struct UtxoInfo {
58	/// Contains the reference to the specific transaction output via transaction ID and index.
59	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
60	pub outpoint: OutPoint,
61	/// The value of the UTXO in satoshis.
62	#[serde(rename = "amount_sat", with = "bitcoin::amount::serde::as_sat")]
63	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
64	pub amount: Amount,
65	/// An optional field that specifies the block height at which the transaction was confirmed. If
66	/// the transaction is unconfirmed, this value will be `None`.
67	pub confirmation_height: Option<u32>,
68}
69
70impl From<bark::UtxoInfo> for UtxoInfo {
71	fn from(v: bark::UtxoInfo) -> Self {
72		UtxoInfo {
73			outpoint: v.outpoint,
74			amount: v.amount,
75			confirmation_height: v.confirmation_height,
76		}
77	}
78}
79
80impl From<bark::onchain::Utxo> for UtxoInfo {
81
82	fn from(v: bark::onchain::Utxo) -> Self {
83		match v {
84			bark::onchain::Utxo::Local(o) => UtxoInfo {
85				outpoint: o.outpoint,
86				amount: o.amount,
87				confirmation_height: o.confirmation_height,
88			},
89			bark::onchain::Utxo::Exit(e) => UtxoInfo {
90				outpoint: e.vtxo.point(),
91				amount: e.vtxo.amount(),
92				confirmation_height: Some(e.height),
93			},
94		}
95	}
96}
97
98/// Information about a single VTXO (Virtual Transaction Output).
99///
100/// A VTXO is a chain of off-chain, pre-signed transactions rooted in an
101/// on-chain output. It represents spendable bitcoin on Ark.
102#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
103#[cfg_attr(feature = "utoipa", derive(ToSchema))]
104pub struct VtxoInfo {
105	/// Unique identifier for this VTXO, formatted as `txid:vout`.
106	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
107	pub id: VtxoId,
108	/// The value of this VTXO in sats.
109	#[serde(rename = "amount_sat", with = "bitcoin::amount::serde::as_sat")]
110	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
111	pub amount: Amount,
112	/// The spending policy that governs this VTXO.
113	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
114	pub policy_type: VtxoPolicyKind,
115	/// The owner's public key. Only the holder of the corresponding
116	/// private key can spend this VTXO.
117	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
118	pub user_pubkey: PublicKey,
119	/// The Ark server's public key used to co-sign transactions
120	/// involving this VTXO.
121	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
122	pub server_pubkey: PublicKey,
123	/// The block height at which this VTXO expires. After expiry, the
124	/// server can reclaim the sats. Refresh before expiry to receive
125	/// new VTXOs, or exit to move them on-chain.
126	pub expiry_height: BlockHeight,
127	/// The relative timelock, in blocks, that must elapse before the
128	/// final on-chain claim in an emergency exit.
129	pub exit_delta: BlockDelta,
130	/// The on-chain outpoint that roots this VTXO, formatted as
131	/// `txid:vout`. Typically an output of a round transaction or a
132	/// board transaction.
133	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
134	pub chain_anchor: OutPoint,
135	/// The number of off-chain transactions in this VTXO. Each must
136	/// be broadcast and confirmed on-chain in sequence during an
137	/// emergency exit.
138	pub exit_depth: Option<u16>,
139}
140
141impl<'a> From<&'a Vtxo<Bare>> for VtxoInfo {
142	fn from(v: &'a Vtxo<Bare>) -> VtxoInfo {
143		VtxoInfo {
144			id: v.id(),
145			amount: v.amount(),
146			policy_type: v.policy().policy_type(),
147			user_pubkey: v.user_pubkey(),
148			server_pubkey: v.server_pubkey(),
149			expiry_height: v.expiry_height(),
150			exit_delta: v.exit_delta(),
151			chain_anchor: v.chain_anchor(),
152			exit_depth: None,
153		}
154	}
155}
156
157impl<'a> From<&'a Vtxo<Full>> for VtxoInfo {
158	fn from(v: &'a Vtxo<Full>) -> VtxoInfo {
159		VtxoInfo {
160			id: v.id(),
161			amount: v.amount(),
162			policy_type: v.policy().policy_type(),
163			user_pubkey: v.user_pubkey(),
164			server_pubkey: v.server_pubkey(),
165			expiry_height: v.expiry_height(),
166			exit_delta: v.exit_delta(),
167			chain_anchor: v.chain_anchor(),
168			exit_depth: Some(v.exit_depth()),
169		}
170	}
171}
172
173impl From<Vtxo<Bare>> for VtxoInfo {
174	fn from(v: Vtxo<Bare>) -> VtxoInfo {
175		VtxoInfo::from(&v)
176	}
177}
178
179impl From<Vtxo<Full>> for VtxoInfo {
180	fn from(v: Vtxo<Full>) -> VtxoInfo {
181		VtxoInfo::from(&v)
182	}
183}
184
185/// A VTXO together with its current wallet state.
186#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
187#[cfg_attr(feature = "utoipa", derive(ToSchema))]
188pub struct WalletVtxoInfo {
189	/// The VTXO details.
190	#[serde(flatten)]
191	pub vtxo: VtxoInfo,
192	/// The current state of this VTXO in the wallet.
193	pub state: VtxoStateInfo,
194}
195
196impl From<bark::WalletVtxo> for WalletVtxoInfo {
197	fn from(v: bark::WalletVtxo) -> Self {
198		WalletVtxoInfo {
199			vtxo: v.vtxo.into(),
200			state: v.state.into(),
201		}
202	}
203}
204
205/// Hex-encoded serialized VTXO.
206///
207/// Serializes as a plain hex string. Can be passed to
208/// `POST /wallet/import-vtxo` to re-import this VTXO.
209#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
210#[cfg_attr(feature = "utoipa", derive(ToSchema))]
211pub struct EncodedVtxo(pub String);
212
213impl Deref for WalletVtxoInfo {
214	type Target = VtxoInfo;
215
216	fn deref(&self) -> &Self::Target {
217		&self.vtxo
218	}
219}
220
221/// The current state of a VTXO in the wallet.
222#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
223#[cfg_attr(feature = "utoipa", derive(ToSchema))]
224#[serde(tag = "type", rename_all = "kebab-case")]
225pub enum VtxoStateInfo {
226	/// The VTXO can be spent immediately.
227	Spendable,
228	/// The VTXO has already been spent.
229	Spent,
230	/// The VTXO is locked by an in-progress movement (e.g. a pending
231	/// round or Lightning payment).
232	Locked {
233		/// The movement that locked this VTXO, if any.
234		#[serde(skip_serializing_if = "Option::is_none")]
235		#[cfg_attr(feature = "utoipa", schema(value_type = u32))]
236		movement_id: Option<MovementId>,
237	},
238}
239
240impl From<VtxoState> for VtxoStateInfo {
241	fn from(state: VtxoState) -> Self {
242		match state {
243			VtxoState::Spendable => VtxoStateInfo::Spendable,
244			VtxoState::Spent => VtxoStateInfo::Spent,
245			VtxoState::Locked { movement_id } => VtxoStateInfo::Locked {
246				movement_id,
247			},
248		}
249	}
250}
251
252/// An information struct used to pair the ID of a transaction with the full transaction for ease
253/// of use and readability for the user
254#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
255#[cfg_attr(feature = "utoipa", derive(ToSchema))]
256pub struct TransactionInfo {
257	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
258	pub txid: Txid,
259	#[serde(with = "bitcoin::consensus::serde::With::<bitcoin::consensus::serde::Hex>")]
260	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
261	pub tx: Transaction,
262}
263
264impl From<bark::exit::TransactionInfo> for TransactionInfo {
265	fn from(v: bark::exit::TransactionInfo) -> Self {
266		TransactionInfo { txid: v.txid, tx: v.tx }
267	}
268}
269
270impl From<Transaction> for TransactionInfo {
271	fn from(v: Transaction) -> Self {
272		TransactionInfo { txid: v.compute_txid(), tx: v }
273	}
274}
275
276impl From<Arc<Transaction>> for TransactionInfo {
277	fn from(v: Arc<Transaction>) -> Self {
278		TransactionInfo { txid: v.compute_txid(), tx: (*v).clone() }
279	}
280}