Pay bond invoice
When the receiving Mostro node has the anti-abuse bond feature enabled, makers and/or takers must lock a small Lightning hold invoice as a security deposit before the trade flow proceeds. Mostro asks for this payment with the pay-bond-invoice action.
The bond is independent from the trade escrow: it is a second hold invoice with its own payment hash, and it is released on every normal exit path — completion, cancel before timeout, or dispute resolution where the solver does not direct otherwise. Bonds are typically around 1% of the trade amount (with an operator-configured floor), much smaller than the trade hold invoice that may follow.
The bond_apply_to tag in the Mostro info event (kind 38385) tells clients which sides must post a bond: "take", "make", or "both" — see Other events published by Mostro.
Taker bond
Direction and trigger
- Direction: Mostro → user (the taker).
- Trigger: Sent immediately after a successful
take-buy/take-sellwhen the operator has bonds enabled for takers. - Order status: The published NIP-33 order event keeps the
stag atpendingwhile the bond is outstanding (per NIP-69's four-bucket model — see Peer-to-peer Order events. NIP-69). The DM payload's embeddedSmallOrderecho carries the daemon-internal statuswaiting-taker-bondso the recipient client can render the bond-payment phase distinctly, but external observers (other potential takers, order-book aggregators) continue to see the order aspendingand may still attempt to take it. This is deliberate: a taker who never pays the bond cannot park the order off the book.
Mostro message to the taker
The message's content has the same shape as pay-invoice; only the action discriminator differs:
[
{
"order": {
"version": 1,
"id": "<Order Id>",
"action": "pay-bond-invoice",
"payload": {
"payment_request": [
{
"id": "<Order Id>",
"kind": "sell",
"status": "pending",
"amount": 7851,
"fiat_code": "VES",
"fiat_amount": 100,
"payment_method": "face to face",
"premium": 1,
"created_at": 1698937797
},
"lnbcrt780n1pj59wmepp5..."
]
}
}
},
null
]
Note: the
SmallOrderecho carries"status": "pending"— the NIP-69 wire bucket the order is advertised in while the bond is outstanding. The daemon-internal statewaiting-taker-bond(which Mostro uses to route subsequent messages) is tracked only in the daemon's database and is never emitted in the DM payload. Clients should dispatch on thepay-bond-invoiceaction, not on a status field.
Expected client behaviour
- Decode the bolt11 and surface it to the user explicitly as a bond, not as the trade escrow. Do not reuse the same wording or UI step that you use for
pay-invoice. - Pay it. The HTLC enters
Acceptedstate — the sats are locked in the taker's wallet, not captured. - Do not collapse this into the same UI step as any subsequent
pay-invoiceon the same order. They are independent HTLCs (different payment hashes), and the user must explicitly approve each.
Follow-up flow
Once the bond HTLC is Accepted, Mostro proceeds with the normal trade flow:
- Sell order taken (taker = buyer): order status moves to
waiting-buyer-invoice; the taker next receivesadd-invoiceto provide a payout invoice. - Buy order taken (taker = seller): order status moves to
waiting-payment; the taker next receivespay-invoicefor the trade hold invoice.
Important — buy order taken (seller-as-taker): this is the only flow on which a single user pays two hold invoices in sequence on the same order — first the bond (
pay-bond-invoice), then the trade escrow (pay-invoice). They arrive as distinct actions and must be presented to the user as separate steps. Do not auto-pay either, do not coalesce them, and make the distinction obvious in the UI; this is the most error-prone path for client developers.
Daemon status waiting-taker-bond (internal only)
Mostro tags the order's internal state as waiting-taker-bond so it can route subsequent messages correctly while one or more taker bonds are outstanding. This status lives only in the daemon's database — it is neither published on the NIP-33 order event (whose s tag stays pending) nor echoed in any DM payload (the pay-bond-invoice SmallOrder carries pending, as shown above). It is documented here only to describe the daemon's lifecycle; clients never observe the literal waiting-taker-bond value on the wire.
Internal transitions (not visible to clients):
- From
pending→waiting-taker-bond, after a successfultake-buy/take-sellwhen bonds are enabled. - From
waiting-taker-bond→waiting-payment(buy order taken) or →waiting-buyer-invoice(sell order taken), once the bond HTLC isAccepted. - From
waiting-taker-bond→pending, if the bond bolt11 is never paid and expires, or the taker cancels before locking. The publishedstag waspendingthroughout — observers see only that the take attempt left no trace.
Failure modes
- The user never pays the bond bolt11 → the invoice expires; the order's NIP-33 status was
pendingthroughout, so the rollback only undoes the daemon-internal take state. The order remains takeable. - The user pays the bond and then cancels before trade completion → the bond HTLC is cancelled and the funds return to the taker.
- Slashing conditions (solver-directed dispute resolution, or timeout while in a waiting state) can settle the bond rather than release it. The solver directs slashing via the
bond_resolutionpayload documented under Admin Settle order and Admin Cancel order, and the non-slashed counterparty is then asked for their share of the bond via Bond payout invoice. When a timeout slash fires, the slashed party first receives abond-slashednotification.
Maker bond
When apply_to is "make" or "both", the maker must lock a bond before the order is published to Nostr. The same pay-bond-invoice action is used, but the trigger and the order lifecycle differ from the taker case.
Direction and trigger
- Direction: Mostro → user (the maker).
- Trigger: Sent in response to a
new-ordermessage when the operator has bonds enabled for makers, before the order is published. - Order visibility: The order is not published to Nostr while the maker bond is outstanding. External observers see nothing — no
pendingorder event, no order in the book. This differs from the taker bond, where the order remains visible and re-takeable throughout. The daemon tracks this internally aswaiting-maker-bond, a status kept in its database only — it is never emitted on the wire (theSmallOrderecho carriespending, as shown below).
Mostro message to the maker
The action and wire shape are identical to the taker case:
[
{
"order": {
"version": 1,
"id": "<Order Id>",
"action": "pay-bond-invoice",
"payload": {
"payment_request": [
{
"id": "<Order Id>",
"kind": "sell",
"status": "pending",
"amount": 7851,
"fiat_code": "VES",
"fiat_amount": 100,
"payment_method": "face to face",
"premium": 1,
"created_at": 1698937797
},
"lnbcrt780n1pj59wmepp5..."
]
}
}
},
null
]
Note: the
SmallOrderecho always carries"status": "pending"— this is the NIP-69 wire bucket the order will appear in once the bond locks and the order is published. The daemon-internal statewaiting-maker-bondis tracked only in the daemon's database and is never emitted in DM payloads. No NIP-33 order event has been emitted yet at this point.
For range sell orders, the bond is sized against max_amount (not the individual fiat_amount). The SmallOrder echo will reflect the range order fields (min_amount, max_amount).
Follow-up after bond locks
Once the maker's bond HTLC is Accepted:
- Mostro publishes the order to Nostr with status
pendingfor the first time. - Mostro sends the maker the
new-orderconfirmation message (same as in the no-bond flow — see Creating a new sell order and Creating a new buy order).
Daemon status waiting-maker-bond (internal only)
Like waiting-taker-bond, this status lives only in the daemon's database — it is never published on a NIP-33 event (none exists yet) nor echoed in any DM payload (the pay-bond-invoice SmallOrder carries pending). It is documented here only to describe the daemon's lifecycle.
Internal transitions (not visible to clients):
- On
new-orderreceipt →waiting-maker-bond, before any NIP-33 event is emitted. waiting-maker-bond→pending(and order published), once the bond HTLC isAccepted.waiting-maker-bonddiscarded (no NIP-33 ever emitted), if the bond invoice expires without payment.
Failure modes
- Maker never pays → invoice expires, order discarded silently. No NIP-33 event was ever emitted so the order book is unaffected.
- Maker pays the bond, order publishes as
pending, then maker cancels → bond HTLC released, funds return to maker. - A waiting-state timeout slash (when
slash_on_waiting_timeout = true) settles the maker's bond HTLC instead of releasing it. The maker first receives abond-slashednotification, then the order is canceled. The winning counterparty (the taker) then receivesadd-bond-invoicefor their share.
Backwards compatibility
Clients running an older mostro-core version that does not yet know pay-bond-invoice will fail to deserialize the message and silently drop it; from the user's perspective the operation stalls and eventually times out without surfacing a useful error. Operators are responsible for not enabling bonds in production until clients in the wild have adopted the mostro-core release that ships Action::PayBondInvoice. Clients should:
- Recognise the action explicitly and surface it to the user.
- If unable to handle it (e.g. an older build talking to a bond-enabled node), present a clear error rather than silently retrying.
The Mostro info event carries bond-related tags so clients can detect bond-enabled nodes ahead of a take or create — see Other events published by Mostro.