DustRepository
Repository for dust wallet operations.
Responsibilities:
Manage DustLocalState lifecycle (FFI bridge to Rust midnight-ledger)
Sync dust tokens from DustLocalState to database (cache layer)
Calculate current dust balance (time-based generation)
Provide available dust tokens for fee payment
Handle token state transitions (AVAILABLE → PENDING → SPENT)
Persist DustLocalState to encrypted storage
Architecture:
DustRepository
├─ DustLocalState (FFI) - Source of truth, in-memory Rust state
├─ DustDao (Database) - Cache layer for fast queries
└─ DataStore (Persistence) - Serialized state backupUsage:
@Inject lateinit var dustRepository: DustRepository
// Initialize dust wallet
dustRepository.initializeIfNeeded(address)
// Get current balance
val balance = dustRepository.getCurrentBalance(address)
// Get tokens for fee payment
val tokens = dustRepository.getAvailableTokens(address)
// Observe balance live
dustRepository.observeBalance(address).collect { balance ->
updateUI(balance)
}Thread Safety: All methods are thread-safe (suspend functions use coroutine context). DustLocalState instances are NOT thread-safe - use one per coroutine scope.
Constructors
Types
A dust checkpoint = the serialized DustLocalState plus the resume cursor (lastEventId) it was built up to. The two MUST describe the same chain point: the commitment-tree frontier carried inside the state has to equal the commitment index the event after lastEventId will try to insert at, or delta replay fails with NonLinearInsertion. state is owned by the caller and must be closed.
Functions
Clear the live state (for force-resync). Caller should close it.
Delete serialized DustLocalState for an address.
Get all available dust tokens for an address.
Get available dust tokens sorted by value (smallest first).
Get current dust balance for an address.
Get last applied dust event ID for delta sync resume. Null if never synced.
Get the live in-memory state from the last sync (no deserialization).
Get dust token count for an address.
Check if cached dust state exists for an address.
True only when BOTH halves of a checkpoint are present — cheaper than loadCheckpoint (no deserialize) for a presence test. A half-written checkpoint reads as absent, forcing a clean genesis sync.
Initialize dust wallet for an address if not already initialized.
Load the checkpoint (state + cursor) as ONE consistent snapshot. Reads both keys from a single DataStore emission, so the returned pair can never be torn across a concurrent write. Returns null if EITHER half is missing or the state fails to deserialize — callers then fall back to genesis rather than resuming on a half-checkpoint. The returned DustCheckpoint.state is owned by the caller and must be closed.
Deserializes DustLocalState for use in fee payment.
Mark dust tokens as available (unlock after transaction failure).
Mark dust tokens as pending (lock for transaction).
Mark dust tokens as spent (transaction confirmed).
Observe dust balance for an address (live updates).
Persist state and its resume cursor lastEventId as ONE atomic unit.
Save last applied dust event ID (for delta sync resume).
Saves updated DustLocalState after creating spends.
Sync dust tokens from DustLocalState to database cache.