Skip to content

Add optional buyer-selected payout via pluggable Lightning-to-onchain swap provider (Boltz MVP) #749

@ermeme

Description

@ermeme

Summary

Add support for optional buyer-selected payout to Bitcoin onchain using a pluggable swap provider.

This proposal is intentionally scoped to the Lightning -> onchain direction and uses Boltz for the MVP. The design must remain provider-agnostic so we can swap Boltz out later without changing the order flow.

Important: Silent Payments are not in scope for this implementation. They should be considered a future payout format and the design should leave room for them, but this issue only covers Lightning -> onchain via Boltz.

Problem

Today, if a buyer wants to end up with onchain BTC, the flow requires extra manual steps outside Mostro. That adds friction, increases the chance of user error, and makes the user experience less predictable.

We want Mostro to support a payout path where the buyer chooses how they want to receive sats, while keeping the core trade flow clean and non-custodial.

Goals

  • Let the buyer choose their payout preference when creating or taking an order.
  • Support Lightning -> onchain swaps in the MVP.
  • Use Boltz as the first provider.
  • Keep the provider interface generic so the provider can be replaced later.
  • Make fees paid by the buyer.
  • Make min/max limits configurable in settings.toml.
  • If the swap expires, Mostro must ask the buyer for new payout instructions.

Out of scope for this issue

  • Silent Payments execution.
  • Any provider-specific hardcoding that makes Boltz the only possible implementation.
  • Automatic provider fallback / routing across multiple providers.
  • Changing the existing core trade semantics beyond what is needed to support the new payout flow.

Future-proofing requirement

The data model and payout abstraction should be designed so that a future proposal can add payout formats such as Silent Payments without rewriting the whole flow.

Proposed implementation phases

To keep the review manageable, this should be split into small phases. The spec must come first.

Phase 0 — Technical spec / design doc

Create a short spec that defines:

  • payout methods and their lifecycle
  • state machine transitions
  • provider interface
  • persistence fields
  • config keys in settings.toml
  • error / expiry / retry behavior
  • what happens when the buyer needs to provide new instructions after expiry
  • how the design remains compatible with future payout formats like Silent Payments

Exit criteria: spec reviewed and approved before implementation starts.

Phase 1 — Domain model and config plumbing

Implement the minimal data model changes:

  • buyer payout preference on the order/trade model
  • swap metadata persistence
  • configurable min/max limits and provider selection in settings.toml
  • validation for the selected payout mode

Exit criteria: the system can store and validate payout preferences without executing a swap.

Phase 2 — Provider abstraction

Introduce a provider-agnostic interface for swap operations, for example:

  • quote request
  • swap creation
  • status polling / updates
  • expiry handling
  • optional cancel / cleanup hooks

Exit criteria: the order flow talks to an interface, not directly to Boltz.

Phase 3 — Boltz MVP adapter

Implement the first concrete provider adapter using Boltz for Lightning -> onchain swaps:

  • quote and swap creation
  • status tracking
  • fee calculation / display
  • limits enforcement
  • proper verification of returned data

Exit criteria: an end-to-end Boltz swap can be executed in the happy path.

Phase 4 — Order-flow integration and fallback handling

Wire the provider into the Mostro order lifecycle:

  • create/take order with payout preference
  • buyer pays the swap fee
  • handle timeout / expiry
  • if the swap expires, request new payout instructions from the buyer
  • keep the order state machine consistent

Exit criteria: the trade flow handles success, expiry, and recovery without leaving the order in an inconsistent state.

Phase 5 — Tests, docs, and review cleanup

Add coverage and docs:

  • unit tests for the provider abstraction and state machine
  • integration tests for the Boltz path
  • config examples and operator notes
  • user-facing messaging for failure/expiry paths

Exit criteria: reviewable, documented, and regression-covered.

Technical notes

  • Keep the provider contract narrow and explicit.
  • Avoid Boltz-specific fields leaking into core domain objects.
  • Prefer deterministic state transitions and persisted swap metadata.
  • Ensure the code path can support a future Silent Payments proposal without redesigning the whole feature.

Open questions for the spec

  • Should the buyer choose payout method when creating the order, taking the order, or both?
  • Which states should be added to the order lifecycle?
  • What exact data do we persist for quotes and swaps?
  • How should the UI/API request a new payout instruction after expiry?
  • Which parts belong in core Mostro vs provider adapter?
  • What is the minimum surface area needed to support future payout formats like Silent Payments?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions