swap orders as a state machine persisted in sqlite, resumed on restart #39

Open
opened 2026-09-15 12:40:28 +00:00 by grenade · 1 comment
Owner

Parent: #7

Scope

An Order in wallet-entities and a state machine in wallet-core (Quoted → AwaitingDeposit → Processing → Success | Refunded | Failed, with Expired on the quote deadline), persisted by wallet-data in SQLite, polled with backoff while non-terminal, and resumed on app start. Deposits the wallet makes itself (a Quantus leg, later) record the tx hash and call deposit/submit.

Acceptance

Kill the app mid-order; on restart the order is still there and reaches its terminal state. A quote past its deadline shows as expired without a network call.

Depends on

The 1Click client.

Parent: #7 ## Scope An `Order` in `wallet-entities` and a state machine in `wallet-core` (`Quoted → AwaitingDeposit → Processing → Success | Refunded | Failed`, with `Expired` on the quote deadline), persisted by `wallet-data` in SQLite, polled with backoff while non-terminal, and resumed on app start. Deposits the wallet makes itself (a Quantus leg, later) record the tx hash and call `deposit/submit`. ## Acceptance Kill the app mid-order; on restart the order is still there and reaches its terminal state. A quote past its deadline shows as expired without a network call. ## Depends on The 1Click client.
grenade added the child label 2026-09-15 12:41:49 +00:00
Author
Owner

Built: wallet_core::orders (the state machine, unit-tested for forward-only moves, expiry without a network call, and the backoff schedule), an OrderStore port on the SQLite file, and the follower in crates/wallet-app/src/swap.rs that resumes every open order at start and polls with backoff and jitter, persisting each move and emitting orders:updated.

What is not yet exercised end to end: a real order. 1Click answers dry quotes without a credential but refuses a wet one (400 Failed to get quote), so no deposit address can be reserved until the partner JWT exists and the relay (#40) attaches it. The "kill the app mid-order" acceptance runs the moment one real order exists; the store and the resume path it needs are in place and tested at the unit level. Leaving this open for that.

Built: `wallet_core::orders` (the state machine, unit-tested for forward-only moves, expiry without a network call, and the backoff schedule), an `OrderStore` port on the SQLite file, and the follower in `crates/wallet-app/src/swap.rs` that resumes every open order at start and polls with backoff and jitter, persisting each move and emitting `orders:updated`. What is not yet exercised end to end: a real order. 1Click answers dry quotes without a credential but refuses a wet one (`400 Failed to get quote`), so no deposit address can be reserved until the partner JWT exists and the relay (#40) attaches it. The "kill the app mid-order" acceptance runs the moment one real order exists; the store and the resume path it needs are in place and tested at the unit level. Leaving this open for that.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: blackbeard/wallet#39