Skip to main content

bark_json/
web.rs

1
2use bitcoin::{Amount, FeeRate, Txid};
3use bitcoin::consensus::encode::serialize_hex;
4use bitcoin::secp256k1::PublicKey;
5use serde::{Deserialize, Serialize};
6
7use ark::VtxoId;
8use ark::lightning::PaymentHash;
9use ark::offboard::OffboardRequest;
10use ark::tree::signed::UnlockHash;
11use ark::vtxo::VtxoPolicyKind;
12use bark::round::RoundFlowKind;
13
14#[cfg(feature = "utoipa")]
15use utoipa::ToSchema;
16
17use crate::cli::RoundStatus;
18
19
20/// Query parameters for filtering wallet history by payment method.
21///
22/// Both fields are optional but must be supplied together: omit both to get the
23/// full history, or provide both to filter by a single payment method. The pair
24/// mirrors the serialized form of a payment method (its `type` tag and `value`).
25#[derive(Default, Serialize, Deserialize)]
26#[cfg_attr(feature = "utoipa", derive(ToSchema))]
27pub struct HistoryQuery {
28	/// The payment method type tag to filter by, e.g. `ark`, `bitcoin`,
29	/// `output-script`, `invoice`, `offer`, `lightning-address`, `lnurl` or
30	/// `custom`. Must be provided together with `value`.
31	#[serde(rename = "type")]
32	pub method_type: Option<String>,
33	/// The payment method value to filter by, e.g. the destination address or
34	/// invoice. Must be provided together with `type`.
35	pub value: Option<String>,
36}
37
38/// Query parameters for fee estimates that only require an amount.
39#[derive(Serialize, Deserialize)]
40#[cfg_attr(feature = "utoipa", derive(ToSchema))]
41pub struct FeeEstimateQuery {
42	/// The amount in satoshis to estimate fees for
43	pub amount_sat: u64,
44}
45
46/// Query parameters for send-onchain fee estimates.
47#[derive(Serialize, Deserialize)]
48#[cfg_attr(feature = "utoipa", derive(ToSchema))]
49pub struct SendOnchainFeeEstimateQuery {
50	/// The amount in satoshis to send
51	pub amount_sat: u64,
52	/// The destination Bitcoin address
53	pub address: String,
54}
55
56/// Query parameters for offboard-all fee estimates.
57#[derive(Serialize, Deserialize)]
58#[cfg_attr(feature = "utoipa", derive(ToSchema))]
59pub struct OffboardAllFeeEstimateQuery {
60	/// The destination Bitcoin address
61	pub address: String,
62}
63
64/// Request body for estimating the fee of offboarding a specific set of VTXOs.
65#[derive(Serialize, Deserialize)]
66#[cfg_attr(feature = "utoipa", derive(ToSchema))]
67pub struct OffboardFeeEstimateRequest {
68	/// The destination Bitcoin address. The fee depends on its script type.
69	pub address: String,
70	/// The IDs of the VTXOs to offboard. Each is offboarded in full.
71	pub vtxos: Vec<String>,
72}
73
74/// A fee estimate for an Ark wallet operation.
75#[derive(Serialize, Deserialize)]
76#[cfg_attr(feature = "utoipa", derive(ToSchema))]
77pub struct FeeEstimateResponse {
78	/// The total amount including fees (in satoshis)
79	#[serde(rename = "gross_amount_sat", with = "bitcoin::amount::serde::as_sat")]
80	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
81	pub gross_amount: Amount,
82	/// The fee portion (in satoshis)
83	#[serde(rename = "fee_sat", with = "bitcoin::amount::serde::as_sat")]
84	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
85	pub fee: Amount,
86	/// The amount excluding fees (in satoshis). For sends, this is the amount
87	/// the recipient receives. For receives, this is the amount the user gets.
88	#[serde(rename = "net_amount_sat", with = "bitcoin::amount::serde::as_sat")]
89	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
90	pub net_amount: Amount,
91	/// The VTXOs that would be spent for this operation
92	#[cfg_attr(feature = "utoipa", schema(value_type = Vec<String>))]
93	pub vtxos_spent: Vec<VtxoId>,
94}
95
96impl From<bark::FeeEstimate> for FeeEstimateResponse {
97	fn from(estimate: bark::FeeEstimate) -> Self {
98		FeeEstimateResponse {
99			gross_amount: estimate.gross_amount,
100			fee: estimate.fee,
101			net_amount: estimate.net_amount,
102			vtxos_spent: estimate.vtxos_spent,
103		}
104	}
105}
106
107/// Query parameters for emergency (unilateral) exit fee estimates.
108#[derive(Serialize, Deserialize)]
109#[cfg_attr(feature = "utoipa", derive(ToSchema))]
110pub struct EmergencyExitFeeEstimateQuery {
111	/// Comma-separated VTXO ids to estimate the exit for. When omitted, every spendable VTXO in
112	/// the wallet is used (i.e. exit the entire wallet).
113	pub vtxo_ids: Option<String>,
114	/// The fee rate to price the estimate at, in sat/vB. Applied to both the broadcast and claim
115	/// legs. When omitted, the broadcast leg uses the current `fast` rate and the claim leg the
116	/// `regular` rate.
117	pub fee_rate_sat_per_vb: Option<u64>,
118	/// The destination address for the claim. Only affects the claim-fee weight; when omitted a
119	/// placeholder of the configured network is used.
120	pub destination: Option<String>,
121}
122
123/// A fee breakdown for unilaterally (emergency) exiting a set of VTXOs.
124#[derive(Debug, Clone, Serialize, Deserialize)]
125#[cfg_attr(feature = "utoipa", derive(ToSchema))]
126pub struct EmergencyExitFeeEstimateResponse {
127	/// The CPFP fees to broadcast every not-yet-confirmed exit transaction (in satoshis). Paid now
128	/// from confirmed on-chain funds.
129	#[serde(rename = "exit_broadcast_fee_sat", with = "bitcoin::amount::serde::as_sat")]
130	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
131	pub exit_broadcast_fee: Amount,
132	/// The fee for the single batched transaction that drains the matured exit outputs (in
133	/// satoshis). Paid later out of the recovered value.
134	#[serde(rename = "claim_fee_sat", with = "bitcoin::amount::serde::as_sat")]
135	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
136	pub claim_fee: Amount,
137	/// The sum of the broadcast and claim fees (in satoshis).
138	#[serde(rename = "total_fee_sat", with = "bitcoin::amount::serde::as_sat")]
139	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
140	pub total_fee: Amount,
141	/// The fee rate the exit-broadcast leg was priced at (sat/vB). Unless an explicit fee rate was
142	/// supplied, the claim leg is priced separately at the chain's `regular` rate.
143	pub fee_rate_sat_per_vb: u64,
144	/// The number of exit transactions that still need to be broadcast and CPFP-bumped.
145	pub txs_to_broadcast: usize,
146	/// Whether the wallet's current on-chain balance covers the full serial exit-broadcast walk.
147	pub fundable: bool,
148}
149
150impl From<bark::exit::ExitFeeEstimate> for EmergencyExitFeeEstimateResponse {
151	fn from(e: bark::exit::ExitFeeEstimate) -> Self {
152		EmergencyExitFeeEstimateResponse {
153			total_fee: e.total(),
154			exit_broadcast_fee: e.exit_broadcast_fee,
155			claim_fee: e.claim_fee,
156			fee_rate_sat_per_vb: e.fee_rate.to_sat_per_vb_ceil(),
157			txs_to_broadcast: e.txs_to_broadcast,
158			fundable: e.fundable,
159		}
160	}
161}
162
163/// Mempool fee rates for on-chain transactions.
164#[derive(Serialize, Deserialize)]
165#[cfg_attr(feature = "utoipa", derive(ToSchema))]
166pub struct OnchainFeeRatesResponse {
167	/// Fee rate targeting ~1 block confirmation (sat/vB)
168	pub fast_sat_per_vb: u64,
169	/// Fee rate targeting ~3 block confirmation (sat/vB)
170	pub regular_sat_per_vb: u64,
171	/// Fee rate targeting ~6 block confirmation (sat/vB)
172	pub slow_sat_per_vb: u64,
173}
174
175
176#[derive(Serialize, Deserialize)]
177#[cfg_attr(feature = "utoipa", derive(ToSchema))]
178pub struct TipResponse {
179	pub tip_height: u32,
180}
181
182#[derive(Serialize, Deserialize)]
183#[cfg_attr(feature = "utoipa", derive(ToSchema))]
184pub struct MailboxSyncResponse {
185	/// The mailbox checkpoint (tip) the wallet has consumed up to after
186	/// the sync. Monotonically non-decreasing across successful syncs.
187	pub checkpoint: u64,
188}
189
190#[derive(Serialize, Deserialize)]
191#[cfg_attr(feature = "utoipa", derive(ToSchema))]
192pub struct CreateWalletRequest {
193	/// The Ark server to use for the wallet.
194	/// Optional when a config.toml already exists in the datadir.
195	pub ark_server: Option<String>,
196	/// An access token for a private Ark server.
197	///
198	/// **Deprecated**: access tokens are no longer enforced by the server;
199	/// this field will be removed in a future release.
200	#[deprecated(
201		since = "0.2.4",
202		note = "access tokens are not enforced by the server; this field will be removed",
203	)]
204	pub ark_server_access_token: Option<String>,
205	/// The chain source to use for the wallet.
206	/// Optional when a config.toml already exists in the datadir.
207	pub chain_source: Option<ChainSourceConfig>,
208	/// The optional mnemonic to use for the wallet
209	pub mnemonic: Option<String>,
210	/// The network to use for the wallet
211	pub network: BarkNetwork,
212	/// An optional birthday height to start syncing the wallet from
213	pub birthday_height: Option<u32>,
214	/// How many consecutive unused key indices a VTXO key scan may cross before
215	/// it concludes the wallet doesn't own a recovered/imported VTXO.
216	#[serde(default)]
217	#[cfg_attr(feature = "utoipa", schema(maximum = 100_000))]
218	pub gap_limit: Option<u32>,
219	/// Proceed even if the datadir contains unexpected files
220	#[serde(default)]
221	pub force: bool,
222}
223
224/// Networks bark can be used on
225#[derive(Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
226#[serde(rename_all = "kebab-case")]
227#[cfg_attr(feature = "utoipa", derive(ToSchema))]
228pub enum BarkNetwork {
229	/// Bitcoin's mainnet
230	Mainnet,
231	/// The official Bitcoin Core signet
232	Signet,
233	/// Mutinynet
234	Mutinynet,
235	/// Any regtest network
236	Regtest,
237}
238
239#[derive(Serialize, Deserialize)]
240#[serde(rename_all = "kebab-case")]
241#[cfg_attr(feature = "utoipa", derive(ToSchema))]
242pub enum ChainSourceConfig {
243	/// Use a bitcoind RPC server
244	Bitcoind {
245		bitcoind: String,
246		bitcoind_auth: BitcoindAuth,
247	},
248	/// Use an Esplora HTTP server
249	Esplora {
250		url: String,
251	},
252}
253
254#[derive(Serialize, Deserialize)]
255#[serde(rename_all = "kebab-case")]
256#[cfg_attr(feature = "utoipa", derive(ToSchema))]
257pub enum BitcoindAuth {
258	/// Use a cookie file for authentication
259	Cookie {
260		cookie: String,
261	},
262	/// Use a username and password for authentication
263	UserPass {
264		user: String,
265		pass: String,
266	},
267}
268
269#[derive(Serialize, Deserialize)]
270#[cfg_attr(feature = "utoipa", derive(ToSchema))]
271pub struct CreateWalletResponse {
272	pub fingerprint: String,
273}
274
275#[derive(Serialize, Deserialize)]
276#[cfg_attr(feature = "utoipa", derive(ToSchema))]
277pub struct ConnectedResponse {
278	/// Whether the wallet is currently connected to its Ark server
279	pub connected: bool,
280}
281
282#[derive(Serialize, Deserialize)]
283#[cfg_attr(feature = "utoipa", derive(ToSchema))]
284pub struct MnemonicResponse {
285	/// The BIP-39 mnemonic phrase backing the wallet.
286	pub mnemonic: String,
287}
288
289#[derive(Serialize, Deserialize)]
290#[cfg_attr(feature = "utoipa", derive(ToSchema))]
291pub struct ArkAddressResponse {
292	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
293	pub address: String,
294}
295
296/// Request to build a BIP 321 unified payment URI.
297///
298/// An Ark address is always included. A BOLT11 invoice is only included when
299/// `amount_sat` is given (an amount is required to create one). An on-chain
300/// address is included only when `onchain` is `true`.
301#[derive(Serialize, Deserialize)]
302#[cfg_attr(feature = "utoipa", derive(ToSchema))]
303pub struct Bip321UriRequest {
304	/// Optional amount (in satoshis) to request. When set, it is embedded in
305	/// the URI and used to create the BOLT11 invoice. Any server-configured
306	/// [LightningReceiveFees](crate::cli::fees::LightningReceiveFees) are
307	/// deducted from the amount the client ultimately receives over Lightning.
308	#[serde(default, skip_serializing_if = "Option::is_none")]
309	pub amount_sat: Option<u64>,
310	/// Whether to include a fresh on-chain address as a payment destination.
311	/// Defaults to `false`.
312	#[serde(default, skip_serializing_if = "Option::is_none")]
313	pub onchain: Option<bool>,
314	/// Optional label describing the payment, recorded in the URI's `label`.
315	#[serde(default, skip_serializing_if = "Option::is_none")]
316	pub label: Option<String>,
317	/// Optional message describing the payment, recorded in the URI's `message`.
318	#[serde(default, skip_serializing_if = "Option::is_none")]
319	pub message: Option<String>,
320}
321
322/// Query parameters for building a BIP 321 URI.
323#[derive(Serialize, Deserialize)]
324#[cfg_attr(feature = "utoipa", derive(ToSchema))]
325pub struct Bip321UriQuery {
326	/// Whether to upper-case the returned `bip321` URI so QR encoders can use
327	/// the compact alphanumeric mode. Defaults to `false`.
328	/// Requesting an upper-case URI fails when it carries case-sensitive data
329	/// (a label or message with lowercase characters, or base58 address) that
330	/// cannot be upper-cased.
331	pub uppercase: Option<bool>,
332}
333
334/// A BIP 321 unified payment URI together with its individual destinations.
335///
336/// The `bip321` field is the combined `bitcoin:` URI; the other fields expose
337/// each generated destination separately for convenience. A field is `null`
338/// when that destination was not requested or could not be produced.
339#[derive(Serialize, Deserialize)]
340#[cfg_attr(feature = "utoipa", derive(ToSchema))]
341pub struct Bip321UriResponse {
342	/// The generated Ark address, if any.
343	#[serde(skip_serializing_if = "Option::is_none")]
344	pub ark: Option<String>,
345	/// The generated BOLT11 invoice, included only when an amount was given.
346	#[serde(skip_serializing_if = "Option::is_none")]
347	pub bolt11: Option<String>,
348	/// The generated on-chain address, included only when `onchain` was set.
349	#[serde(skip_serializing_if = "Option::is_none")]
350	pub onchain: Option<String>,
351	/// The combined BIP 321 `bitcoin:` URI.
352	pub bip321: String,
353}
354
355/// Response for the encoded-VTXO endpoint.
356///
357/// Wraps the hex-encoded VTXO in a named field so clients can easily
358/// extract it.
359#[derive(Serialize, Deserialize)]
360#[cfg_attr(feature = "utoipa", derive(ToSchema))]
361pub struct EncodedVtxoResponse {
362	/// Hex-encoded serialized VTXO.
363	pub encoded: crate::primitives::EncodedVtxo,
364}
365
366#[derive(Serialize, Deserialize)]
367#[cfg_attr(feature = "utoipa", derive(ToSchema))]
368pub struct VtxosQuery {
369	/// Return all VTXOs regardless of their state (including spent ones)
370	pub all: Option<bool>,
371}
372
373#[derive(Serialize, Deserialize)]
374#[cfg_attr(feature = "utoipa", derive(ToSchema))]
375pub struct RefreshRequest {
376	/// List of VTXO IDs to refresh. The sum of the VTXOs being refreshed must be
377	/// >= [P2TR_DUST](bitcoin_ext::P2TR_DUST). Keep in mind that fees set out in
378	/// [RefreshFees](crate::cli::fees::RefreshFees) will be deducted from the newly created VTXO, this
379	/// value must also be >= [P2TR_DUST](bitcoin_ext::P2TR_DUST).
380	pub vtxos: Vec<String>,
381}
382
383#[derive(Serialize, Deserialize)]
384#[cfg_attr(feature = "utoipa", derive(ToSchema))]
385pub struct DelegatedRefreshRequest {
386	/// List of VTXO IDs to refresh. The sum of the VTXOs being refreshed must be
387	/// >= [P2TR_DUST](bitcoin_ext::P2TR_DUST). Keep in mind that fees set out in
388	/// [RefreshFees](crate::cli::fees::RefreshFees) will be deducted from the newly created VTXO, this
389	/// value must also be >= [P2TR_DUST](bitcoin_ext::P2TR_DUST).
390	pub vtxos: Vec<String>,
391	/// Optional block height to schedule the refresh at. When set, the refresh fee is priced at
392	/// that height and the server includes the participation in the first round once the chain
393	/// tip reaches it; when omitted, the participation is eligible for the next round.
394	pub height: Option<u32>,
395}
396
397#[derive(Serialize, Deserialize)]
398#[cfg_attr(feature = "utoipa", derive(ToSchema))]
399pub struct BoardRequest {
400	/// An amount of onchain funds to board (in satoshis). For a board operation to be successful,
401	/// this value, with any server-configured [BoardFees](crate::cli::fees::BoardFees) deducted, must be
402	/// >= [P2TR_DUST](bitcoin_ext::P2TR_DUST).
403	pub amount_sat: u64,
404}
405
406#[derive(Serialize, Deserialize)]
407#[cfg_attr(feature = "utoipa", derive(ToSchema))]
408pub struct SendRequest {
409	/// The destination can be an Ark address, a BOLT11-invoice, LNURL or a lightning address
410	pub destination: String,
411	/// The amount to send (in satoshis). Optional for bolt11 invoices. Depending on the
412	/// `destination`, the wallet must contain this amount plus any fees configured by the server in
413	/// [FeeSchedule](crate::cli::fees::FeeSchedule).
414	pub amount_sat: Option<u64>,
415	/// An optional comment, only supported when paying to lightning addresses
416	pub comment: Option<String>,
417}
418
419#[derive(Serialize, Deserialize)]
420#[cfg_attr(feature = "utoipa", derive(ToSchema))]
421pub struct SendResponse {
422	/// Success message
423	pub message: String,
424	/// The payment hash, when the destination resolved to a lightning
425	/// payment. Can be used to poll the payment status.
426	#[serde(default, skip_serializing_if = "Option::is_none")]
427	#[cfg_attr(feature = "utoipa", schema(value_type = Option<String>))]
428	pub payment_hash: Option<PaymentHash>,
429}
430
431/// Request to sign an arbitrary message with one of the wallet's keys
432#[derive(Serialize, Deserialize)]
433#[cfg_attr(feature = "utoipa", derive(ToSchema))]
434pub struct SignMessageRequest {
435	/// The message to sign
436	pub message: String,
437	/// The Ark address to sign the message with
438	pub address: String,
439}
440
441/// Request to verify a signed message
442///
443/// Exactly one of `pubkey` and `address` must be set.
444#[derive(Serialize, Deserialize)]
445#[cfg_attr(feature = "utoipa", derive(ToSchema))]
446pub struct VerifyMessageRequest {
447	/// The message that was signed
448	pub message: String,
449	/// The BIP-340 Schnorr signature over the message digest
450	/// `SHA256("bark/message" || message)`, in hex
451	pub signature: String,
452	/// The public key to verify the signature against
453	pub pubkey: Option<String>,
454	/// The Ark address whose user public key to verify the signature against
455	pub address: Option<String>,
456}
457
458#[derive(Serialize, Deserialize)]
459#[cfg_attr(feature = "utoipa", derive(ToSchema))]
460pub struct SendOnchainRequest {
461	/// The destination Bitcoin address
462	pub destination: String,
463	/// The amount (in satoshis) to be received by `destination` onchain. Must be
464	/// >= [P2TR_DUST](bitcoin_ext::P2TR_DUST). Server-configured fees laid out in
465	/// [OffboardFees](crate::cli::fees::OffboardFees) will be added on top of this amount.
466	pub amount_sat: u64,
467}
468
469#[derive(Serialize, Deserialize)]
470#[cfg_attr(feature = "utoipa", derive(ToSchema))]
471pub struct OffboardVtxosRequest {
472	/// Optional Bitcoin address to send to. If not provided, uses the onchain wallet's address
473	pub address: Option<String>,
474	/// List of VTXO IDs to offboard. The sum of the VTXOs being refreshed must be
475	/// >= [P2TR_DUST](bitcoin_ext::P2TR_DUST) after the server-configured
476	/// [OffboardFees](crate::cli::fees::OffboardFees) are deducted.
477	pub vtxos: Vec<String>,
478}
479
480#[derive(Serialize, Deserialize)]
481#[cfg_attr(feature = "utoipa", derive(ToSchema))]
482pub struct OffboardAllRequest {
483	/// Optional Bitcoin address to send to. If not provided, uses the onchain wallet's address
484	pub address: Option<String>,
485}
486
487#[derive(Serialize, Deserialize)]
488#[cfg_attr(feature = "utoipa", derive(ToSchema))]
489pub struct ImportVtxoRequest {
490	/// Hex-encoded VTXOs to import
491	pub vtxos: Vec<String>,
492	/// How many consecutive unused key indices to scan for each VTXO's user
493	/// pubkey. Overrides the wallet's configured gap limit.
494	#[serde(default)]
495	#[cfg_attr(feature = "utoipa", schema(maximum = 100_000))]
496	pub gap_limit: Option<u32>,
497	/// Import as spendable without asking the server for each VTXO's state.
498	///
499	/// Use it when you already know it's spendable or when the server can't be reached,
500	/// as it can leave the wallet in an inconsistent state.
501	#[serde(default)]
502	pub skip_status_check: bool,
503	/// Keep the VTXOs that import successfully even when another one in the
504	/// request fails. The response lists the VTXOs that were kept.
505	///
506	/// Without it, a single failure discards the whole request.
507	#[serde(default)]
508	pub allow_partial: bool,
509}
510
511#[derive(Serialize, Deserialize)]
512#[cfg_attr(feature = "utoipa", derive(ToSchema))]
513pub struct LightningInvoiceRequest {
514	/// The amount to create invoice for (in satoshis). This is the amount the payee will pay but
515	/// the final amount received by the client will have any server-configured
516	/// [LightningReceiveFees](crate::cli::fees::LightningReceiveFees) deducted.
517	pub amount_sat: u64,
518	/// Optional description embedded in the invoice as its memo.
519	#[serde(default, skip_serializing_if = "Option::is_none")]
520	pub description: Option<String>,
521	/// Optional lightning receive token for authentication of the claim, if
522	/// the server requires one and there are no existing spendable VTXOs to
523	/// prove ownership of.
524	#[serde(default, skip_serializing_if = "Option::is_none")]
525	pub token: Option<String>,
526}
527
528#[derive(Serialize, Deserialize)]
529#[cfg_attr(feature = "utoipa", derive(ToSchema))]
530pub struct LightningInvoiceForAddressRequest {
531	/// The amount to create invoice for (in satoshis).
532	pub amount_sat: u64,
533	/// Ark address that will receive the claimed VTXO.
534	pub address: String,
535	/// Optional description embedded in the invoice as its memo.
536	#[serde(default, skip_serializing_if = "Option::is_none")]
537	pub description: Option<String>,
538}
539
540#[derive(Serialize, Deserialize)]
541#[cfg_attr(feature = "utoipa", derive(ToSchema))]
542pub struct LightningPayRequest {
543	/// The invoice, offer, or lightning address to pay
544	pub destination: String,
545	/// The amount to send (in satoshis). Optional for bolt11 invoices with amount. This must be
546	/// higher than the minimum fee laid out in server-configured
547	/// [LightningSendFees](crate::cli::fees::LightningSendFees). The wallet must also contain enough
548	/// funds to cover the amount plus any fees.
549	pub amount_sat: Option<u64>,
550	/// An optional comment, only supported when paying to lightning addresses
551	pub comment: Option<String>,
552}
553
554#[derive(Serialize, Deserialize)]
555#[cfg_attr(feature = "utoipa", derive(ToSchema))]
556pub struct LightningPayResponse {
557	/// Success message
558	pub message: String,
559	/// The payment hash of the lightning payment. Can be used to poll the
560	/// payment status.
561	#[serde(default, skip_serializing_if = "Option::is_none")]
562	#[cfg_attr(feature = "utoipa", schema(value_type = Option<String>))]
563	pub payment_hash: Option<PaymentHash>,
564}
565
566#[derive(Serialize, Deserialize)]
567#[cfg_attr(feature = "utoipa", derive(ToSchema))]
568pub struct OnchainSendRequest {
569	/// The destination Bitcoin address
570	pub destination: String,
571	/// The amount to send (in satoshis)
572	pub amount_sat: u64,
573}
574
575#[derive(Serialize, Deserialize)]
576#[cfg_attr(feature = "utoipa", derive(ToSchema))]
577pub struct OnchainSendManyRequest {
578	/// List of destinations in format "address:amount"
579	pub destinations: Vec<String>,
580	/// Sends the transaction immediately instead of waiting
581	pub immediate: Option<bool>,
582}
583
584#[derive(Serialize, Deserialize)]
585#[cfg_attr(feature = "utoipa", derive(ToSchema))]
586pub struct OnchainDrainRequest {
587	/// The destination Bitcoin address
588	pub destination: String,
589}
590
591#[derive(Serialize, Deserialize)]
592#[cfg_attr(feature = "utoipa", derive(ToSchema))]
593pub struct ExitStatusRequest {
594	/// Whether to include the detailed history of the exit process
595	pub history: Option<bool>,
596	/// Whether to include the exit transactions and their CPFP children
597	pub transactions: Option<bool>,
598}
599
600#[derive(Serialize, Deserialize)]
601#[cfg_attr(feature = "utoipa", derive(ToSchema))]
602pub struct ExitStartRequest {
603	/// The ID of VTXOs to unilaterally exit
604	pub vtxos: Vec<String>,
605}
606
607#[derive(Serialize, Deserialize)]
608#[cfg_attr(feature = "utoipa", derive(ToSchema))]
609pub struct ExitStartResponse {
610	pub message: String,
611}
612
613#[derive(Serialize, Deserialize)]
614#[cfg_attr(feature = "utoipa", derive(ToSchema))]
615pub struct ExitProgressRequest {
616	/// Wait until the exit is completed
617	pub wait: Option<bool>,
618	/// Sets the desired fee-rate in sats/kvB to use broadcasting exit transactions
619	pub fee_rate: Option<u64>,
620}
621
622#[derive(Serialize, Deserialize)]
623#[cfg_attr(feature = "utoipa", derive(ToSchema))]
624pub struct ExitClaimAllRequest {
625	/// The destination Bitcoin address
626	pub destination: String,
627	/// Sets the desired fee-rate in sats/kvB to use broadcasting exit transactions
628	pub fee_rate: Option<u64>,
629}
630
631#[derive(Serialize, Deserialize)]
632#[cfg_attr(feature = "utoipa", derive(ToSchema))]
633pub struct ExitClaimVtxosRequest {
634	/// The destination Bitcoin address
635	pub destination: String,
636	/// The ID of an exited VTXO to be claimed
637	pub vtxos: Vec<String>,
638	/// Sets the desired fee-rate in sats/kvB to use broadcasting exit transactions
639	pub fee_rate: Option<u64>,
640}
641
642#[derive(Serialize, Deserialize)]
643#[cfg_attr(feature = "utoipa", derive(ToSchema))]
644pub struct ExitClaimResponse {
645	pub message: String,
646}
647
648#[derive(Serialize, Deserialize)]
649#[cfg_attr(feature = "utoipa", derive(ToSchema))]
650pub struct ExitCancelResponse {
651	pub message: String,
652}
653
654
655#[derive(Serialize, Deserialize)]
656#[cfg_attr(feature = "utoipa", derive(ToSchema))]
657pub struct VtxoRequestInfo {
658	#[serde(rename = "amount_sat", with = "bitcoin::amount::serde::as_sat")]
659	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
660	pub amount: Amount,
661	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
662	pub policy_type: VtxoPolicyKind,
663	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
664	pub user_pubkey: PublicKey,
665}
666
667impl<'a> From<&'a ark::VtxoRequest> for VtxoRequestInfo {
668	fn from(v: &'a ark::VtxoRequest) -> Self {
669		Self {
670			amount: v.amount,
671			policy_type: v.policy.policy_type(),
672			user_pubkey: v.policy.user_pubkey(),
673		}
674	}
675}
676
677#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
678#[cfg_attr(feature = "utoipa", derive(ToSchema))]
679pub struct OffboardRequestInfo {
680	/// hexadecimal representation of the output script
681	pub script_pubkey_hex: String,
682	/// opcode representation of the output script
683	pub script_pubkey_asm: String,
684	/// The target amount in sats.
685	#[serde(rename = "net_amount_sat", with = "bitcoin::amount::serde::as_sat")]
686	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
687	pub net_amount: Amount,
688	/// Determines whether fees should be added onto the given amount or deducted from it.
689	pub deduct_fees_from_gross_amount: bool,
690	/// What fee rate was used when calculating the fee for the offboard.
691	#[serde(rename = "fee_rate_kwu")]
692	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
693	pub fee_rate: FeeRate,
694}
695
696impl<'a> From<&'a OffboardRequest> for OffboardRequestInfo {
697	fn from(v: &'a OffboardRequest) -> Self {
698		Self {
699			script_pubkey_hex: v.script_pubkey.to_hex_string(),
700			script_pubkey_asm: v.script_pubkey.to_asm_string(),
701			net_amount: v.net_amount,
702			deduct_fees_from_gross_amount: v.deduct_fees_from_gross_amount,
703			fee_rate: v.fee_rate,
704		}
705	}
706}
707
708#[derive(Serialize, Deserialize)]
709#[cfg_attr(feature = "utoipa", derive(ToSchema))]
710pub struct RoundParticipationInfo {
711	#[cfg_attr(feature = "utoipa", schema(value_type = Vec<String>))]
712	pub inputs: Vec<VtxoId>,
713	pub outputs: Vec<VtxoRequestInfo>,
714}
715
716impl<'a> From<&'a bark::round::RoundParticipation> for RoundParticipationInfo {
717	fn from(v: &'a bark::round::RoundParticipation) -> Self {
718		Self {
719			inputs: v.inputs.iter().map(|v| v.id()).collect(),
720			outputs: v.outputs.iter().map(Into::into).collect(),
721		}
722	}
723}
724
725/// Lifecycle phase of a round participation.
726#[derive(Serialize, Deserialize)]
727#[cfg_attr(feature = "utoipa", derive(ToSchema))]
728#[serde(rename_all = "kebab-case")]
729pub enum RoundFlowState {
730	/// Delegated participation waiting for its round.
731	DelegatedPending,
732	/// Interactive participation waiting for its round.
733	Pending,
734	/// The interactive part is being played out with the server.
735	Ongoing,
736	/// The round finished and its funding tx is waiting for confirmations.
737	AwaitingConfirmations,
738	/// The participation failed.
739	Failed,
740	/// The user canceled the participation.
741	Canceled,
742}
743
744impl From<RoundFlowKind> for RoundFlowState {
745	fn from(kind: RoundFlowKind) -> Self {
746		match kind {
747			RoundFlowKind::DelegatedPending => Self::DelegatedPending,
748			RoundFlowKind::Pending => Self::Pending,
749			RoundFlowKind::Ongoing => Self::Ongoing,
750			RoundFlowKind::AwaitingConfirmations => Self::AwaitingConfirmations,
751			RoundFlowKind::Failed => Self::Failed,
752			RoundFlowKind::Canceled => Self::Canceled,
753		}
754	}
755}
756
757#[derive(Serialize, Deserialize)]
758#[cfg_attr(feature = "utoipa", derive(ToSchema))]
759pub struct PendingRoundInfo {
760	/// Unique identifier for the round
761	pub id: u32,
762	/// the current status of the round
763	pub status: RoundStatus,
764	/// Lifecycle phase of the participation
765	pub state: RoundFlowState,
766	/// the round participation details
767	pub participation: RoundParticipationInfo,
768	#[cfg_attr(feature = "utoipa", schema(value_type = String, nullable = true))]
769	pub unlock_hash: Option<UnlockHash>,
770	/// The block height a delegated participation is scheduled for, if any
771	#[serde(default)]
772	pub scheduled_height: Option<u32>,
773	/// The round transaction id, if already assigned
774	#[cfg_attr(feature = "utoipa", schema(value_type = String, nullable = true))]
775	pub funding_txid: Option<Txid>,
776	pub funding_tx_hex: Option<String>,
777}
778
779impl PendingRoundInfo {
780	pub fn new<G>(
781		state: &bark::persist::models::StoredRoundState<G>,
782		sync_result: anyhow::Result<bark::round::RoundStatus>,
783	) -> Self {
784		let funding_tx = state.state().funding_tx();
785		Self {
786			id: state.id().0,
787			status: match sync_result {
788				Ok(status) => status.into(),
789				Err(e) => RoundStatus::SyncError {
790					error: format!("{:#}", e),
791				},
792			},
793			state: state.state().flow_kind().into(),
794			participation: state.state().participation().into(),
795			unlock_hash: state.state().unlock_hash(),
796			scheduled_height: state.state().scheduled_height(),
797			funding_txid: funding_tx.map(|t| t.compute_txid()),
798			funding_tx_hex: funding_tx.map(|t| serialize_hex(t)),
799		}
800	}
801
802	/// Like [PendingRoundInfo::new], but without contacting the server: the
803	/// status is derived from the stored state alone.
804	pub fn from_state<G>(state: &bark::persist::models::StoredRoundState<G>) -> Self {
805		let status = match state.state().flow_kind() {
806			RoundFlowKind::AwaitingConfirmations => {
807				bark::round::RoundStatus::Unconfirmed {
808					funding_txid: state.state().funding_tx()
809						.expect("finished rounds have a funding tx")
810						.compute_txid(),
811				}
812			},
813			RoundFlowKind::Canceled => bark::round::RoundStatus::Canceled,
814			RoundFlowKind::DelegatedPending
815				| RoundFlowKind::Pending
816				| RoundFlowKind::Ongoing
817				| RoundFlowKind::Failed
818			=> bark::round::RoundStatus::Pending,
819		};
820		Self::new(state, Ok(status))
821	}
822}
823
824#[derive(Serialize, Deserialize)]
825#[cfg_attr(feature = "utoipa", derive(ToSchema))]
826pub struct WalletExistsResponse {
827	pub fingerprint: Option<String>,
828}
829
830#[derive(Serialize, Deserialize)]
831#[cfg_attr(feature = "utoipa", derive(ToSchema))]
832pub struct WalletDeleteRequest {
833	pub dangerous: bool,
834	pub fingerprint: String,
835}
836
837#[derive(Serialize, Deserialize)]
838#[cfg_attr(feature = "utoipa", derive(ToSchema))]
839pub struct WalletDeleteResponse {
840	pub deleted: bool,
841	pub fingerprint: Option<String>,
842	pub message: String,
843}