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::offboard::OffboardRequest;
9use ark::tree::signed::UnlockHash;
10use ark::vtxo::VtxoPolicyKind;
11
12#[cfg(feature = "utoipa")]
13use utoipa::ToSchema;
14
15use crate::cli::RoundStatus;
16
17
18/// Query parameters for fee estimates that only require an amount.
19#[derive(Serialize, Deserialize)]
20#[cfg_attr(feature = "utoipa", derive(ToSchema))]
21pub struct FeeEstimateQuery {
22	/// The amount in satoshis to estimate fees for
23	pub amount_sat: u64,
24}
25
26/// Query parameters for send-onchain fee estimates.
27#[derive(Serialize, Deserialize)]
28#[cfg_attr(feature = "utoipa", derive(ToSchema))]
29pub struct SendOnchainFeeEstimateQuery {
30	/// The amount in satoshis to send
31	pub amount_sat: u64,
32	/// The destination Bitcoin address
33	pub address: String,
34}
35
36/// Query parameters for offboard-all fee estimates.
37#[derive(Serialize, Deserialize)]
38#[cfg_attr(feature = "utoipa", derive(ToSchema))]
39pub struct OffboardAllFeeEstimateQuery {
40	/// The destination Bitcoin address
41	pub address: String,
42}
43
44/// A fee estimate for an Ark wallet operation.
45#[derive(Serialize, Deserialize)]
46#[cfg_attr(feature = "utoipa", derive(ToSchema))]
47pub struct FeeEstimateResponse {
48	/// The total amount including fees (in satoshis)
49	#[serde(rename = "gross_amount_sat", with = "bitcoin::amount::serde::as_sat")]
50	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
51	pub gross_amount: Amount,
52	/// The fee portion (in satoshis)
53	#[serde(rename = "fee_sat", with = "bitcoin::amount::serde::as_sat")]
54	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
55	pub fee: Amount,
56	/// The amount excluding fees (in satoshis). For sends, this is the amount
57	/// the recipient receives. For receives, this is the amount the user gets.
58	#[serde(rename = "net_amount_sat", with = "bitcoin::amount::serde::as_sat")]
59	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
60	pub net_amount: Amount,
61	/// The VTXOs that would be spent for this operation
62	#[cfg_attr(feature = "utoipa", schema(value_type = Vec<String>))]
63	pub vtxos_spent: Vec<VtxoId>,
64}
65
66impl From<bark::FeeEstimate> for FeeEstimateResponse {
67	fn from(estimate: bark::FeeEstimate) -> Self {
68		FeeEstimateResponse {
69			gross_amount: estimate.gross_amount,
70			fee: estimate.fee,
71			net_amount: estimate.net_amount,
72			vtxos_spent: estimate.vtxos_spent,
73		}
74	}
75}
76
77/// Mempool fee rates for on-chain transactions.
78#[derive(Serialize, Deserialize)]
79#[cfg_attr(feature = "utoipa", derive(ToSchema))]
80pub struct OnchainFeeRatesResponse {
81	/// Fee rate targeting ~1 block confirmation (sat/vB)
82	pub fast_sat_per_vb: u64,
83	/// Fee rate targeting ~3 block confirmation (sat/vB)
84	pub regular_sat_per_vb: u64,
85	/// Fee rate targeting ~6 block confirmation (sat/vB)
86	pub slow_sat_per_vb: u64,
87}
88
89
90#[derive(Serialize, Deserialize)]
91#[cfg_attr(feature = "utoipa", derive(ToSchema))]
92pub struct TipResponse {
93	pub tip_height: u32,
94}
95
96#[derive(Serialize, Deserialize)]
97#[cfg_attr(feature = "utoipa", derive(ToSchema))]
98pub struct MailboxSyncResponse {
99	/// The mailbox checkpoint (tip) the wallet has consumed up to after
100	/// the sync. Monotonically non-decreasing across successful syncs.
101	pub checkpoint: u64,
102}
103
104#[derive(Serialize, Deserialize)]
105#[cfg_attr(feature = "utoipa", derive(ToSchema))]
106pub struct CreateWalletRequest {
107	/// The Ark server to use for the wallet.
108	/// Optional when a config.toml already exists in the datadir.
109	pub ark_server: Option<String>,
110	/// An access token for a private Ark server
111	pub ark_server_access_token: Option<String>,
112	/// The chain source to use for the wallet.
113	/// Optional when a config.toml already exists in the datadir.
114	pub chain_source: Option<ChainSourceConfig>,
115	/// The optional mnemonic to use for the wallet
116	pub mnemonic: Option<String>,
117	/// The network to use for the wallet
118	pub network: BarkNetwork,
119	/// An optional birthday height to start syncing the wallet from
120	pub birthday_height: Option<u32>,
121}
122
123/// Networks bark can be used on
124#[derive(Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
125#[serde(rename_all = "kebab-case")]
126#[cfg_attr(feature = "utoipa", derive(ToSchema))]
127pub enum BarkNetwork {
128	/// Bitcoin's mainnet
129	Mainnet,
130	/// The official Bitcoin Core signet
131	Signet,
132	/// Mutinynet
133	Mutinynet,
134	/// Any regtest network
135	Regtest,
136}
137
138#[derive(Serialize, Deserialize)]
139#[serde(rename_all = "kebab-case")]
140#[cfg_attr(feature = "utoipa", derive(ToSchema))]
141pub enum ChainSourceConfig {
142	/// Use a bitcoind RPC server
143	Bitcoind {
144		bitcoind: String,
145		bitcoind_auth: BitcoindAuth,
146	},
147	/// Use an Esplora HTTP server
148	Esplora {
149		url: String,
150	},
151}
152
153#[derive(Serialize, Deserialize)]
154#[serde(rename_all = "kebab-case")]
155#[cfg_attr(feature = "utoipa", derive(ToSchema))]
156pub enum BitcoindAuth {
157	/// Use a cookie file for authentication
158	Cookie {
159		cookie: String,
160	},
161	/// Use a username and password for authentication
162	UserPass {
163		user: String,
164		pass: String,
165	},
166}
167
168#[derive(Serialize, Deserialize)]
169#[cfg_attr(feature = "utoipa", derive(ToSchema))]
170pub struct CreateWalletResponse {
171	pub fingerprint: String,
172}
173
174#[derive(Serialize, Deserialize)]
175#[cfg_attr(feature = "utoipa", derive(ToSchema))]
176pub struct ConnectedResponse {
177	/// Whether the wallet is currently connected to its Ark server
178	pub connected: bool,
179}
180
181#[derive(Serialize, Deserialize)]
182#[cfg_attr(feature = "utoipa", derive(ToSchema))]
183pub struct ArkAddressResponse {
184	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
185	pub address: String,
186}
187
188/// Response for the encoded-VTXO endpoint.
189///
190/// Wraps the hex-encoded VTXO in a named field so clients can easily
191/// extract it.
192#[derive(Serialize, Deserialize)]
193#[cfg_attr(feature = "utoipa", derive(ToSchema))]
194pub struct EncodedVtxoResponse {
195	/// Hex-encoded serialized VTXO.
196	pub encoded: crate::primitives::EncodedVtxo,
197}
198
199#[derive(Serialize, Deserialize)]
200#[cfg_attr(feature = "utoipa", derive(ToSchema))]
201pub struct VtxosQuery {
202	/// Return all VTXOs regardless of their state (including spent ones)
203	pub all: Option<bool>,
204}
205
206#[derive(Serialize, Deserialize)]
207#[cfg_attr(feature = "utoipa", derive(ToSchema))]
208pub struct RefreshRequest {
209	/// List of VTXO IDs to refresh. The sum of the VTXOs being refreshed must be
210	/// >= [P2TR_DUST](bitcoin_ext::P2TR_DUST). Keep in mind that fees set out in
211	/// [RefreshFees](crate::cli::RefreshFees) will be deducted from the newly created VTXO, this
212	/// value must also be >= [P2TR_DUST](bitcoin_ext::P2TR_DUST).
213	pub vtxos: Vec<String>,
214}
215
216#[derive(Serialize, Deserialize)]
217#[cfg_attr(feature = "utoipa", derive(ToSchema))]
218pub struct BoardRequest {
219	/// An amount of onchain funds to board (in satoshis). For a board operation to be successful,
220	/// this value, with any server-configured [BoardFees](crate::cli::BoardFees) deducted, must be
221	/// >= [P2TR_DUST](bitcoin_ext::P2TR_DUST).
222	pub amount_sat: u64,
223}
224
225#[derive(Serialize, Deserialize)]
226#[cfg_attr(feature = "utoipa", derive(ToSchema))]
227pub struct SendRequest {
228	/// The destination can be an Ark address, a BOLT11-invoice, LNURL or a lightning address
229	pub destination: String,
230	/// The amount to send (in satoshis). Optional for bolt11 invoices. Depending on the
231	/// `destination`, the wallet must contain this amount plus any fees configured by the server in
232	/// [FeeSchedule](crate::cli::FeeSchedule).
233	pub amount_sat: Option<u64>,
234	/// An optional comment, only supported when paying to lightning addresses
235	pub comment: Option<String>,
236}
237
238#[derive(Serialize, Deserialize)]
239#[cfg_attr(feature = "utoipa", derive(ToSchema))]
240pub struct SendResponse {
241	/// Success message
242	pub message: String,
243}
244
245#[derive(Serialize, Deserialize)]
246#[cfg_attr(feature = "utoipa", derive(ToSchema))]
247pub struct SendOnchainRequest {
248	/// The destination Bitcoin address
249	pub destination: String,
250	/// The amount (in satoshis) to be received by `destination` onchain. Must be
251	/// >= [P2TR_DUST](bitcoin_ext::P2TR_DUST). Server-configured fees laid out in
252	/// [OffboardFees](crate::cli::OffboardFees) will be added on top of this amount.
253	pub amount_sat: u64,
254}
255
256#[derive(Serialize, Deserialize)]
257#[cfg_attr(feature = "utoipa", derive(ToSchema))]
258pub struct OffboardVtxosRequest {
259	/// Optional Bitcoin address to send to. If not provided, uses the onchain wallet's address
260	pub address: Option<String>,
261	/// List of VTXO IDs to offboard. The sum of the VTXOs being refreshed must be
262	/// >= [P2TR_DUST](bitcoin_ext::P2TR_DUST) after the server-configured
263	/// [OffboardFees](crate::cli::OffboardFees) are deducted.
264	pub vtxos: Vec<String>,
265}
266
267#[derive(Serialize, Deserialize)]
268#[cfg_attr(feature = "utoipa", derive(ToSchema))]
269pub struct OffboardAllRequest {
270	/// Optional Bitcoin address to send to. If not provided, uses the onchain wallet's address
271	pub address: Option<String>,
272}
273
274#[derive(Serialize, Deserialize)]
275#[cfg_attr(feature = "utoipa", derive(ToSchema))]
276pub struct ImportVtxoRequest {
277	/// Hex-encoded VTXOs to import
278	pub vtxos: Vec<String>,
279}
280
281#[derive(Serialize, Deserialize)]
282#[cfg_attr(feature = "utoipa", derive(ToSchema))]
283pub struct LightningInvoiceRequest {
284	/// The amount to create invoice for (in satoshis). This is the amount the payee will pay but
285	/// the final amount received by the client will have any server-configured
286	/// [LightningReceiveFees](crate::cli::LightningReceiveFees) deducted.
287	pub amount_sat: u64,
288	/// Optional description embedded in the invoice as its memo.
289	#[serde(default, skip_serializing_if = "Option::is_none")]
290	pub description: Option<String>,
291}
292
293#[derive(Serialize, Deserialize)]
294#[cfg_attr(feature = "utoipa", derive(ToSchema))]
295pub struct LightningPayRequest {
296	/// The invoice, offer, or lightning address to pay
297	pub destination: String,
298	/// The amount to send (in satoshis). Optional for bolt11 invoices with amount. This must be
299	/// higher than the minimum fee laid out in server-configured
300	/// [LightningSendFees](crate::cli::LightningSendFees). The wallet must also contain enough
301	/// funds to cover the amount plus any fees.
302	pub amount_sat: Option<u64>,
303	/// An optional comment, only supported when paying to lightning addresses
304	pub comment: Option<String>,
305}
306
307#[derive(Serialize, Deserialize)]
308#[cfg_attr(feature = "utoipa", derive(ToSchema))]
309pub struct LightningPayResponse {
310	/// Success message
311	pub message: String,
312}
313
314#[derive(Serialize, Deserialize)]
315#[cfg_attr(feature = "utoipa", derive(ToSchema))]
316pub struct OnchainSendRequest {
317	/// The destination Bitcoin address
318	pub destination: String,
319	/// The amount to send (in satoshis)
320	pub amount_sat: u64,
321}
322
323#[derive(Serialize, Deserialize)]
324#[cfg_attr(feature = "utoipa", derive(ToSchema))]
325pub struct OnchainSendManyRequest {
326	/// List of destinations in format "address:amount"
327	pub destinations: Vec<String>,
328	/// Sends the transaction immediately instead of waiting
329	pub immediate: Option<bool>,
330}
331
332#[derive(Serialize, Deserialize)]
333#[cfg_attr(feature = "utoipa", derive(ToSchema))]
334pub struct OnchainDrainRequest {
335	/// The destination Bitcoin address
336	pub destination: String,
337}
338
339#[derive(Serialize, Deserialize)]
340#[cfg_attr(feature = "utoipa", derive(ToSchema))]
341pub struct ExitStatusRequest {
342	/// Whether to include the detailed history of the exit process
343	pub history: Option<bool>,
344	/// Whether to include the exit transactions and their CPFP children
345	pub transactions: Option<bool>,
346}
347
348#[derive(Serialize, Deserialize)]
349#[cfg_attr(feature = "utoipa", derive(ToSchema))]
350pub struct ExitStartRequest {
351	/// The ID of VTXOs to unilaterally exit
352	pub vtxos: Vec<String>,
353}
354
355#[derive(Serialize, Deserialize)]
356#[cfg_attr(feature = "utoipa", derive(ToSchema))]
357pub struct ExitStartResponse {
358	pub message: String,
359}
360
361#[derive(Serialize, Deserialize)]
362#[cfg_attr(feature = "utoipa", derive(ToSchema))]
363pub struct ExitProgressRequest {
364	/// Wait until the exit is completed
365	pub wait: Option<bool>,
366	/// Sets the desired fee-rate in sats/kvB to use broadcasting exit transactions
367	pub fee_rate: Option<u64>,
368}
369
370#[derive(Serialize, Deserialize)]
371#[cfg_attr(feature = "utoipa", derive(ToSchema))]
372pub struct ExitClaimAllRequest {
373	/// The destination Bitcoin address
374	pub destination: String,
375	/// Sets the desired fee-rate in sats/kvB to use broadcasting exit transactions
376	pub fee_rate: Option<u64>,
377}
378
379#[derive(Serialize, Deserialize)]
380#[cfg_attr(feature = "utoipa", derive(ToSchema))]
381pub struct ExitClaimVtxosRequest {
382	/// The destination Bitcoin address
383	pub destination: String,
384	/// The ID of an exited VTXO to be claimed
385	pub vtxos: Vec<String>,
386	/// Sets the desired fee-rate in sats/kvB to use broadcasting exit transactions
387	pub fee_rate: Option<u64>,
388}
389
390#[derive(Serialize, Deserialize)]
391#[cfg_attr(feature = "utoipa", derive(ToSchema))]
392pub struct ExitClaimResponse {
393	pub message: String,
394}
395
396
397#[derive(Serialize, Deserialize)]
398#[cfg_attr(feature = "utoipa", derive(ToSchema))]
399pub struct VtxoRequestInfo {
400	#[serde(rename = "amount_sat", with = "bitcoin::amount::serde::as_sat")]
401	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
402	pub amount: Amount,
403	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
404	pub policy_type: VtxoPolicyKind,
405	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
406	pub user_pubkey: PublicKey,
407}
408
409impl<'a> From<&'a ark::VtxoRequest> for VtxoRequestInfo {
410	fn from(v: &'a ark::VtxoRequest) -> Self {
411		Self {
412			amount: v.amount,
413			policy_type: v.policy.policy_type(),
414			user_pubkey: v.policy.user_pubkey(),
415		}
416	}
417}
418
419#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
420#[cfg_attr(feature = "utoipa", derive(ToSchema))]
421pub struct OffboardRequestInfo {
422	/// hexadecimal representation of the output script
423	pub script_pubkey_hex: String,
424	/// opcode representation of the output script
425	pub script_pubkey_asm: String,
426	/// The target amount in sats.
427	#[serde(rename = "net_amount_sat", with = "bitcoin::amount::serde::as_sat")]
428	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
429	pub net_amount: Amount,
430	/// Determines whether fees should be added onto the given amount or deducted from it.
431	pub deduct_fees_from_gross_amount: bool,
432	/// What fee rate was used when calculating the fee for the offboard.
433	#[serde(rename = "fee_rate_kwu")]
434	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
435	pub fee_rate: FeeRate,
436}
437
438impl<'a> From<&'a OffboardRequest> for OffboardRequestInfo {
439	fn from(v: &'a OffboardRequest) -> Self {
440		Self {
441			script_pubkey_hex: v.script_pubkey.to_hex_string(),
442			script_pubkey_asm: v.script_pubkey.to_asm_string(),
443			net_amount: v.net_amount,
444			deduct_fees_from_gross_amount: v.deduct_fees_from_gross_amount,
445			fee_rate: v.fee_rate,
446		}
447	}
448}
449
450#[derive(Serialize, Deserialize)]
451#[cfg_attr(feature = "utoipa", derive(ToSchema))]
452pub struct RoundParticipationInfo {
453	#[cfg_attr(feature = "utoipa", schema(value_type = Vec<String>))]
454	pub inputs: Vec<VtxoId>,
455	pub outputs: Vec<VtxoRequestInfo>,
456}
457
458impl<'a> From<&'a bark::round::RoundParticipation> for RoundParticipationInfo {
459	fn from(v: &'a bark::round::RoundParticipation) -> Self {
460		Self {
461			inputs: v.inputs.iter().map(|v| v.id()).collect(),
462			outputs: v.outputs.iter().map(Into::into).collect(),
463		}
464	}
465}
466
467#[derive(Serialize, Deserialize)]
468#[cfg_attr(feature = "utoipa", derive(ToSchema))]
469pub struct PendingRoundInfo {
470	/// Unique identifier for the round
471	pub id: u32,
472	/// the current status of the round
473	pub status: RoundStatus,
474	/// the round participation details
475	pub participation: RoundParticipationInfo,
476	#[cfg_attr(feature = "utoipa", schema(value_type = String, nullable = true))]
477	pub unlock_hash: Option<UnlockHash>,
478	/// The round transaction id, if already assigned
479	#[cfg_attr(feature = "utoipa", schema(value_type = String, nullable = true))]
480	pub funding_txid: Option<Txid>,
481	pub funding_tx_hex: Option<String>,
482}
483
484impl PendingRoundInfo {
485	pub fn new<'a>(
486		state: &'a bark::persist::models::StoredRoundState,
487		sync_result: anyhow::Result<bark::round::RoundStatus>,
488	) -> Self {
489		let funding_tx = state.state().funding_tx();
490		Self {
491			id: state.id().0,
492			status: match sync_result {
493				Ok(status) => status.into(),
494				Err(e) => RoundStatus::SyncError {
495					error: format!("{:#}", e),
496				},
497			},
498			participation: state.state().participation().into(),
499			unlock_hash: state.state().unlock_hash(),
500			funding_txid: funding_tx.map(|t| t.compute_txid()),
501			funding_tx_hex: funding_tx.map(|t| serialize_hex(t)),
502		}
503	}
504}
505
506#[derive(Serialize, Deserialize)]
507#[cfg_attr(feature = "utoipa", derive(ToSchema))]
508pub struct WalletExistsResponse {
509	pub fingerprint: Option<String>,
510}
511
512#[derive(Serialize, Deserialize)]
513#[cfg_attr(feature = "utoipa", derive(ToSchema))]
514pub struct WalletDeleteRequest {
515	pub dangerous: bool,
516	pub fingerprint: String,
517}
518
519#[derive(Serialize, Deserialize)]
520#[cfg_attr(feature = "utoipa", derive(ToSchema))]
521pub struct WalletDeleteResponse {
522	pub deleted: bool,
523	pub message: String,
524}
525