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::{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 #[cfg_attr(feature = "utoipa", schema(value_type = u32))]
24 pub height: BlockHeight,
25 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
26 pub hash: bitcoin::BlockHash,
27}
28
29impl From<bitcoin_ext::BlockRef> for BlockRef {
30 fn from(v: bitcoin_ext::BlockRef) -> Self {
31 BlockRef {
32 height: v.height,
33 hash: v.hash,
34 }
35 }
36}
37
38impl From<BlockRef> for bitcoin_ext::BlockRef {
39 fn from(v: BlockRef) -> Self {
40 bitcoin_ext::BlockRef {
41 height: v.height,
42 hash: v.hash,
43 }
44 }
45}
46
47#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
58#[cfg_attr(feature = "utoipa", derive(ToSchema))]
59pub struct UtxoInfo {
60 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
62 pub outpoint: OutPoint,
63 #[serde(rename = "amount_sat", with = "bitcoin::amount::serde::as_sat")]
65 #[cfg_attr(feature = "utoipa", schema(value_type = u64))]
66 pub amount: Amount,
67 pub confirmation_height: Option<u32>,
70}
71
72impl From<bark::UtxoInfo> for UtxoInfo {
73 fn from(v: bark::UtxoInfo) -> Self {
74 UtxoInfo {
75 outpoint: v.outpoint,
76 amount: v.amount,
77 confirmation_height: v.confirmation_height,
78 }
79 }
80}
81
82impl From<bark::onchain::Utxo> for UtxoInfo {
83
84 fn from(v: bark::onchain::Utxo) -> Self {
85 match v {
86 bark::onchain::Utxo::Local(o) => UtxoInfo {
87 outpoint: o.outpoint,
88 amount: o.amount,
89 confirmation_height: o.confirmation_height.map(|h| h.to_u32()),
90 },
91 bark::onchain::Utxo::Exit(e) => UtxoInfo {
92 outpoint: e.vtxo.point(),
93 amount: e.vtxo.amount(),
94 confirmation_height: Some(e.height.to_u32()),
95 },
96 }
97 }
98}
99
100#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
105#[cfg_attr(feature = "utoipa", derive(ToSchema))]
106pub struct VtxoInfo {
107 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
109 pub id: VtxoId,
110 #[serde(rename = "amount_sat", with = "bitcoin::amount::serde::as_sat")]
112 #[cfg_attr(feature = "utoipa", schema(value_type = u64))]
113 pub amount: Amount,
114 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
116 pub policy_type: VtxoPolicyKind,
117 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
120 pub user_pubkey: PublicKey,
121 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
124 pub server_pubkey: PublicKey,
125 #[cfg_attr(feature = "utoipa", schema(value_type = u32))]
129 pub expiry_height: BlockHeight,
130 #[cfg_attr(feature = "utoipa", schema(value_type = u16))]
133 pub exit_delta: BlockDelta,
134 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
138 pub chain_anchor: OutPoint,
139 pub exit_depth: Option<u16>,
143}
144
145impl<'a> From<&'a Vtxo<Full>> for VtxoInfo {
146 fn from(v: &'a Vtxo<Full>) -> VtxoInfo {
147 VtxoInfo {
148 id: v.id(),
149 amount: v.amount(),
150 policy_type: v.policy().policy_type(),
151 user_pubkey: v.user_pubkey(),
152 server_pubkey: v.server_pubkey(),
153 expiry_height: v.expiry_height(),
154 exit_delta: v.exit_delta(),
155 chain_anchor: v.chain_anchor(),
156 exit_depth: Some(v.exit_depth()),
157 }
158 }
159}
160
161impl From<Vtxo<Full>> for VtxoInfo {
162 fn from(v: Vtxo<Full>) -> VtxoInfo {
163 VtxoInfo::from(&v)
164 }
165}
166
167#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
169#[cfg_attr(feature = "utoipa", derive(ToSchema))]
170pub struct WalletVtxoInfo {
171 #[serde(flatten)]
173 pub vtxo: VtxoInfo,
174 pub state: VtxoStateInfo,
176}
177
178impl<'a> From<&'a bark::WalletVtxo> for WalletVtxoInfo {
179 fn from(v: &'a bark::WalletVtxo) -> Self {
180 WalletVtxoInfo {
181 vtxo: VtxoInfo {
182 id: v.id(),
183 amount: v.amount(),
184 policy_type: v.policy().policy_type(),
185 user_pubkey: v.user_pubkey(),
186 server_pubkey: v.server_pubkey(),
187 expiry_height: v.expiry_height(),
188 exit_delta: v.exit_delta(),
189 chain_anchor: v.chain_anchor(),
190 exit_depth: Some(v.exit_depth),
191 },
192 state: VtxoStateInfo::from(&v.state),
193 }
194 }
195}
196
197#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
202#[cfg_attr(feature = "utoipa", derive(ToSchema))]
203pub struct EncodedVtxo(pub String);
204
205impl Deref for WalletVtxoInfo {
206 type Target = VtxoInfo;
207
208 fn deref(&self) -> &Self::Target {
209 &self.vtxo
210 }
211}
212
213#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
215#[cfg_attr(feature = "utoipa", derive(ToSchema))]
216#[serde(tag = "type", rename_all = "kebab-case")]
217pub enum VtxoStateInfo {
218 Spendable,
220 Spent,
222 Exited,
225 Locked {
228 #[serde(skip_serializing_if = "Option::is_none")]
230 #[cfg_attr(feature = "utoipa", schema(value_type = u32))]
231 movement_id: Option<MovementId>,
232 #[serde(skip_serializing_if = "Option::is_none")]
234 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
235 action_id: Option<WalletActionId>,
236 },
237}
238
239impl<'a> From<&'a VtxoState> for VtxoStateInfo {
240 fn from(state: &'a VtxoState) -> Self {
241 match state {
242 VtxoState::Spendable => VtxoStateInfo::Spendable,
243 VtxoState::Spent => VtxoStateInfo::Spent,
244 VtxoState::Exited => VtxoStateInfo::Exited,
245 VtxoState::Locked { holder } => {
246 match holder {
247 Some(bark::vtxo::VtxoLockHolder::Movement { id }) => {
248 VtxoStateInfo::Locked { movement_id: Some(*id), action_id: None }
249 },
250 Some(bark::vtxo::VtxoLockHolder::Action { id }) => {
251 VtxoStateInfo::Locked { movement_id: None, action_id: Some(id.clone()) }
252 },
253 None => VtxoStateInfo::Locked { movement_id: None, action_id: None },
254 }
255 },
256 }
257 }
258}
259
260#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
263#[cfg_attr(feature = "utoipa", derive(ToSchema))]
264pub struct TransactionInfo {
265 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
266 pub txid: Txid,
267 #[serde(with = "bitcoin::consensus::serde::With::<bitcoin::consensus::serde::Hex>")]
268 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
269 pub tx: Transaction,
270}
271
272impl From<bark::exit::TransactionInfo> for TransactionInfo {
273 fn from(v: bark::exit::TransactionInfo) -> Self {
274 TransactionInfo { txid: v.txid, tx: v.tx }
275 }
276}
277
278impl From<Transaction> for TransactionInfo {
279 fn from(v: Transaction) -> Self {
280 TransactionInfo { txid: v.compute_txid(), tx: v }
281 }
282}
283
284impl From<Arc<Transaction>> for TransactionInfo {
285 fn from(v: Arc<Transaction>) -> Self {
286 TransactionInfo { txid: v.compute_txid(), tx: (*v).clone() }
287 }
288}
289
290#[derive(Clone, Debug, Deserialize, Serialize)]
295#[cfg_attr(feature = "utoipa", derive(ToSchema))]
296pub struct WalletTxInfo {
297 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
298 pub txid: Txid,
299 #[serde(with = "bitcoin::consensus::serde::With::<bitcoin::consensus::serde::Hex>")]
300 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
301 pub tx: Transaction,
302 #[serde(rename = "onchain_fee_sat", default, with = "bitcoin::amount::serde::as_sat::opt", skip_serializing_if = "Option::is_none")]
306 #[cfg_attr(feature = "utoipa", schema(value_type = Option<u64>))]
307 pub onchain_fees: Option<Amount>,
308 #[serde(rename = "balance_change_sat", with = "bitcoin::amount::serde::as_sat")]
311 #[cfg_attr(feature = "utoipa", schema(value_type = i64))]
312 pub balance_change: SignedAmount,
313 pub confirmation: Option<BlockRef>,
315 pub is_cpfp: bool,
319}
320
321impl From<bark::onchain::WalletTxInfo> for WalletTxInfo {
322 fn from(v: bark::onchain::WalletTxInfo) -> Self {
323 WalletTxInfo {
324 txid: v.txid,
325 tx: (*v.tx).clone(),
326 onchain_fees: v.onchain_fees,
327 balance_change: v.balance_change,
328 confirmation: v.confirmation.map(Into::into),
329 is_cpfp: v.is_cpfp,
330 }
331 }
332}