1
2use std::ops::Deref;
3use std::sync::Arc;
4
5use bark::actions::WalletActionId;
6use bitcoin::{Amount, OutPoint, SignedAmount, Transaction, Txid};
7use bitcoin::secp256k1::PublicKey;
8#[cfg(feature = "utoipa")]
9use utoipa::ToSchema;
10
11use ark::{Vtxo, VtxoId};
12use ark::vtxo::{Bare, Full, VtxoPolicyKind};
13use bark::movement::MovementId;
14use bark::vtxo::VtxoState;
15use bitcoin_ext::{BlockDelta, BlockHeight};
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
21#[cfg_attr(feature = "utoipa", derive(ToSchema))]
22pub struct BlockRef {
23 pub height: BlockHeight,
24 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
25 pub hash: bitcoin::BlockHash,
26}
27
28impl From<bitcoin_ext::BlockRef> for BlockRef {
29 fn from(v: bitcoin_ext::BlockRef) -> Self {
30 BlockRef {
31 height: v.height,
32 hash: v.hash,
33 }
34 }
35}
36
37impl From<BlockRef> for bitcoin_ext::BlockRef {
38 fn from(v: BlockRef) -> Self {
39 bitcoin_ext::BlockRef {
40 height: v.height,
41 hash: v.hash,
42 }
43 }
44}
45
46#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
57#[cfg_attr(feature = "utoipa", derive(ToSchema))]
58pub struct UtxoInfo {
59 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
61 pub outpoint: OutPoint,
62 #[serde(rename = "amount_sat", with = "bitcoin::amount::serde::as_sat")]
64 #[cfg_attr(feature = "utoipa", schema(value_type = u64))]
65 pub amount: Amount,
66 pub confirmation_height: Option<u32>,
69}
70
71impl From<bark::UtxoInfo> for UtxoInfo {
72 fn from(v: bark::UtxoInfo) -> Self {
73 UtxoInfo {
74 outpoint: v.outpoint,
75 amount: v.amount,
76 confirmation_height: v.confirmation_height,
77 }
78 }
79}
80
81impl From<bark::onchain::Utxo> for UtxoInfo {
82
83 fn from(v: bark::onchain::Utxo) -> Self {
84 match v {
85 bark::onchain::Utxo::Local(o) => UtxoInfo {
86 outpoint: o.outpoint,
87 amount: o.amount,
88 confirmation_height: o.confirmation_height,
89 },
90 bark::onchain::Utxo::Exit(e) => UtxoInfo {
91 outpoint: e.vtxo.point(),
92 amount: e.vtxo.amount(),
93 confirmation_height: Some(e.height),
94 },
95 }
96 }
97}
98
99#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
104#[cfg_attr(feature = "utoipa", derive(ToSchema))]
105pub struct VtxoInfo {
106 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
108 pub id: VtxoId,
109 #[serde(rename = "amount_sat", with = "bitcoin::amount::serde::as_sat")]
111 #[cfg_attr(feature = "utoipa", schema(value_type = u64))]
112 pub amount: Amount,
113 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
115 pub policy_type: VtxoPolicyKind,
116 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
119 pub user_pubkey: PublicKey,
120 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
123 pub server_pubkey: PublicKey,
124 pub expiry_height: BlockHeight,
128 pub exit_delta: BlockDelta,
131 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
135 pub chain_anchor: OutPoint,
136 pub exit_depth: Option<u16>,
140}
141
142impl<'a> From<&'a Vtxo<Bare>> for VtxoInfo {
143 fn from(v: &'a Vtxo<Bare>) -> VtxoInfo {
144 VtxoInfo {
145 id: v.id(),
146 amount: v.amount(),
147 policy_type: v.policy().policy_type(),
148 user_pubkey: v.user_pubkey(),
149 server_pubkey: v.server_pubkey(),
150 expiry_height: v.expiry_height(),
151 exit_delta: v.exit_delta(),
152 chain_anchor: v.chain_anchor(),
153 exit_depth: None,
154 }
155 }
156}
157
158impl<'a> From<&'a Vtxo<Full>> for VtxoInfo {
159 fn from(v: &'a Vtxo<Full>) -> VtxoInfo {
160 VtxoInfo {
161 id: v.id(),
162 amount: v.amount(),
163 policy_type: v.policy().policy_type(),
164 user_pubkey: v.user_pubkey(),
165 server_pubkey: v.server_pubkey(),
166 expiry_height: v.expiry_height(),
167 exit_delta: v.exit_delta(),
168 chain_anchor: v.chain_anchor(),
169 exit_depth: Some(v.exit_depth()),
170 }
171 }
172}
173
174impl From<Vtxo<Bare>> for VtxoInfo {
175 fn from(v: Vtxo<Bare>) -> VtxoInfo {
176 VtxoInfo::from(&v)
177 }
178}
179
180impl From<Vtxo<Full>> for VtxoInfo {
181 fn from(v: Vtxo<Full>) -> VtxoInfo {
182 VtxoInfo::from(&v)
183 }
184}
185
186#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
188#[cfg_attr(feature = "utoipa", derive(ToSchema))]
189pub struct WalletVtxoInfo {
190 #[serde(flatten)]
192 pub vtxo: VtxoInfo,
193 pub state: VtxoStateInfo,
195}
196
197impl From<bark::WalletVtxo> for WalletVtxoInfo {
198 fn from(v: bark::WalletVtxo) -> Self {
199 WalletVtxoInfo {
200 vtxo: v.vtxo.into(),
201 state: v.state.into(),
202 }
203 }
204}
205
206#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
211#[cfg_attr(feature = "utoipa", derive(ToSchema))]
212pub struct EncodedVtxo(pub String);
213
214impl Deref for WalletVtxoInfo {
215 type Target = VtxoInfo;
216
217 fn deref(&self) -> &Self::Target {
218 &self.vtxo
219 }
220}
221
222#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
224#[cfg_attr(feature = "utoipa", derive(ToSchema))]
225#[serde(tag = "type", rename_all = "kebab-case")]
226pub enum VtxoStateInfo {
227 Spendable,
229 Spent,
231 Locked {
234 #[serde(skip_serializing_if = "Option::is_none")]
236 #[cfg_attr(feature = "utoipa", schema(value_type = u32))]
237 movement_id: Option<MovementId>,
238 #[serde(skip_serializing_if = "Option::is_none")]
240 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
241 action_id: Option<WalletActionId>,
242 },
243}
244
245impl From<VtxoState> for VtxoStateInfo {
246 fn from(state: VtxoState) -> Self {
247 match state {
248 VtxoState::Spendable => VtxoStateInfo::Spendable,
249 VtxoState::Spent => VtxoStateInfo::Spent,
250 VtxoState::Locked { holder } => {
251 match holder {
252 Some(bark::vtxo::VtxoLockHolder::Movement { id }) => {
253 VtxoStateInfo::Locked { movement_id: Some(id), action_id: None }
254 },
255 Some(bark::vtxo::VtxoLockHolder::Action { id }) => {
256 VtxoStateInfo::Locked { movement_id: None, action_id: Some(id) }
257 },
258 None => VtxoStateInfo::Locked { movement_id: None, action_id: None },
259 }
260 },
261 }
262 }
263}
264
265#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
268#[cfg_attr(feature = "utoipa", derive(ToSchema))]
269pub struct TransactionInfo {
270 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
271 pub txid: Txid,
272 #[serde(with = "bitcoin::consensus::serde::With::<bitcoin::consensus::serde::Hex>")]
273 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
274 pub tx: Transaction,
275}
276
277impl From<bark::exit::TransactionInfo> for TransactionInfo {
278 fn from(v: bark::exit::TransactionInfo) -> Self {
279 TransactionInfo { txid: v.txid, tx: v.tx }
280 }
281}
282
283impl From<Transaction> for TransactionInfo {
284 fn from(v: Transaction) -> Self {
285 TransactionInfo { txid: v.compute_txid(), tx: v }
286 }
287}
288
289impl From<Arc<Transaction>> for TransactionInfo {
290 fn from(v: Arc<Transaction>) -> Self {
291 TransactionInfo { txid: v.compute_txid(), tx: (*v).clone() }
292 }
293}
294
295#[derive(Clone, Debug, Deserialize, Serialize)]
300#[cfg_attr(feature = "utoipa", derive(ToSchema))]
301pub struct WalletTxInfo {
302 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
303 pub txid: Txid,
304 #[serde(with = "bitcoin::consensus::serde::With::<bitcoin::consensus::serde::Hex>")]
305 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
306 pub tx: Transaction,
307 #[serde(rename = "onchain_fee_sat", default, with = "bitcoin::amount::serde::as_sat::opt", skip_serializing_if = "Option::is_none")]
311 #[cfg_attr(feature = "utoipa", schema(value_type = Option<u64>))]
312 pub onchain_fees: Option<Amount>,
313 #[serde(rename = "balance_change_sat", with = "bitcoin::amount::serde::as_sat")]
316 #[cfg_attr(feature = "utoipa", schema(value_type = i64))]
317 pub balance_change: SignedAmount,
318 pub confirmation: Option<BlockRef>,
320}
321
322impl From<bark::onchain::WalletTxInfo> for WalletTxInfo {
323 fn from(v: bark::onchain::WalletTxInfo) -> Self {
324 WalletTxInfo {
325 txid: v.txid,
326 tx: (*v.tx).clone(),
327 onchain_fees: v.onchain_fees,
328 balance_change: v.balance_change,
329 confirmation: v.confirmation.map(Into::into),
330 }
331 }
332}