bark/persist/mod.rs
1//! Persistence abstractions for Bark wallets.
2//!
3//! This module defines the [BarkPersister] trait and related data models used by the
4//! wallet to store and retrieve state. Implementors can provide their own storage backends
5//! (e.g., SQLite, PostgreSQL, in-memory, mobile key/value stores) by implementing the
6//! [BarkPersister] trait.
7//!
8//! Design goals
9//! - Clear separation between wallet logic and storage.
10//! - Transactional semantics where appropriate (round state transitions, movement recording).
11//! - Portability across different platforms and environments.
12//!
13//! Typical usage
14//! - Applications construct a concrete persister (for example, a SQLite-backed client) and
15//! pass it to the [crate::Wallet]. The [crate::Wallet] only depends on this trait for reads/writes.
16//! - Custom wallet implementations can reuse this trait to remain compatible with Bark
17//! storage expectations without depending on a specific database.
18//! - A default rusqlite implementation is provided by [sqlite::SqliteClient].
19
20pub mod adaptor;
21pub mod models;
22#[cfg(feature = "sqlite")]
23pub mod sqlite;
24#[cfg(test)]
25pub(crate) mod test_suite;
26
27
28use bitcoin::{Amount, Transaction, Txid};
29use bitcoin::secp256k1::PublicKey;
30use chrono::DateTime;
31use lightning_invoice::Bolt11Invoice;
32#[cfg(feature = "onchain-bdk")]
33use bdk_wallet::ChangeSet;
34
35use ark::{Vtxo, VtxoId};
36use ark::lightning::{Invoice, PaymentHash, Preimage};
37use ark::vtxo::Full;
38use bitcoin_ext::BlockDelta;
39
40use crate::WalletProperties;
41use crate::actions::{WalletActionCheckpoint, WalletActionId};
42use crate::exit::ExitTxOrigin;
43use crate::persist::models::{
44 LightningReceive, LightningSend, PendingBoard, RoundStateId, StoredExit, StoredRoundState,
45 Unlocked, PendingOffboard,
46};
47use crate::movement::{Movement, MovementId, MovementStatus, MovementSubsystem, PaymentMethod};
48use crate::round::RoundState;
49use crate::vtxo::{VtxoState, VtxoStateKind, WalletVtxo};
50
51/// Storage interface for Bark wallets.
52///
53/// Implement this trait to plug a custom persistence backend. The wallet uses it to:
54/// - Initialize and read wallet properties and configuration.
55/// - Record movements (spends/receives), recipients, and enforce [Vtxo] state transitions.
56/// - Manage round lifecycles (attempts, pending confirmation, confirmations/cancellations).
57/// - Persist ephemeral protocol artifacts (e.g., secret nonces) transactionally.
58/// - Track Lightning receives and preimage revelation.
59/// - Track exit-related data and associated child transactions.
60/// - Persist the last synchronized Ark block height.
61///
62/// Feature integration:
63/// - With the `onchain-bdk` feature, methods are provided to initialize and persist a BDK
64/// wallet ChangeSet in the same storage.
65///
66/// Notes for implementors:
67/// - Ensure that operations that change multiple records (e.g., registering a movement,
68/// storing round state transitions) are executed transactionally.
69/// - Enforce state integrity by verifying allowed_old_states before updating a [Vtxo] state.
70/// - If your backend is not thread-safe, prefer a short-lived connection per call or use
71/// an internal pool with checked-out connections per operation.
72/// - Return precise errors so callers can surface actionable diagnostics.
73#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
74#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
75pub trait BarkPersister: Send + Sync + 'static {
76 /// Check if the wallet is initialized.
77 ///
78 /// Returns:
79 /// - `Ok(true)` if the wallet is initialized.
80 /// - `Ok(false)` if the wallet is not initialized.
81 ///
82 /// Errors:
83 /// - Returns an error if the query fails.
84 async fn is_initialized(&self) -> anyhow::Result<bool> {
85 Ok(self.read_properties().await?.is_some())
86 }
87
88 /// Initialize a wallet in storage with the provided properties.
89 ///
90 /// Call exactly once per wallet database. Subsequent calls should fail to prevent
91 /// accidental re-initialization.
92 ///
93 /// Parameters:
94 /// - properties: WalletProperties to persist (e.g., network, descriptors, metadata).
95 ///
96 /// Returns:
97 /// - `Ok(())` on success.
98 ///
99 /// Errors:
100 /// - Returns an error if the wallet is already initialized or if persistence fails.
101 async fn init_wallet(&self, properties: &WalletProperties) -> anyhow::Result<()>;
102
103 /// Initialize the onchain BDK wallet and return any previously stored ChangeSet.
104 ///
105 /// Must be called before storing any new BDK changesets to bootstrap the BDK state.
106 ///
107 /// Feature: only available with `onchain-bdk`.
108 ///
109 /// Returns:
110 /// - `Ok(ChangeSet)` containing the previously persisted BDK state (possibly empty).
111 ///
112 /// Errors:
113 /// - Returns an error if the BDK state cannot be created or loaded.
114 #[cfg(feature = "onchain-bdk")]
115 async fn initialize_bdk_wallet(&self) -> anyhow::Result<ChangeSet>;
116
117 /// Persist an incremental BDK ChangeSet.
118 ///
119 /// The changeset should be applied atomically. Callers typically obtain the changeset
120 /// from a BDK wallet instance after mutating wallet state (e.g., sync).
121 ///
122 /// Feature: only available with `onchain-bdk`.
123 ///
124 /// Parameters:
125 /// - changeset: The BDK ChangeSet to persist.
126 ///
127 /// Errors:
128 /// - Returns an error if the changeset cannot be written.
129 #[cfg(feature = "onchain-bdk")]
130 async fn store_bdk_wallet_changeset(&self, changeset: &ChangeSet) -> anyhow::Result<()>;
131
132 /// Read wallet properties from storage.
133 ///
134 /// Returns:
135 /// - `Ok(Some(WalletProperties))` if the wallet has been initialized.
136 /// - `Ok(None)` if no wallet exists yet.
137 ///
138 /// Errors:
139 /// - Returns an error on I/O or deserialization failures.
140 async fn read_properties(&self) -> anyhow::Result<Option<WalletProperties>>;
141
142 /// Set the server public key in wallet properties.
143 ///
144 /// This is used to store the server pubkey for existing wallets that were
145 /// created before server pubkey tracking was added. Once set, the wallet
146 /// will verify the server pubkey on every connection.
147 ///
148 /// Parameters:
149 /// - server_pubkey: The server's public key to store.
150 ///
151 /// Errors:
152 /// - Returns an error if the update fails.
153 async fn set_server_pubkey(&self, server_pubkey: PublicKey) -> anyhow::Result<()>;
154
155 /// Set the server's mailbox public key in wallet properties.
156 ///
157 /// This is used to store the server mailbox pubkey for existing wallets that were
158 /// created before mailbox pubkey tracking was added. Once set, Ark addresses
159 /// can be generated offline without a live server connection.
160 ///
161 /// Parameters:
162 /// - server_mailbox_pubkey: The server's mailbox public key to store.
163 ///
164 /// Errors:
165 /// - Returns an error if the update fails.
166 async fn set_server_mailbox_pubkey(&self, server_mailbox_pubkey: PublicKey) -> anyhow::Result<()>;
167
168 /// Creates a new movement in the given state, ready to be updated.
169 ///
170 /// Parameters:
171 /// - status: The desired status for the new movement.
172 /// - subsystem: The subsystem that created the movement.
173 /// - time: The time the movement should be marked as created.
174 ///
175 /// Returns:
176 /// - `Ok(MovementId)` of the newly created movement.
177 ///
178 /// Errors:
179 /// - Returns an error if the movement is unable to be created.
180 async fn create_new_movement(&self,
181 status: MovementStatus,
182 subsystem: &MovementSubsystem,
183 time: DateTime<chrono::Local>,
184 ) -> anyhow::Result<MovementId>;
185
186 /// Persists the given movement state.
187 ///
188 /// Parameters:
189 /// - movement: The movement and its associated data to be persisted.
190 ///
191 /// Errors:
192 /// - Returns an error if updating the movement fails for any reason.
193 async fn update_movement(&self, movement: &Movement) -> anyhow::Result<()>;
194
195 /// Gets the movement with the given [MovementId].
196 ///
197 /// Parameters:
198 /// - movement_id: The ID of the movement to retrieve.
199 ///
200 /// Returns:
201 /// - `Ok(Movement)` if the movement exists.
202 ///
203 /// Errors:
204 /// - If the movement does not exist.
205 /// - If retrieving the movement fails.
206 async fn get_movement_by_id(&self, movement_id: MovementId) -> anyhow::Result<Movement>;
207
208 /// Gets every stored movement.
209 ///
210 /// Returns:
211 /// - `Ok(Vec<Movement>)` containing all movements, empty if none exist.
212 ///
213 /// Errors:
214 /// - If retrieving the movements fails.
215 async fn get_all_movements(&self) -> anyhow::Result<Vec<Movement>>;
216
217 /// Get all movements for a given payment method
218 ///
219 /// Parameters:
220 /// - `payment_method`: The [PaymentMethod] to look up.
221 ///
222 /// Returns:
223 /// - `Ok(movements)` containing all relevant movements, empty if none exist.
224 ///
225 /// Errors:
226 /// - Returns an error if the query fails.
227 async fn get_movements_by_payment_method(
228 &self,
229 payment_method: &PaymentMethod,
230 ) -> anyhow::Result<Vec<Movement>>;
231
232 /// Store a pending board.
233 ///
234 /// Parameters:
235 /// - vtxo: The [Vtxo] to store.
236 /// - funding_txid: The funding [Txid].
237 /// - movement_id: The [MovementId] associated with this board.
238 ///
239 /// Errors:
240 /// - Returns an error if the board cannot be stored.
241 async fn store_pending_board(
242 &self,
243 vtxo: &Vtxo<Full>,
244 funding_tx: &Transaction,
245 movement_id: MovementId,
246 ) -> anyhow::Result<()>;
247
248 /// Remove a pending board.
249 ///
250 /// Parameters:
251 /// - vtxo_id: The [VtxoId] to remove.
252 ///
253 /// Errors:
254 /// - Returns an error if the board cannot be removed.
255 async fn remove_pending_board(&self, vtxo_id: &VtxoId) -> anyhow::Result<()>;
256
257 /// Get the [VtxoId] for each pending board.
258 ///
259 /// Returns:
260 /// - `Ok(Vec<VtxoId>)` possibly empty.
261 ///
262 /// Errors:
263 /// - Returns an error if the query fails.
264 async fn get_all_pending_board_ids(&self) -> anyhow::Result<Vec<VtxoId>>;
265
266 /// Get the [PendingBoard] associated with the given [VtxoId].
267 ///
268 /// Returns:
269 /// - `Ok(Some(PendingBoard))` if a matching board exists
270 /// - `Ok(None)` if no matching board exists
271 ///
272 /// Errors:
273 /// - Returns an error if the query fails.
274 async fn get_pending_board_by_vtxo_id(&self, vtxo_id: VtxoId) -> anyhow::Result<Option<PendingBoard>>;
275
276 /// Store a new ongoing round state and lock the VTXOs in round
277 ///
278 /// Parameters:
279 /// - `round_state`: the state to store
280 ///
281 /// Returns:
282 /// - `RoundStateId`: the storaged ID of the new state
283 ///
284 /// Errors:
285 /// - returns an error of the new round state could not be stored or the VTXOs
286 /// couldn't be marked as locked
287 async fn store_round_state_lock_vtxos(&self, round_state: &RoundState) -> anyhow::Result<RoundStateId>;
288
289 /// Update an existing stored pending round state
290 ///
291 /// Parameters:
292 /// - `round_state`: the round state to update
293 ///
294 /// Errors:
295 /// - returns an error of the existing round state could not be found or updated
296 async fn update_round_state(&self, round_state: &StoredRoundState) -> anyhow::Result<()>;
297
298 /// Remove a pending round state from the db
299 ///
300 /// Parameters:
301 /// - `round_state`: the round state to remove
302 ///
303 /// Errors:
304 /// - returns an error of the existing round state could not be found or removed
305 async fn remove_round_state(&self, round_state: &StoredRoundState) -> anyhow::Result<()>;
306
307 /// Load a single round state by its id
308 ///
309 /// Returns:
310 /// - `Option<StoredRoundState>`: the stored round state if found, `None` otherwise
311 ///
312 /// Errors:
313 /// - returns an error of the states could not be succesfully retrieved
314 async fn get_round_state_by_id(&self, id: RoundStateId) -> anyhow::Result<Option<StoredRoundState<Unlocked>>>;
315
316 /// Load all pending round states from the db
317 ///
318 /// Returns:
319 /// - `Vec<RoundStateId>`: unordered vector with all stored round state ids
320 ///
321 /// Errors:
322 /// - returns an error of the ids could not be succesfully retrieved
323 async fn get_pending_round_state_ids(&self) -> anyhow::Result<Vec<RoundStateId>>;
324
325 /// Stores VTXOs with their initial state.
326 ///
327 /// This operation is idempotent: if a VTXO already exists (same `id`), the
328 /// implementation should succeed without modifying the existing VTXO or its
329 /// state. This allows safe retries during crash recovery scenarios.
330 ///
331 /// # Parameters
332 /// - `vtxos`: Slice of VTXO and state pairs to store.
333 ///
334 /// # Behavior
335 /// - For each VTXO that does not exist: inserts the VTXO and its initial state.
336 /// - For each VTXO that already exists: no-op for that VTXO.
337 ///
338 /// # Errors
339 /// - Returns an error if the storage operation fails.
340 async fn store_vtxos(
341 &self,
342 vtxos: &[(&Vtxo<Full>, &VtxoState)],
343 ) -> anyhow::Result<()>;
344
345 /// Fetch a wallet [Vtxo] with its current state by ID.
346 ///
347 /// Parameters:
348 /// - id: [VtxoId] to look up.
349 ///
350 /// Returns:
351 /// - `Ok(Some(WalletVtxo))` if found,
352 /// - `Ok(None)` otherwise.
353 ///
354 /// Errors:
355 /// - Returns an error if the lookup fails.
356 async fn get_wallet_vtxo(&self, id: VtxoId) -> anyhow::Result<Option<WalletVtxo>>;
357
358 /// Fetch all wallet VTXOs in the database.
359 ///
360 /// Returns:
361 /// - `Ok(Vec<WalletVtxo>)` possibly empty.
362 ///
363 /// Errors:
364 /// - Returns an error if the query fails.
365 async fn get_all_vtxos(&self) -> anyhow::Result<Vec<WalletVtxo>>;
366
367 /// Fetch all wallet VTXOs whose state matches any of the provided kinds.
368 ///
369 /// Parameters:
370 /// - state: Slice of `VtxoStateKind` filters.
371 ///
372 /// Returns:
373 /// - `Ok(Vec<WalletVtxo>)` possibly empty.
374 ///
375 /// Errors:
376 /// - Returns an error if the query fails.
377 async fn get_vtxos_by_state(&self, state: &[VtxoStateKind]) -> anyhow::Result<Vec<WalletVtxo>>;
378
379 /// Fetch a single VTXO in full form (including the unilateral exit chain).
380 ///
381 /// Listing/balance/selection paths return [WalletVtxo] (which holds
382 /// [Vtxo<ark::vtxo::Bare>]) to keep memory bounded. Operations that
383 /// genuinely need the genesis chain — unilateral exit, server
384 /// registration, arkoor send, offboard — should call this method
385 /// (or [BarkPersister::get_full_vtxos] for batches) on demand.
386 async fn get_full_vtxo(&self, id: VtxoId) -> anyhow::Result<Option<Vtxo<Full>>>;
387
388 /// Hydrate a batch of VTXOs into their full form, preserving the order
389 /// of the input slice. Returns an error if any id is missing — callers
390 /// reach this from a selection step against the wallet's listings, so a
391 /// missing row indicates the wallet's state is inconsistent with the
392 /// caller's view.
393 async fn get_full_vtxos(&self, ids: &[VtxoId]) -> anyhow::Result<Vec<Vtxo<Full>>>;
394
395 /// Remove a [Vtxo] by ID.
396 ///
397 /// Parameters:
398 /// - id: `VtxoId` to remove.
399 ///
400 /// Returns:
401 /// - `Ok(Some(Vtxo))` with the removed [Vtxo] data if it existed,
402 /// - `Ok(None)` otherwise.
403 ///
404 /// Errors:
405 /// - Returns an error if the delete operation fails.
406 async fn remove_vtxo(&self, id: VtxoId) -> anyhow::Result<Option<Vtxo<Full>>>;
407
408 /// Check whether a [Vtxo] is already marked spent.
409 ///
410 /// Parameters:
411 /// - id: VtxoId to check.
412 ///
413 /// Returns:
414 /// - `Ok(true)` if spent,
415 /// - `Ok(false)` if not found or not spent.
416 ///
417 /// Errors:
418 /// - Returns an error if the lookup fails.
419 async fn has_spent_vtxo(&self, id: VtxoId) -> anyhow::Result<bool>;
420
421 /// Store a newly derived/assigned [Vtxo] public key index mapping.
422 ///
423 /// Parameters:
424 /// - index: Derivation index.
425 /// - public_key: PublicKey at that index.
426 ///
427 /// Errors:
428 /// - Returns an error if the mapping cannot be stored.
429 async fn store_vtxo_key(&self, index: u32, public_key: PublicKey) -> anyhow::Result<()>;
430
431 /// Get the last revealed/used [Vtxo] key index.
432 ///
433 /// Returns:
434 /// - `Ok(Some(u32))` if a key was stored
435 /// - `Ok(None)` otherwise.
436 ///
437 /// Errors:
438 /// - Returns an error if the query fails.
439 async fn get_last_vtxo_key_index(&self) -> anyhow::Result<Option<u32>>;
440
441 /// Retrieves the derivation index of the provided [PublicKey] from the database
442 ///
443 /// Returns:
444 /// - `Ok(Some(u32))` if the key was stored.
445 /// - `Ok(None)` if the key was not stored.
446 ///
447 /// Errors:
448 /// - Returns an error if the query fails.
449 async fn get_public_key_idx(&self, public_key: &PublicKey) -> anyhow::Result<Option<u32>>;
450
451 /// Retrieves the mailbox checkpoint from the database
452 ///
453 /// Returns:
454 /// - `Ok(u64)` the stored checkpoint.
455 ///
456 /// Errors:
457 /// - Returns an error if the query fails.
458 async fn get_mailbox_checkpoint(&self) -> anyhow::Result<u64>;
459
460 /// Update the mailbox checkpoint to the new checkpoint
461 ///
462 /// Returns:
463 ///
464 ///
465 /// Errors:
466 /// - Returns error when the query fails
467 /// - Returns error when the provided checkpoint is smaller than the existing checkpoint
468 async fn store_mailbox_checkpoint(&self, checkpoint: u64) -> anyhow::Result<()>;
469
470 /// Store a new pending lightning send.
471 ///
472 /// Parameters:
473 /// - invoice: The invoice of the pending lightning send.
474 /// - amount: The amount of the pending lightning send.
475 /// - fee: The fee of the pending lightning send.
476 /// - vtxos: The vtxos of the pending lightning send.
477 /// - movement_id: The movement ID associated with this send.
478 ///
479 /// Errors:
480 /// - Returns an error if the pending lightning send cannot be stored.
481 async fn store_new_pending_lightning_send(
482 &self,
483 invoice: &Invoice,
484 amount: Amount,
485 fee: Amount,
486 vtxos: &[VtxoId],
487 movement_id: MovementId,
488 ) -> anyhow::Result<LightningSend>;
489
490 /// Get all pending lightning sends.
491 ///
492 /// Returns:
493 /// - `Ok(Vec<LightningSend>)` possibly empty.
494 ///
495 /// Errors:
496 /// - Returns an error if the query fails.
497 async fn get_all_pending_lightning_send(&self) -> anyhow::Result<Vec<LightningSend>>;
498
499 /// Mark a lightning send as finished.
500 ///
501 /// Parameters:
502 /// - payment_hash: The [PaymentHash] of the lightning send to update.
503 /// - preimage: The [Preimage] of the successful lightning send.
504 ///
505 /// Errors:
506 /// - Returns an error if the lightning send cannot be updated.
507 async fn finish_lightning_send(
508 &self,
509 payment_hash: PaymentHash,
510 preimage: Option<Preimage>,
511 ) -> anyhow::Result<()>;
512
513 /// Remove a lightning send.
514 ///
515 /// Parameters:
516 /// - payment_hash: The [PaymentHash] of the lightning send to remove.
517 ///
518 /// Errors:
519 /// - Returns an error if the lightning send cannot be removed.
520 async fn remove_lightning_send(&self, payment_hash: PaymentHash) -> anyhow::Result<()>;
521
522 /// Get a lightning send by payment hash
523 ///
524 /// Parameters:
525 /// - payment_hash: The [PaymentHash] of the lightning send to get.
526 ///
527 /// Errors:
528 /// - Returns an error if the lookup fails.
529 async fn get_lightning_send(&self, payment_hash: PaymentHash) -> anyhow::Result<Option<LightningSend>>;
530
531 /// Persist or overwrite a wallet action checkpoint.
532 ///
533 /// Parameters:
534 /// - id: stable action identifier (e.g. payment hash hex for a lightning send).
535 /// - checkpoint: the payload to persist; replaces any existing row with the same id.
536 ///
537 /// Errors:
538 /// - Returns an error if the write fails.
539 async fn upsert_wallet_action_checkpoint(
540 &self,
541 id: &WalletActionId,
542 checkpoint: &WalletActionCheckpoint,
543 ) -> anyhow::Result<()>;
544
545 /// Fetch a wallet action checkpoint by id.
546 ///
547 /// Returns:
548 /// - `Ok(Some(_))` if a row exists, `Ok(None)` otherwise.
549 ///
550 /// Errors:
551 /// - Returns an error if the lookup or deserialization fails.
552 async fn get_wallet_action_checkpoint(
553 &self,
554 id: &WalletActionId,
555 ) -> anyhow::Result<Option<WalletActionCheckpoint>>;
556
557 /// Fetch every persisted wallet action checkpoint, oldest first.
558 ///
559 /// Used by the periodic sync to find work to re-drive.
560 async fn get_all_wallet_action_checkpoints(
561 &self,
562 ) -> anyhow::Result<Vec<WalletActionCheckpoint>>;
563
564 /// Remove a wallet action checkpoint by id. No-op if absent.
565 async fn remove_wallet_action_checkpoint(
566 &self,
567 id: &WalletActionId,
568 ) -> anyhow::Result<()>;
569
570 /// Store an incoming Lightning receive record.
571 ///
572 /// Parameters:
573 /// - payment_hash: Unique payment hash.
574 /// - preimage: Payment preimage (kept until disclosure).
575 /// - invoice: The associated BOLT11 invoice.
576 /// - htlc_recv_cltv_delta: The CLTV delta for the HTLC VTXO.
577 ///
578 /// Errors:
579 /// - Returns an error if the receive cannot be stored.
580 async fn store_lightning_receive(
581 &self,
582 payment_hash: PaymentHash,
583 preimage: Preimage,
584 invoice: &Bolt11Invoice,
585 htlc_recv_cltv_delta: BlockDelta,
586 ) -> anyhow::Result<()>;
587
588 /// Returns a list of all pending lightning receives
589 ///
590 /// Returns:
591 /// - `Ok(Vec<LightningReceive>)` possibly empty.
592 ///
593 /// Errors:
594 /// - Returns an error if the query fails.
595 async fn get_all_pending_lightning_receives(&self) -> anyhow::Result<Vec<LightningReceive>>;
596
597 /// Mark a Lightning receive preimage as revealed (e.g., after settlement).
598 ///
599 /// Parameters:
600 /// - payment_hash: The payment hash identifying the receive.
601 ///
602 /// Errors:
603 /// - Returns an error if the update fails or the receive does not exist.
604 async fn set_preimage_revealed(&self, payment_hash: PaymentHash) -> anyhow::Result<()>;
605
606 /// Set the VTXO IDs and [MovementId] for a [LightningReceive].
607 ///
608 /// Parameters:
609 /// - payment_hash: The payment hash identifying the receive.
610 /// - htlc_vtxo_ids: The VTXO IDs to set.
611 /// - movement_id: The movement ID associated with the invoice.
612 ///
613 /// Errors:
614 /// - Returns an error if the update fails or the receive does not exist.
615 async fn update_lightning_receive(
616 &self,
617 payment_hash: PaymentHash,
618 htlc_vtxo_ids: &[VtxoId],
619 movement_id: MovementId,
620 ) -> anyhow::Result<()>;
621
622 /// Fetch a Lightning receive by its payment hash.
623 ///
624 /// Parameters:
625 /// - payment_hash: The payment hash to look up.
626 ///
627 /// Returns:
628 /// - `Ok(Some(LightningReceive))` if found,
629 /// - `Ok(None)` otherwise.
630 ///
631 /// Errors:
632 /// - Returns an error if the lookup fails.
633 async fn fetch_lightning_receive_by_payment_hash(
634 &self,
635 payment_hash: PaymentHash,
636 ) -> anyhow::Result<Option<LightningReceive>>;
637
638 /// Mark a Lightning receive as finished by its payment hash.
639 ///
640 /// Parameters:
641 /// - payment_hash: The payment hash of the record to mark finished
642 ///
643 /// Errors:
644 /// - Returns an error if the operation fails.
645 async fn finish_pending_lightning_receive(
646 &self,
647 payment_hash: PaymentHash,
648 ) -> anyhow::Result<()>;
649
650 /// Store an entry indicating a [Vtxo] is being exited.
651 ///
652 /// Parameters:
653 /// - exit: StoredExit describing the exit operation.
654 ///
655 /// Errors:
656 /// - Returns an error if the entry cannot be stored.
657 async fn store_exit_vtxo_entry(&self, exit: &StoredExit) -> anyhow::Result<()>;
658
659 /// Remove an exit entry for a given [Vtxo] ID.
660 ///
661 /// Parameters:
662 /// - id: VtxoId to remove from exit tracking.
663 ///
664 /// Errors:
665 /// - Returns an error if the removal fails.
666 async fn remove_exit_vtxo_entry(&self, id: &VtxoId) -> anyhow::Result<()>;
667
668 /// List all VTXOs currently tracked as being exited.
669 ///
670 /// Returns:
671 /// - `Ok(Vec<StoredExit>)` possibly empty.
672 ///
673 /// Errors:
674 /// - Returns an error if the query fails.
675 async fn get_exit_vtxo_entries(&self) -> anyhow::Result<Vec<StoredExit>>;
676
677 /// Store a child transaction related to an exit transaction.
678 ///
679 /// Parameters:
680 /// - exit_txid: The parent exit transaction ID.
681 /// - child_tx: The child bitcoin Transaction to store.
682 /// - origin: Metadata describing where the child came from (ExitTxOrigin).
683 ///
684 /// Errors:
685 /// - Returns an error if the transaction cannot be stored.
686 async fn store_exit_child_tx(
687 &self,
688 exit_txid: Txid,
689 child_tx: &Transaction,
690 origin: ExitTxOrigin,
691 ) -> anyhow::Result<()>;
692
693 /// Retrieve a stored child transaction for a given exit transaction ID.
694 ///
695 /// Parameters:
696 /// - exit_txid: The parent exit transaction ID.
697 ///
698 /// Returns:
699 /// - `Ok(Some((Transaction, ExitTxOrigin)))` if found,
700 /// - `Ok(None)` otherwise.
701 ///
702 /// Errors:
703 /// - Returns an error if the lookup fails.
704 async fn get_exit_child_tx(
705 &self,
706 exit_txid: Txid,
707 ) -> anyhow::Result<Option<(Transaction, ExitTxOrigin)>>;
708
709 /// Updates the state of the VTXO corresponding to the given [VtxoId], provided that their
710 /// current state is one of the given `allowed_states`.
711 ///
712 /// # Parameters
713 /// - `vtxo_id`: The ID of the [Vtxo] to update.
714 /// - `state`: The new state to be set for the specified [Vtxo].
715 /// - `allowed_states`: An iterable collection of allowed states ([VtxoStateKind]) that the
716 /// [Vtxo] must currently be in for their state to be updated to the new `state`.
717 ///
718 /// # Returns
719 /// - `Ok(WalletVtxo)` if the state update is successful.
720 /// - `Err(anyhow::Error)` if the VTXO fails to meet the required conditions,
721 /// or if another error occurs during the operation.
722 ///
723 /// # Errors
724 /// - Returns an error if the current state is not within the `allowed_states`.
725 /// - Returns an error for any other issues encountered during the operation.
726 async fn update_vtxo_state_checked(
727 &self,
728 vtxo_id: VtxoId,
729 new_state: VtxoState,
730 allowed_old_states: &[VtxoStateKind],
731 ) -> anyhow::Result<WalletVtxo>;
732
733 /// Store a pending offboard record.
734 ///
735 /// Parameters:
736 /// - pending: The [PendingOffboard] to store.
737 ///
738 /// Errors:
739 /// - Returns an error if the record cannot be stored.
740 async fn store_pending_offboard(
741 &self,
742 pending: &PendingOffboard,
743 ) -> anyhow::Result<()>;
744
745 /// Get all pending offboard records.
746 ///
747 /// Returns:
748 /// - `Ok(Vec<PendingOffboard>)` possibly empty.
749 ///
750 /// Errors:
751 /// - Returns an error if the query fails.
752 async fn get_pending_offboards(&self) -> anyhow::Result<Vec<PendingOffboard>>;
753
754 /// Remove a pending offboard record by its [MovementId].
755 ///
756 /// Parameters:
757 /// - movement_id: The [MovementId] to remove.
758 ///
759 /// Errors:
760 /// - Returns an error if the record cannot be removed.
761 async fn remove_pending_offboard(&self, movement_id: MovementId) -> anyhow::Result<()>;
762}