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#[derive(Default, Serialize, Deserialize)]
26#[cfg_attr(feature = "utoipa", derive(ToSchema))]
27pub struct HistoryQuery {
28 #[serde(rename = "type")]
32 pub method_type: Option<String>,
33 pub value: Option<String>,
36}
37
38#[derive(Serialize, Deserialize)]
40#[cfg_attr(feature = "utoipa", derive(ToSchema))]
41pub struct FeeEstimateQuery {
42 pub amount_sat: u64,
44}
45
46#[derive(Serialize, Deserialize)]
48#[cfg_attr(feature = "utoipa", derive(ToSchema))]
49pub struct SendOnchainFeeEstimateQuery {
50 pub amount_sat: u64,
52 pub address: String,
54}
55
56#[derive(Serialize, Deserialize)]
58#[cfg_attr(feature = "utoipa", derive(ToSchema))]
59pub struct OffboardAllFeeEstimateQuery {
60 pub address: String,
62}
63
64#[derive(Serialize, Deserialize)]
66#[cfg_attr(feature = "utoipa", derive(ToSchema))]
67pub struct OffboardFeeEstimateRequest {
68 pub address: String,
70 pub vtxos: Vec<String>,
72}
73
74#[derive(Serialize, Deserialize)]
76#[cfg_attr(feature = "utoipa", derive(ToSchema))]
77pub struct FeeEstimateResponse {
78 #[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 #[serde(rename = "fee_sat", with = "bitcoin::amount::serde::as_sat")]
84 #[cfg_attr(feature = "utoipa", schema(value_type = u64))]
85 pub fee: Amount,
86 #[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 #[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#[derive(Serialize, Deserialize)]
109#[cfg_attr(feature = "utoipa", derive(ToSchema))]
110pub struct EmergencyExitFeeEstimateQuery {
111 pub vtxo_ids: Option<String>,
114 pub fee_rate_sat_per_vb: Option<f64>,
118 pub destination: Option<String>,
121 pub fee_margin: Option<f64>,
124}
125
126#[derive(Debug, Clone, Serialize, Deserialize)]
128#[cfg_attr(feature = "utoipa", derive(ToSchema))]
129pub struct EmergencyExitFeeEstimateResponse {
130 #[serde(rename = "exit_broadcast_fee_sat", with = "bitcoin::amount::serde::as_sat")]
134 #[cfg_attr(feature = "utoipa", schema(value_type = u64))]
135 pub exit_broadcast_fee: Amount,
136 #[serde(rename = "claim_fee_sat", with = "bitcoin::amount::serde::as_sat")]
139 #[cfg_attr(feature = "utoipa", schema(value_type = u64))]
140 pub claim_fee: Amount,
141 #[serde(rename = "total_fee_sat", with = "bitcoin::amount::serde::as_sat")]
143 #[cfg_attr(feature = "utoipa", schema(value_type = u64))]
144 pub total_fee: Amount,
145 pub fee_rate_sat_per_vb: f64,
149 pub txs_to_broadcast: usize,
151 #[deprecated(note = "compare `exit_broadcast_fee` against the on-chain balance instead")]
159 #[serde(default)]
160 #[cfg_attr(feature = "utoipa", schema(required = true))]
161 pub fundable: bool,
162}
163
164impl EmergencyExitFeeEstimateResponse {
165 #[allow(deprecated)] pub fn new(e: bark::exit::ExitFeeEstimate, onchain_balance: Option<Amount>) -> Self {
169 EmergencyExitFeeEstimateResponse {
170 total_fee: e.total(),
171 exit_broadcast_fee: e.exit_broadcast_fee,
172 claim_fee: e.claim_fee,
173 fee_rate_sat_per_vb: e.fee_rate.to_sat_per_kwu() as f64 / 250.0,
174 txs_to_broadcast: e.txs_to_broadcast,
175 fundable: onchain_balance.map_or(false, |b| b >= e.exit_broadcast_fee),
176 }
177 }
178}
179
180#[derive(Serialize, Deserialize)]
182#[cfg_attr(feature = "utoipa", derive(ToSchema))]
183pub struct OnchainFeeRatesResponse {
184 pub fast_sat_per_vb: u64,
186 pub regular_sat_per_vb: u64,
188 pub slow_sat_per_vb: u64,
190}
191
192
193#[derive(Serialize, Deserialize)]
194#[cfg_attr(feature = "utoipa", derive(ToSchema))]
195pub struct TipResponse {
196 pub tip_height: u32,
197}
198
199#[derive(Serialize, Deserialize)]
200#[cfg_attr(feature = "utoipa", derive(ToSchema))]
201pub struct MailboxSyncResponse {
202 pub checkpoint: u64,
205}
206
207#[derive(Serialize, Deserialize)]
208#[cfg_attr(feature = "utoipa", derive(ToSchema))]
209pub struct CreateWalletRequest {
210 pub ark_server: Option<String>,
214 #[deprecated(
219 since = "0.2.4",
220 note = "access tokens are not enforced by the server; this field will be removed",
221 )]
222 pub ark_server_access_token: Option<String>,
223 pub chain_source: Option<ChainSourceConfig>,
228 pub mnemonic: Option<String>,
230 pub network: BarkNetwork,
232 pub birthday_height: Option<u32>,
234 #[serde(default)]
237 #[cfg_attr(feature = "utoipa", schema(maximum = 100_000))]
238 pub gap_limit: Option<u32>,
239 #[serde(default)]
241 pub force: bool,
242}
243
244#[derive(Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
246#[serde(rename_all = "kebab-case")]
247#[cfg_attr(feature = "utoipa", derive(ToSchema))]
248pub enum BarkNetwork {
249 Mainnet,
251 Signet,
253 Mutinynet,
255 Regtest,
257}
258
259#[derive(Serialize, Deserialize)]
260#[serde(rename_all = "kebab-case")]
261#[cfg_attr(feature = "utoipa", derive(ToSchema))]
262pub enum ChainSourceConfig {
263 Bitcoind {
265 bitcoind: String,
266 bitcoind_auth: BitcoindAuth,
267 },
268 Esplora {
270 url: String,
271 },
272}
273
274#[derive(Serialize, Deserialize)]
275#[serde(rename_all = "kebab-case")]
276#[cfg_attr(feature = "utoipa", derive(ToSchema))]
277pub enum BitcoindAuth {
278 Cookie {
280 cookie: String,
281 },
282 UserPass {
284 user: String,
285 pass: String,
286 },
287}
288
289#[derive(Serialize, Deserialize)]
290#[cfg_attr(feature = "utoipa", derive(ToSchema))]
291pub struct CreateWalletResponse {
292 pub fingerprint: String,
293}
294
295#[derive(Serialize, Deserialize)]
296#[cfg_attr(feature = "utoipa", derive(ToSchema))]
297pub struct ConnectedResponse {
298 pub connected: bool,
300}
301
302#[derive(Serialize, Deserialize)]
303#[cfg_attr(feature = "utoipa", derive(ToSchema))]
304pub struct MnemonicResponse {
305 pub mnemonic: String,
307}
308
309#[derive(Serialize, Deserialize)]
310#[cfg_attr(feature = "utoipa", derive(ToSchema))]
311pub struct ArkAddressResponse {
312 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
313 pub address: String,
314}
315
316#[derive(Serialize, Deserialize)]
322#[cfg_attr(feature = "utoipa", derive(ToSchema))]
323pub struct Bip321UriRequest {
324 #[serde(default, skip_serializing_if = "Option::is_none")]
329 pub amount_sat: Option<u64>,
330 #[serde(default, skip_serializing_if = "Option::is_none")]
333 pub onchain: Option<bool>,
334 #[serde(default, skip_serializing_if = "Option::is_none")]
336 pub label: Option<String>,
337 #[serde(default, skip_serializing_if = "Option::is_none")]
339 pub message: Option<String>,
340}
341
342#[derive(Serialize, Deserialize)]
344#[cfg_attr(feature = "utoipa", derive(ToSchema))]
345pub struct Bip321UriQuery {
346 pub uppercase: Option<bool>,
352}
353
354#[derive(Serialize, Deserialize)]
360#[cfg_attr(feature = "utoipa", derive(ToSchema))]
361pub struct Bip321UriResponse {
362 #[serde(skip_serializing_if = "Option::is_none")]
364 pub ark: Option<String>,
365 #[serde(skip_serializing_if = "Option::is_none")]
367 pub bolt11: Option<String>,
368 #[serde(skip_serializing_if = "Option::is_none")]
370 pub onchain: Option<String>,
371 pub bip321: String,
373}
374
375#[derive(Serialize, Deserialize)]
380#[cfg_attr(feature = "utoipa", derive(ToSchema))]
381pub struct EncodedVtxoResponse {
382 pub encoded: crate::primitives::EncodedVtxo,
384}
385
386#[derive(Serialize, Deserialize)]
387#[cfg_attr(feature = "utoipa", derive(ToSchema))]
388pub struct VtxosQuery {
389 pub all: Option<bool>,
391}
392
393#[derive(Serialize, Deserialize)]
394#[cfg_attr(feature = "utoipa", derive(ToSchema))]
395pub struct RefreshRequest {
396 pub vtxos: Vec<String>,
401}
402
403#[derive(Serialize, Deserialize)]
404#[cfg_attr(feature = "utoipa", derive(ToSchema))]
405pub struct DelegatedRefreshRequest {
406 pub vtxos: Vec<String>,
411 pub height: Option<u32>,
415}
416
417#[derive(Serialize, Deserialize)]
418#[cfg_attr(feature = "utoipa", derive(ToSchema))]
419pub struct BoardRequest {
420 pub amount_sat: u64,
424}
425
426#[derive(Serialize, Deserialize)]
427#[cfg_attr(feature = "utoipa", derive(ToSchema))]
428pub struct SendRequest {
429 pub destination: String,
431 pub amount_sat: Option<u64>,
435 pub comment: Option<String>,
437 #[serde(default)]
441 pub retry_for_secs: Option<u64>,
442}
443
444#[derive(Serialize, Deserialize)]
445#[cfg_attr(feature = "utoipa", derive(ToSchema))]
446pub struct SendResponse {
447 pub message: String,
449 #[serde(default, skip_serializing_if = "Option::is_none")]
452 #[cfg_attr(feature = "utoipa", schema(value_type = Option<String>))]
453 pub payment_hash: Option<PaymentHash>,
454}
455
456#[derive(Serialize, Deserialize)]
458#[cfg_attr(feature = "utoipa", derive(ToSchema))]
459pub struct SignMessageRequest {
460 pub message: String,
462 pub address: String,
464}
465
466#[derive(Serialize, Deserialize)]
470#[cfg_attr(feature = "utoipa", derive(ToSchema))]
471pub struct VerifyMessageRequest {
472 pub message: String,
474 pub signature: String,
477 pub pubkey: Option<String>,
479 pub address: Option<String>,
481}
482
483#[derive(Serialize, Deserialize)]
484#[cfg_attr(feature = "utoipa", derive(ToSchema))]
485pub struct SendOnchainRequest {
486 pub destination: String,
488 pub amount_sat: u64,
492}
493
494#[derive(Serialize, Deserialize)]
495#[cfg_attr(feature = "utoipa", derive(ToSchema))]
496pub struct OffboardVtxosRequest {
497 pub address: Option<String>,
499 pub vtxos: Vec<String>,
503}
504
505#[derive(Serialize, Deserialize)]
506#[cfg_attr(feature = "utoipa", derive(ToSchema))]
507pub struct OffboardAllRequest {
508 pub address: Option<String>,
510}
511
512#[derive(Serialize, Deserialize)]
513#[cfg_attr(feature = "utoipa", derive(ToSchema))]
514pub struct ImportVtxoRequest {
515 pub vtxos: Vec<String>,
517 #[serde(default)]
520 #[cfg_attr(feature = "utoipa", schema(maximum = 100_000))]
521 pub gap_limit: Option<u32>,
522 #[serde(default)]
527 pub skip_status_check: bool,
528 #[serde(default)]
533 pub allow_partial: bool,
534}
535
536#[derive(Serialize, Deserialize)]
537#[cfg_attr(feature = "utoipa", derive(ToSchema))]
538pub struct LightningInvoiceRequest {
539 pub amount_sat: u64,
543 #[serde(default, skip_serializing_if = "Option::is_none")]
545 pub description: Option<String>,
546 #[serde(default, skip_serializing_if = "Option::is_none")]
550 pub token: Option<String>,
551}
552
553#[derive(Serialize, Deserialize)]
554#[cfg_attr(feature = "utoipa", derive(ToSchema))]
555pub struct LightningInvoiceForAddressRequest {
556 pub amount_sat: u64,
558 pub address: String,
560 #[serde(default, skip_serializing_if = "Option::is_none")]
562 pub description: Option<String>,
563}
564
565#[derive(Serialize, Deserialize)]
566#[cfg_attr(feature = "utoipa", derive(ToSchema))]
567pub struct LightningPayRequest {
568 pub destination: String,
570 pub amount_sat: Option<u64>,
575 pub comment: Option<String>,
577 #[serde(default)]
580 pub retry_for_secs: Option<u64>,
581}
582
583#[derive(Serialize, Deserialize)]
584#[cfg_attr(feature = "utoipa", derive(ToSchema))]
585pub struct LightningPayResponse {
586 pub message: String,
588 #[serde(default, skip_serializing_if = "Option::is_none")]
591 #[cfg_attr(feature = "utoipa", schema(value_type = Option<String>))]
592 pub payment_hash: Option<PaymentHash>,
593}
594
595#[derive(Serialize, Deserialize)]
596#[cfg_attr(feature = "utoipa", derive(ToSchema))]
597pub struct OnchainSendRequest {
598 pub destination: String,
600 pub amount_sat: u64,
602}
603
604#[derive(Serialize, Deserialize)]
605#[cfg_attr(feature = "utoipa", derive(ToSchema))]
606pub struct OnchainSendManyRequest {
607 pub destinations: Vec<String>,
609 pub immediate: Option<bool>,
611}
612
613#[derive(Serialize, Deserialize)]
614#[cfg_attr(feature = "utoipa", derive(ToSchema))]
615pub struct OnchainDrainRequest {
616 pub destination: String,
618}
619
620#[derive(Serialize, Deserialize)]
621#[cfg_attr(feature = "utoipa", derive(ToSchema))]
622pub struct ExitStatusRequest {
623 pub history: Option<bool>,
625 pub transactions: Option<bool>,
627}
628
629#[derive(Serialize, Deserialize)]
630#[cfg_attr(feature = "utoipa", derive(ToSchema))]
631pub struct ExitStartRequest {
632 pub vtxos: Vec<String>,
634}
635
636#[derive(Serialize, Deserialize)]
637#[cfg_attr(feature = "utoipa", derive(ToSchema))]
638pub struct ExitStartResponse {
639 pub message: String,
640}
641
642#[derive(Serialize, Deserialize)]
643#[cfg_attr(feature = "utoipa", derive(ToSchema))]
644pub struct ExitProgressRequest {
645 pub wait: Option<bool>,
647 pub fee_rate: Option<u64>,
649}
650
651#[derive(Serialize, Deserialize)]
652#[cfg_attr(feature = "utoipa", derive(ToSchema))]
653pub struct ExitClaimAllRequest {
654 pub destination: String,
656 pub fee_rate: Option<u64>,
658}
659
660#[derive(Serialize, Deserialize)]
661#[cfg_attr(feature = "utoipa", derive(ToSchema))]
662pub struct ExitClaimVtxosRequest {
663 pub destination: String,
665 pub vtxos: Vec<String>,
667 pub fee_rate: Option<u64>,
669}
670
671#[derive(Serialize, Deserialize)]
672#[cfg_attr(feature = "utoipa", derive(ToSchema))]
673pub struct ExitClaimResponse {
674 pub message: String,
675}
676
677#[derive(Serialize, Deserialize)]
678#[cfg_attr(feature = "utoipa", derive(ToSchema))]
679pub struct ExitCancelResponse {
680 pub message: String,
681}
682
683
684#[derive(Serialize, Deserialize)]
685#[cfg_attr(feature = "utoipa", derive(ToSchema))]
686pub struct VtxoRequestInfo {
687 #[serde(rename = "amount_sat", with = "bitcoin::amount::serde::as_sat")]
688 #[cfg_attr(feature = "utoipa", schema(value_type = u64))]
689 pub amount: Amount,
690 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
691 pub policy_type: VtxoPolicyKind,
692 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
693 pub user_pubkey: PublicKey,
694}
695
696impl<'a> From<&'a ark::VtxoRequest> for VtxoRequestInfo {
697 fn from(v: &'a ark::VtxoRequest) -> Self {
698 Self {
699 amount: v.amount,
700 policy_type: v.policy.policy_type(),
701 user_pubkey: v.policy.user_pubkey(),
702 }
703 }
704}
705
706#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
707#[cfg_attr(feature = "utoipa", derive(ToSchema))]
708pub struct OffboardRequestInfo {
709 pub script_pubkey_hex: String,
711 pub script_pubkey_asm: String,
713 #[serde(rename = "net_amount_sat", with = "bitcoin::amount::serde::as_sat")]
715 #[cfg_attr(feature = "utoipa", schema(value_type = u64))]
716 pub net_amount: Amount,
717 pub deduct_fees_from_gross_amount: bool,
719 #[serde(rename = "fee_rate_kwu")]
721 #[cfg_attr(feature = "utoipa", schema(value_type = u64))]
722 pub fee_rate: FeeRate,
723}
724
725impl<'a> From<&'a OffboardRequest> for OffboardRequestInfo {
726 fn from(v: &'a OffboardRequest) -> Self {
727 Self {
728 script_pubkey_hex: v.script_pubkey.to_hex_string(),
729 script_pubkey_asm: v.script_pubkey.to_asm_string(),
730 net_amount: v.net_amount,
731 deduct_fees_from_gross_amount: v.deduct_fees_from_gross_amount,
732 fee_rate: v.fee_rate,
733 }
734 }
735}
736
737#[derive(Serialize, Deserialize)]
738#[cfg_attr(feature = "utoipa", derive(ToSchema))]
739pub struct RoundParticipationInfo {
740 #[cfg_attr(feature = "utoipa", schema(value_type = Vec<String>))]
741 pub inputs: Vec<VtxoId>,
742 pub outputs: Vec<VtxoRequestInfo>,
743}
744
745impl<'a> From<&'a bark::round::RoundParticipation> for RoundParticipationInfo {
746 fn from(v: &'a bark::round::RoundParticipation) -> Self {
747 Self {
748 inputs: v.inputs.iter().map(|v| v.id()).collect(),
749 outputs: v.outputs.iter().map(Into::into).collect(),
750 }
751 }
752}
753
754#[derive(Serialize, Deserialize)]
756#[cfg_attr(feature = "utoipa", derive(ToSchema))]
757#[serde(rename_all = "kebab-case")]
758pub enum RoundFlowState {
759 DelegatedPending,
761 Pending,
763 Ongoing,
765 AwaitingConfirmations,
767 Failed,
769 Canceled,
771}
772
773impl From<RoundFlowKind> for RoundFlowState {
774 fn from(kind: RoundFlowKind) -> Self {
775 match kind {
776 RoundFlowKind::DelegatedPending => Self::DelegatedPending,
777 RoundFlowKind::Pending => Self::Pending,
778 RoundFlowKind::Ongoing => Self::Ongoing,
779 RoundFlowKind::AwaitingConfirmations => Self::AwaitingConfirmations,
780 RoundFlowKind::Failed => Self::Failed,
781 RoundFlowKind::Canceled => Self::Canceled,
782 }
783 }
784}
785
786#[derive(Serialize, Deserialize)]
787#[cfg_attr(feature = "utoipa", derive(ToSchema))]
788pub struct PendingRoundInfo {
789 pub id: u32,
791 pub status: RoundStatus,
793 pub state: RoundFlowState,
795 pub participation: RoundParticipationInfo,
797 #[cfg_attr(feature = "utoipa", schema(value_type = String, nullable = true))]
798 pub unlock_hash: Option<UnlockHash>,
799 #[serde(default)]
801 pub scheduled_height: Option<u32>,
802 #[cfg_attr(feature = "utoipa", schema(value_type = String, nullable = true))]
804 pub funding_txid: Option<Txid>,
805 pub funding_tx_hex: Option<String>,
806}
807
808impl PendingRoundInfo {
809 pub fn new<G>(
810 state: &bark::persist::models::StoredRoundState<G>,
811 sync_result: anyhow::Result<bark::round::RoundStatus>,
812 ) -> Self {
813 let funding_tx = state.state().funding_tx();
814 Self {
815 id: state.id().0,
816 status: match sync_result {
817 Ok(status) => status.into(),
818 Err(e) => RoundStatus::SyncError {
819 error: format!("{:#}", e),
820 },
821 },
822 state: state.state().flow_kind().into(),
823 participation: state.state().participation().into(),
824 unlock_hash: state.state().unlock_hash(),
825 scheduled_height: state.state().scheduled_height().map(Into::into),
826 funding_txid: funding_tx.map(|t| t.compute_txid()),
827 funding_tx_hex: funding_tx.map(|t| serialize_hex(t)),
828 }
829 }
830
831 pub fn from_state<G>(state: &bark::persist::models::StoredRoundState<G>) -> Self {
834 let status = match state.state().flow_kind() {
835 RoundFlowKind::AwaitingConfirmations => {
836 bark::round::RoundStatus::Unconfirmed {
837 funding_txid: state.state().funding_tx()
838 .expect("finished rounds have a funding tx")
839 .compute_txid(),
840 }
841 },
842 RoundFlowKind::Canceled => bark::round::RoundStatus::Canceled,
843 RoundFlowKind::DelegatedPending
844 | RoundFlowKind::Pending
845 | RoundFlowKind::Ongoing
846 | RoundFlowKind::Failed
847 => bark::round::RoundStatus::Pending,
848 };
849 Self::new(state, Ok(status))
850 }
851}
852
853#[derive(Serialize, Deserialize)]
854#[cfg_attr(feature = "utoipa", derive(ToSchema))]
855pub struct WalletExistsResponse {
856 pub fingerprint: Option<String>,
857}
858
859#[derive(Serialize, Deserialize)]
860#[cfg_attr(feature = "utoipa", derive(ToSchema))]
861pub struct WalletDeleteRequest {
862 pub dangerous: bool,
863 pub fingerprint: String,
864}
865
866#[derive(Serialize, Deserialize)]
867#[cfg_attr(feature = "utoipa", derive(ToSchema))]
868pub struct WalletDeleteResponse {
869 pub deleted: bool,
870 pub fingerprint: Option<String>,
871 pub message: String,
872}