bark_json/
cli.rs

1
2use std::borrow::Borrow;
3use std::time::Duration;
4
5use bitcoin::secp256k1::PublicKey;
6use bitcoin::{Amount, FeeRate, Txid, SignedAmount};
7use chrono::DateTime;
8#[cfg(feature = "utoipa")]
9use utoipa::ToSchema;
10
11use ark::lightning::{PaymentHash, Preimage};
12use ark::VtxoId;
13use bark::movement::{MovementId, MovementStatus};
14use bitcoin_ext::{BlockDelta, BlockHeight};
15
16use crate::exit::error::ExitError;
17use crate::exit::package::ExitTransactionPackage;
18use crate::exit::ExitState;
19use crate::primitives::{VtxoInfo, WalletVtxoInfo};
20use crate::serde_utils;
21
22#[derive(Debug, Clone, Deserialize, Serialize)]
23#[cfg_attr(feature = "utoipa", derive(ToSchema))]
24pub struct ArkInfo {
25	/// The bitcoin network the server operates on
26	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
27	pub network: bitcoin::Network,
28	/// The Ark server pubkey
29	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
30	pub server_pubkey: PublicKey,
31	/// The interval between each round
32	#[serde(with = "serde_utils::duration")]
33	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
34	pub round_interval: Duration,
35	/// Number of nonces per round
36	pub nb_round_nonces: usize,
37	/// Delta between exit confirmation and coins becoming spendable
38	pub vtxo_exit_delta: BlockDelta,
39	/// Expiration delta of the VTXO
40	pub vtxo_expiry_delta: BlockDelta,
41	/// The number of blocks after which an HTLC-send VTXO expires once granted.
42	pub htlc_send_expiry_delta: BlockDelta,
43	/// The number of blocks to keep between Lightning and Ark HTLCs expiries
44	pub htlc_expiry_delta: BlockDelta,
45	/// Maximum amount of a VTXO
46	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
47	pub max_vtxo_amount: Option<Amount>,
48	/// Maximum number of OOR transition after VTXO tree leaf
49	pub max_arkoor_depth: u16,
50	/// The number of confirmations required to register a board vtxo
51	pub required_board_confirmations: usize,
52	/// Maximum CLTV delta server will allow clients to request an
53	/// invoice generation with.
54	pub max_user_invoice_cltv_delta: u16,
55	/// Minimum amount for a board the server will cosign
56	#[serde(rename = "min_board_amount_sat", with = "bitcoin::amount::serde::as_sat")]
57	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
58	pub min_board_amount: Amount,
59	/// offboard feerate in sat per kvb
60	pub offboard_feerate_sat_per_kvb: u64,
61	/// Indicates whether the Ark server requires clients to either
62	/// provide a VTXO ownership proof, or a lightning receive token
63	/// when preparing a lightning claim.
64	pub ln_receive_anti_dos_required: bool,
65}
66
67impl<T: Borrow<ark::ArkInfo>> From<T> for ArkInfo {
68	fn from(v: T) -> Self {
69		let v = v.borrow();
70	    ArkInfo {
71			network: v.network,
72			server_pubkey: v.server_pubkey,
73			round_interval: v.round_interval,
74			nb_round_nonces: v.nb_round_nonces,
75			vtxo_exit_delta: v.vtxo_exit_delta,
76			vtxo_expiry_delta: v.vtxo_expiry_delta,
77			htlc_send_expiry_delta: v.htlc_send_expiry_delta,
78			htlc_expiry_delta: v.htlc_expiry_delta,
79			max_vtxo_amount: v.max_vtxo_amount,
80			max_arkoor_depth: v.max_arkoor_depth,
81			required_board_confirmations: v.required_board_confirmations,
82			max_user_invoice_cltv_delta: v.max_user_invoice_cltv_delta,
83			min_board_amount: v.min_board_amount,
84			offboard_feerate_sat_per_kvb: v.offboard_feerate.to_sat_per_kwu() * 4,
85			ln_receive_anti_dos_required: v.ln_receive_anti_dos_required,
86		}
87	}
88}
89
90#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
91#[cfg_attr(feature = "utoipa", derive(ToSchema))]
92pub struct LightningReceiveBalance {
93	#[serde(rename = "total_sat", with = "bitcoin::amount::serde::as_sat")]
94	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
95	pub total: Amount,
96	#[serde(rename = "claimable_sat", with = "bitcoin::amount::serde::as_sat")]
97	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
98	pub claimable: Amount,
99}
100
101impl From<bark::LightningReceiveBalance> for LightningReceiveBalance {
102	fn from(v: bark::LightningReceiveBalance) -> Self {
103		LightningReceiveBalance {
104			total: v.total,
105			claimable: v.claimable,
106		}
107	}
108}
109
110#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
111#[cfg_attr(feature = "utoipa", derive(ToSchema))]
112pub struct Balance {
113	#[serde(rename = "spendable_sat", with = "bitcoin::amount::serde::as_sat")]
114	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
115	pub spendable: Amount,
116	#[serde(rename = "pending_lightning_send_sat", with = "bitcoin::amount::serde::as_sat")]
117	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
118	pub pending_lightning_send: Amount,
119	pub pending_lightning_receive: LightningReceiveBalance,
120	#[serde(rename = "pending_in_round_sat", with = "bitcoin::amount::serde::as_sat")]
121	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
122	pub pending_in_round: Amount,
123	#[serde(rename = "pending_board_sat", with = "bitcoin::amount::serde::as_sat")]
124	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
125	pub pending_board: Amount,
126	#[serde(
127		default,
128		rename = "pending_exit_sat",
129		with = "bitcoin::amount::serde::as_sat::opt",
130		skip_serializing_if = "Option::is_none",
131	)]
132	#[cfg_attr(feature = "utoipa", schema(value_type = u64, nullable=true))]
133	pub pending_exit: Option<Amount>,
134}
135
136impl From<bark::Balance> for Balance {
137	fn from(v: bark::Balance) -> Self {
138		Balance {
139			spendable: v.spendable,
140			pending_in_round: v.pending_in_round,
141			pending_lightning_send: v.pending_lightning_send,
142			pending_lightning_receive: v.pending_lightning_receive.into(),
143			pending_exit: v.pending_exit,
144			pending_board: v.pending_board,
145		}
146	}
147}
148
149#[derive(Debug, Clone, Deserialize, Serialize)]
150#[cfg_attr(feature = "utoipa", derive(ToSchema))]
151pub struct Config {
152	/// Ark server address
153	pub ark: String,
154	/// Bitcoin Core RPC address to use for syncing
155	pub bitcoind: Option<String>,
156	/// Cookie to use for RPC authentication
157	pub bitcoind_cookie: Option<String>,
158	/// Username to use for RPC authentication
159	pub bitcoind_user: Option<String>,
160	/// password to use for RPC authentication
161	pub bitcoind_pass: Option<String>,
162	/// The Esplora REST API address to use for syncing
163	pub esplora: Option<String>,
164	/// How many blocks before VTXO expiration before preemptively refreshing them
165	pub vtxo_refresh_expiry_threshold: BlockHeight,
166	#[serde(rename = "fallback_fee_rate_kvb", with = "serde_utils::fee_rate_sats_per_kvb")]
167	#[cfg_attr(feature = "utoipa", schema(value_type = u64, nullable = true))]
168	pub fallback_fee_rate: Option<FeeRate>,
169}
170
171#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
172#[cfg_attr(feature = "utoipa", derive(ToSchema))]
173pub struct ExitProgressResponse {
174	/// Status of each pending exit transaction
175	pub exits: Vec<ExitProgressStatus>,
176	/// Whether all transactions have been confirmed
177	pub done: bool,
178	/// Block height at which all exit outputs will be spendable
179	pub claimable_height: Option<u32>,
180}
181
182#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
183#[cfg_attr(feature = "utoipa", derive(ToSchema))]
184pub struct ExitProgressStatus {
185	/// The ID of the VTXO that is being unilaterally exited
186	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
187	pub vtxo_id: VtxoId,
188	/// The current state of the exit transaction
189	pub state: ExitState,
190	/// Any error that occurred during the exit process
191	#[serde(default, skip_serializing_if = "Option::is_none")]
192	pub error: Option<ExitError>,
193}
194
195impl From<bark::exit::models::ExitProgressStatus> for ExitProgressStatus {
196	fn from(v: bark::exit::models::ExitProgressStatus) -> Self {
197		ExitProgressStatus {
198			vtxo_id: v.vtxo_id,
199			state: v.state.into(),
200			error: v.error.map(ExitError::from),
201		}
202	}
203}
204
205#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
206#[cfg_attr(feature = "utoipa", derive(ToSchema))]
207pub struct ExitTransactionStatus {
208	/// The ID of the VTXO that is being unilaterally exited
209	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
210	pub vtxo_id: VtxoId,
211	/// The current state of the exit transaction
212	pub state: ExitState,
213	/// The history of each state the exit transaction has gone through
214	#[serde(default, skip_serializing_if = "Option::is_none")]
215	pub history: Option<Vec<ExitState>>,
216	/// Each exit transaction package required for the unilateral exit
217	#[serde(default, skip_serializing_if = "Vec::is_empty")]
218	pub transactions: Vec<ExitTransactionPackage>,
219}
220
221impl From<bark::exit::models::ExitTransactionStatus> for ExitTransactionStatus {
222	fn from(v: bark::exit::models::ExitTransactionStatus) -> Self {
223		ExitTransactionStatus {
224			vtxo_id: v.vtxo_id,
225			state: v.state.into(),
226			history: v.history.map(|h| h.into_iter().map(ExitState::from).collect()),
227			transactions: v.transactions.into_iter().map(ExitTransactionPackage::from).collect(),
228		}
229	}
230}
231
232/// Describes a completed transition of funds from onchain to offchain.
233#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
234#[cfg_attr(feature = "utoipa", derive(ToSchema))]
235pub struct Board {
236	/// The [Txid] of the funding-transaction.
237	/// This is the transaction that has to be confirmed
238	/// onchain for the board to succeed.
239	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
240	pub funding_txid: Txid,
241	/// The info for each [ark::Vtxo] that was created
242	/// in this board.
243	///
244	/// Currently, this is always a vector of length 1
245	pub vtxos: Vec<VtxoInfo>,
246}
247
248impl From<bark::Board> for Board {
249	fn from(v: bark::Board) -> Self {
250		Board {
251			funding_txid: v.funding_txid,
252			vtxos: v.vtxos.into_iter().map(VtxoInfo::from).collect(),
253		}
254	}
255}
256
257/// Describes an attempted movement of offchain funds within the Bark [Wallet].
258#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
259#[cfg_attr(feature = "utoipa", derive(ToSchema))]
260pub struct Movement {
261	/// The internal ID of the movement.
262	#[cfg_attr(feature = "utoipa", schema(value_type = u32))]
263	pub id: MovementId,
264	/// The status of the movement.
265	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
266	pub status: MovementStatus,
267	/// Contains information about the subsystem that created the movement as well as the purpose
268	/// of the movement.
269	pub subsystem: MovementSubsystem,
270	/// Miscellaneous metadata for the movement. This is JSON containing arbitrary information as
271	/// defined by the subsystem that created the movement.
272	#[serde(default, skip_serializing_if = "Option::is_none")]
273	pub metadata: Option<String>,
274	/// How much the movement was expected to increase or decrease the balance by. This is always an
275	/// estimate and often discounts any applicable fees.
276	#[serde(rename="intended_balance_sat", with="bitcoin::amount::serde::as_sat")]
277	#[cfg_attr(feature = "utoipa", schema(value_type = i64))]
278	pub intended_balance: SignedAmount,
279	/// How much the wallet balance actually changed by. Positive numbers indicate an increase and
280	/// negative numbers indicate a decrease. This is often inclusive of applicable fees, and it
281	/// should be the most accurate number.
282	#[serde(rename="effective_balance_sat", with="bitcoin::amount::serde::as_sat")]
283	#[cfg_attr(feature = "utoipa", schema(value_type = i64))]
284	pub effective_balance: SignedAmount,
285	/// How much the movement cost the user in offchain fees. If there are applicable onchain fees
286	/// they will not be included in this value but, depending on the subsystem, could be found in
287	/// the metadata.
288	#[serde(rename="offchain_fee_sat", with="bitcoin::amount::serde::as_sat")]
289	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
290	pub offchain_fee: Amount,
291	/// A list of external recipients that received funds from this movement.
292	pub sent_to: Vec<MovementDestination>,
293	/// Describes the means by which the wallet received funds in this movement. This could include
294	/// BOLT11 invoices or other useful data.
295	pub received_on: Vec<MovementDestination>,
296	/// A list of [Vtxo] IDs that were consumed by this movement and are either locked or
297	/// unavailable.
298	#[cfg_attr(feature = "utoipa", schema(value_type = Vec<String>))]
299	pub input_vtxos: Vec<VtxoId>,
300	/// A list of IDs for new VTXOs that were produced as a result of this movement. Often change
301	/// VTXOs will be found here for outbound actions unless this was an inbound action.
302	#[cfg_attr(feature = "utoipa", schema(value_type = Vec<String>))]
303	pub output_vtxos: Vec<VtxoId>,
304	/// A list of IDs for VTXOs that were marked for unilateral exit as a result of this movement.
305	/// This could happen for many reasons, e.g. an unsuccessful lightning payment which can't be
306	/// revoked but is about to expire. VTXOs listed here will result in a reduction of spendable
307	/// balance due to the VTXOs being managed by the [bark::Exit] system.
308	#[cfg_attr(feature = "utoipa", schema(value_type = Vec<String>))]
309	pub exited_vtxos: Vec<VtxoId>,
310	/// Contains the times at which the movement was created, updated and completed.
311	pub time: MovementTimestamp,
312}
313
314impl TryFrom<bark::movement::Movement> for Movement {
315	type Error = serde_json::Error;
316
317	fn try_from(m: bark::movement::Movement) -> Result<Self, Self::Error> {
318		Ok(Movement {
319			id: m.id,
320			status: m.status,
321			subsystem: MovementSubsystem::from(m.subsystem),
322			metadata: if m.metadata.is_empty() { None } else {
323				Some(serde_json::to_string(&m.metadata)?)
324			},
325			intended_balance: m.intended_balance,
326			effective_balance: m.effective_balance,
327			offchain_fee: m.offchain_fee,
328			sent_to: m.sent_to.into_iter().map(MovementDestination::from).collect(),
329			received_on: m.received_on.into_iter().map(MovementDestination::from).collect(),
330			input_vtxos: m.input_vtxos,
331			output_vtxos: m.output_vtxos,
332			exited_vtxos: m.exited_vtxos,
333			time: MovementTimestamp::from(m.time),
334		})
335	}
336}
337
338/// Describes a recipient of a movement. This could either be an external recipient in send actions
339/// or it could be the bark wallet itself.
340#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
341#[cfg_attr(feature = "utoipa", derive(ToSchema))]
342pub struct MovementDestination {
343	/// An address, invoice or any other identifier to distinguish the recipient.
344	pub destination: String,
345	/// How many sats the recipient received.
346	#[serde(rename="amount_sat", with="bitcoin::amount::serde::as_sat")]
347	#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
348	pub amount: Amount,
349}
350
351impl From<bark::movement::MovementDestination> for MovementDestination {
352	fn from(d: bark::movement::MovementDestination) -> Self {
353		MovementDestination {
354			destination: d.destination,
355			amount: d.amount,
356		}
357	}
358}
359
360/// Contains information about the subsystem that created the movement as well as the purpose
361/// of the movement.
362#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
363#[cfg_attr(feature = "utoipa", derive(ToSchema))]
364pub struct MovementSubsystem {
365	/// The name of the subsystem that created and manages the movement.
366	pub name: String,
367	/// The action responsible for registering the movement.
368	pub kind: String,
369}
370
371impl From<bark::movement::MovementSubsystem> for MovementSubsystem {
372	fn from(s: bark::movement::MovementSubsystem) -> Self {
373		MovementSubsystem {
374			name: s.name,
375			kind: s.kind,
376		}
377	}
378}
379
380/// Contains the times at which the movement was created, updated and completed.
381#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
382#[cfg_attr(feature = "utoipa", derive(ToSchema))]
383pub struct MovementTimestamp {
384	/// When the movement was first created.
385	pub created_at: DateTime<chrono::Utc>,
386	/// When the movement was last updated.
387	pub updated_at: DateTime<chrono::Utc>,
388	/// The action responsible for registering the movement.
389	#[serde(default, skip_serializing_if = "Option::is_none")]
390	pub completed_at: Option<DateTime<chrono::Utc>>,
391}
392
393impl From<bark::movement::MovementTimestamp> for MovementTimestamp {
394	fn from(t: bark::movement::MovementTimestamp) -> Self {
395		MovementTimestamp {
396			created_at: t.created_at,
397			updated_at: t.updated_at,
398			completed_at: t.completed_at,
399		}
400	}
401}
402
403pub mod onchain {
404	use super::*;
405
406	#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
407	#[cfg_attr(feature = "utoipa", derive(ToSchema))]
408	pub struct Send {
409		#[cfg_attr(feature = "utoipa", schema(value_type = String))]
410		pub txid: Txid,
411	}
412
413	#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
414	#[cfg_attr(feature = "utoipa", derive(ToSchema))]
415	pub struct Address {
416		#[cfg_attr(feature = "utoipa", schema(value_type = String))]
417		pub address: bitcoin::Address<bitcoin::address::NetworkUnchecked>,
418	}
419
420	#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
421	#[cfg_attr(feature = "utoipa", derive(ToSchema))]
422	pub struct OnchainBalance {
423		/// All of them combined.
424		#[serde(rename="total_sat", with="bitcoin::amount::serde::as_sat")]
425		#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
426		pub total: Amount,
427		/// Get sum of trusted_pending and confirmed coins.
428		///
429		/// This is the balance you can spend right now that shouldn't get cancelled via another party
430		/// double spending it.
431		#[serde(rename="trusted_spendable_sat", with="bitcoin::amount::serde::as_sat")]
432		#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
433		pub trusted_spendable: Amount,
434		/// All coinbase outputs not yet matured
435		#[serde(rename="immature_sat", with="bitcoin::amount::serde::as_sat")]
436		#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
437		pub immature: Amount,
438		/// Unconfirmed UTXOs generated by a wallet tx
439		#[serde(rename="trusted_pending_sat", with="bitcoin::amount::serde::as_sat")]
440		#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
441		pub trusted_pending: Amount,
442		/// Unconfirmed UTXOs received from an external wallet
443		#[serde(rename="untrusted_pending_sat", with="bitcoin::amount::serde::as_sat")]
444		#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
445		pub untrusted_pending: Amount,
446		/// Confirmed and immediately spendable balance
447		#[serde(rename="confirmed_sat", with="bitcoin::amount::serde::as_sat")]
448		#[cfg_attr(feature = "utoipa", schema(value_type = u64))]
449		pub confirmed: Amount,
450	}
451}
452
453#[derive(Debug, Clone, Serialize, Deserialize)]
454#[serde(tag = "result", rename_all = "lowercase")]
455#[cfg_attr(feature = "utoipa", derive(ToSchema))]
456pub enum RoundStatus {
457	/// The round was successful and is fully confirmed
458	Confirmed {
459		#[cfg_attr(feature = "utoipa", schema(value_type = String))]
460		funding_txid: Txid,
461	},
462	/// Round successful but not fully confirmed
463	Unconfirmed {
464		#[cfg_attr(feature = "utoipa", schema(value_type = String))]
465		funding_txid: Txid,
466	},
467	/// We have unsigned funding transactions that might confirm
468	Pending {
469		#[cfg_attr(feature = "utoipa", schema(value_type = Vec<String>))]
470		unsigned_funding_txids: Vec<Txid>,
471	},
472	/// The round failed
473	Failed {
474		error: String,
475	},
476}
477
478impl RoundStatus {
479	/// Whether this is the final state and it won't change anymore
480	pub fn is_final(&self) -> bool {
481		match self {
482			Self::Confirmed { .. } => true,
483			Self::Unconfirmed { .. } => false,
484			Self::Pending { .. } => false,
485			Self::Failed { .. } => true,
486		}
487	}
488
489	/// Whether it looks like the round succeeded
490	pub fn is_success(&self) -> bool {
491		match self {
492			Self::Confirmed { .. } => true,
493			Self::Unconfirmed { .. } => true,
494			Self::Pending { .. } => false,
495			Self::Failed { .. } => false,
496		}
497	}
498}
499
500#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
501#[cfg_attr(feature = "utoipa", derive(ToSchema))]
502pub struct InvoiceInfo {
503	/// The invoice string
504	pub invoice: String,
505}
506
507#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
508#[cfg_attr(feature = "utoipa", derive(ToSchema))]
509pub struct LightningReceiveInfo {
510	/// The payment hash linked to the lightning receive info
511	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
512	pub payment_hash: PaymentHash,
513	/// The payment preimage linked to the lightning receive info
514	#[cfg_attr(feature = "utoipa", schema(value_type = String))]
515	pub payment_preimage: Preimage,
516	/// The timestamp at which the preimage was revealed
517	pub preimage_revealed_at: Option<chrono::DateTime<chrono::Utc>>,
518	/// The invoice string
519	pub invoice: String,
520	/// The HTLC VTXOs granted by the server for the lightning receive
521	///
522	/// Only present if the lightning HTLC has been received by the server.
523	#[cfg_attr(feature = "utoipa", schema(value_type = Vec<WalletVtxoInfo>, nullable = true))]
524	pub htlc_vtxos: Option<Vec<WalletVtxoInfo>>,
525}
526
527impl From<bark::persist::models::LightningReceive> for LightningReceiveInfo {
528	fn from(v: bark::persist::models::LightningReceive) -> Self {
529		LightningReceiveInfo {
530			payment_hash: v.payment_hash,
531			payment_preimage: v.payment_preimage,
532			preimage_revealed_at: v.preimage_revealed_at.map(|ts| {
533				chrono::DateTime::from_timestamp_secs(ts as i64)
534					.expect("timestamp is valid")
535			}),
536			invoice: v.invoice.to_string(),
537			htlc_vtxos: v.htlc_vtxos.map(|vtxos| vtxos.into_iter()
538				.map(crate::primitives::WalletVtxoInfo::from).collect()),
539		}
540	}
541}
542
543#[cfg(test)]
544mod test {
545	use super::*;
546
547	#[test]
548	fn ark_info_fields() {
549		//! the purpose of this test is to fail if we add a field to
550		//! ark::ArkInfo but we forgot to add it to the ArkInfo here
551
552		#[allow(unused)]
553		fn convert(j: ArkInfo) -> ark::ArkInfo {
554			ark::ArkInfo {
555				network: j.network,
556				server_pubkey: j.server_pubkey,
557				round_interval: j.round_interval,
558				nb_round_nonces: j.nb_round_nonces,
559				vtxo_exit_delta: j.vtxo_exit_delta,
560				vtxo_expiry_delta: j.vtxo_expiry_delta,
561				htlc_send_expiry_delta: j.htlc_send_expiry_delta,
562				htlc_expiry_delta: j.htlc_expiry_delta,
563				max_vtxo_amount: j.max_vtxo_amount,
564				max_arkoor_depth: j.max_arkoor_depth,
565				required_board_confirmations: j.required_board_confirmations,
566				max_user_invoice_cltv_delta: j.max_user_invoice_cltv_delta,
567				min_board_amount: j.min_board_amount,
568				offboard_feerate: FeeRate::from_sat_per_kwu(j.offboard_feerate_sat_per_kvb / 4),
569				ln_receive_anti_dos_required: j.ln_receive_anti_dos_required,
570			}
571		}
572	}
573}
574