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<u64>,
118 pub destination: Option<String>,
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
125#[cfg_attr(feature = "utoipa", derive(ToSchema))]
126pub struct EmergencyExitFeeEstimateResponse {
127 #[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 #[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 #[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 pub fee_rate_sat_per_vb: u64,
144 pub txs_to_broadcast: usize,
146 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#[derive(Serialize, Deserialize)]
165#[cfg_attr(feature = "utoipa", derive(ToSchema))]
166pub struct OnchainFeeRatesResponse {
167 pub fast_sat_per_vb: u64,
169 pub regular_sat_per_vb: u64,
171 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 pub checkpoint: u64,
188}
189
190#[derive(Serialize, Deserialize)]
191#[cfg_attr(feature = "utoipa", derive(ToSchema))]
192pub struct CreateWalletRequest {
193 pub ark_server: Option<String>,
196 #[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 pub chain_source: Option<ChainSourceConfig>,
208 pub mnemonic: Option<String>,
210 pub network: BarkNetwork,
212 pub birthday_height: Option<u32>,
214 #[serde(default)]
217 #[cfg_attr(feature = "utoipa", schema(maximum = 100_000))]
218 pub gap_limit: Option<u32>,
219 #[serde(default)]
221 pub force: bool,
222}
223
224#[derive(Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
226#[serde(rename_all = "kebab-case")]
227#[cfg_attr(feature = "utoipa", derive(ToSchema))]
228pub enum BarkNetwork {
229 Mainnet,
231 Signet,
233 Mutinynet,
235 Regtest,
237}
238
239#[derive(Serialize, Deserialize)]
240#[serde(rename_all = "kebab-case")]
241#[cfg_attr(feature = "utoipa", derive(ToSchema))]
242pub enum ChainSourceConfig {
243 Bitcoind {
245 bitcoind: String,
246 bitcoind_auth: BitcoindAuth,
247 },
248 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 Cookie {
260 cookie: String,
261 },
262 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 pub connected: bool,
280}
281
282#[derive(Serialize, Deserialize)]
283#[cfg_attr(feature = "utoipa", derive(ToSchema))]
284pub struct MnemonicResponse {
285 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#[derive(Serialize, Deserialize)]
302#[cfg_attr(feature = "utoipa", derive(ToSchema))]
303pub struct Bip321UriRequest {
304 #[serde(default, skip_serializing_if = "Option::is_none")]
309 pub amount_sat: Option<u64>,
310 #[serde(default, skip_serializing_if = "Option::is_none")]
313 pub onchain: Option<bool>,
314 #[serde(default, skip_serializing_if = "Option::is_none")]
316 pub label: Option<String>,
317 #[serde(default, skip_serializing_if = "Option::is_none")]
319 pub message: Option<String>,
320}
321
322#[derive(Serialize, Deserialize)]
324#[cfg_attr(feature = "utoipa", derive(ToSchema))]
325pub struct Bip321UriQuery {
326 pub uppercase: Option<bool>,
332}
333
334#[derive(Serialize, Deserialize)]
340#[cfg_attr(feature = "utoipa", derive(ToSchema))]
341pub struct Bip321UriResponse {
342 #[serde(skip_serializing_if = "Option::is_none")]
344 pub ark: Option<String>,
345 #[serde(skip_serializing_if = "Option::is_none")]
347 pub bolt11: Option<String>,
348 #[serde(skip_serializing_if = "Option::is_none")]
350 pub onchain: Option<String>,
351 pub bip321: String,
353}
354
355#[derive(Serialize, Deserialize)]
360#[cfg_attr(feature = "utoipa", derive(ToSchema))]
361pub struct EncodedVtxoResponse {
362 pub encoded: crate::primitives::EncodedVtxo,
364}
365
366#[derive(Serialize, Deserialize)]
367#[cfg_attr(feature = "utoipa", derive(ToSchema))]
368pub struct VtxosQuery {
369 pub all: Option<bool>,
371}
372
373#[derive(Serialize, Deserialize)]
374#[cfg_attr(feature = "utoipa", derive(ToSchema))]
375pub struct RefreshRequest {
376 pub vtxos: Vec<String>,
381}
382
383#[derive(Serialize, Deserialize)]
384#[cfg_attr(feature = "utoipa", derive(ToSchema))]
385pub struct DelegatedRefreshRequest {
386 pub vtxos: Vec<String>,
391 pub height: Option<u32>,
395}
396
397#[derive(Serialize, Deserialize)]
398#[cfg_attr(feature = "utoipa", derive(ToSchema))]
399pub struct BoardRequest {
400 pub amount_sat: u64,
404}
405
406#[derive(Serialize, Deserialize)]
407#[cfg_attr(feature = "utoipa", derive(ToSchema))]
408pub struct SendRequest {
409 pub destination: String,
411 pub amount_sat: Option<u64>,
415 pub comment: Option<String>,
417}
418
419#[derive(Serialize, Deserialize)]
420#[cfg_attr(feature = "utoipa", derive(ToSchema))]
421pub struct SendResponse {
422 pub message: String,
424 #[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#[derive(Serialize, Deserialize)]
433#[cfg_attr(feature = "utoipa", derive(ToSchema))]
434pub struct SignMessageRequest {
435 pub message: String,
437 pub address: String,
439}
440
441#[derive(Serialize, Deserialize)]
445#[cfg_attr(feature = "utoipa", derive(ToSchema))]
446pub struct VerifyMessageRequest {
447 pub message: String,
449 pub signature: String,
452 pub pubkey: Option<String>,
454 pub address: Option<String>,
456}
457
458#[derive(Serialize, Deserialize)]
459#[cfg_attr(feature = "utoipa", derive(ToSchema))]
460pub struct SendOnchainRequest {
461 pub destination: String,
463 pub amount_sat: u64,
467}
468
469#[derive(Serialize, Deserialize)]
470#[cfg_attr(feature = "utoipa", derive(ToSchema))]
471pub struct OffboardVtxosRequest {
472 pub address: Option<String>,
474 pub vtxos: Vec<String>,
478}
479
480#[derive(Serialize, Deserialize)]
481#[cfg_attr(feature = "utoipa", derive(ToSchema))]
482pub struct OffboardAllRequest {
483 pub address: Option<String>,
485}
486
487#[derive(Serialize, Deserialize)]
488#[cfg_attr(feature = "utoipa", derive(ToSchema))]
489pub struct ImportVtxoRequest {
490 pub vtxos: Vec<String>,
492 #[serde(default)]
495 #[cfg_attr(feature = "utoipa", schema(maximum = 100_000))]
496 pub gap_limit: Option<u32>,
497 #[serde(default)]
502 pub skip_status_check: bool,
503 #[serde(default)]
508 pub allow_partial: bool,
509}
510
511#[derive(Serialize, Deserialize)]
512#[cfg_attr(feature = "utoipa", derive(ToSchema))]
513pub struct LightningInvoiceRequest {
514 pub amount_sat: u64,
518 #[serde(default, skip_serializing_if = "Option::is_none")]
520 pub description: Option<String>,
521 #[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 pub amount_sat: u64,
533 pub address: String,
535 #[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 pub destination: String,
545 pub amount_sat: Option<u64>,
550 pub comment: Option<String>,
552}
553
554#[derive(Serialize, Deserialize)]
555#[cfg_attr(feature = "utoipa", derive(ToSchema))]
556pub struct LightningPayResponse {
557 pub message: String,
559 #[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 pub destination: String,
571 pub amount_sat: u64,
573}
574
575#[derive(Serialize, Deserialize)]
576#[cfg_attr(feature = "utoipa", derive(ToSchema))]
577pub struct OnchainSendManyRequest {
578 pub destinations: Vec<String>,
580 pub immediate: Option<bool>,
582}
583
584#[derive(Serialize, Deserialize)]
585#[cfg_attr(feature = "utoipa", derive(ToSchema))]
586pub struct OnchainDrainRequest {
587 pub destination: String,
589}
590
591#[derive(Serialize, Deserialize)]
592#[cfg_attr(feature = "utoipa", derive(ToSchema))]
593pub struct ExitStatusRequest {
594 pub history: Option<bool>,
596 pub transactions: Option<bool>,
598}
599
600#[derive(Serialize, Deserialize)]
601#[cfg_attr(feature = "utoipa", derive(ToSchema))]
602pub struct ExitStartRequest {
603 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 pub wait: Option<bool>,
618 pub fee_rate: Option<u64>,
620}
621
622#[derive(Serialize, Deserialize)]
623#[cfg_attr(feature = "utoipa", derive(ToSchema))]
624pub struct ExitClaimAllRequest {
625 pub destination: String,
627 pub fee_rate: Option<u64>,
629}
630
631#[derive(Serialize, Deserialize)]
632#[cfg_attr(feature = "utoipa", derive(ToSchema))]
633pub struct ExitClaimVtxosRequest {
634 pub destination: String,
636 pub vtxos: Vec<String>,
638 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 pub script_pubkey_hex: String,
682 pub script_pubkey_asm: String,
684 #[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 pub deduct_fees_from_gross_amount: bool,
690 #[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#[derive(Serialize, Deserialize)]
727#[cfg_attr(feature = "utoipa", derive(ToSchema))]
728#[serde(rename_all = "kebab-case")]
729pub enum RoundFlowState {
730 DelegatedPending,
732 Pending,
734 Ongoing,
736 AwaitingConfirmations,
738 Failed,
740 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 pub id: u32,
762 pub status: RoundStatus,
764 pub state: RoundFlowState,
766 pub participation: RoundParticipationInfo,
768 #[cfg_attr(feature = "utoipa", schema(value_type = String, nullable = true))]
769 pub unlock_hash: Option<UnlockHash>,
770 #[serde(default)]
772 pub scheduled_height: Option<u32>,
773 #[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 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}