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": 2,
"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,
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 (afterhold_invoice_expiration_windowseconds, see Failure modes), or the taker cancels before locking, and no other taker's bond is still outstanding. Otherwise the order stays inwaiting-taker-bondwhile the remaining bonds race. 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
hold_invoice_expiration_windowseconds after it was issued, the value the node advertises in its info event. From then on the Lightning node refuses any payment on it. Mostro releases the bond and, if no other taker's bond is still outstanding, returns the order topendingand republishes its event with the same tags (a range order keepsamt"0"andfa[min, max]). The order's NIP-33 status waspendingthroughout, so the rollback only undoes the daemon-internal take state, and the order remains takeable.The taker receives no message when this happens. A client should treat the bolt11's expiry as the end of the take and let the user take the order again.
If the daemon misses the Lightning node's cancel (for example across a restart), a periodic check releases a bond left unpaid past
hold_invoice_expiration_windowwithin a few minutes. Nodes that predate the expiry issued taker bond invoices with the Lightning node's default expiry (24 hours on LND); on those, the invoice may stay payable long after the window. -
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": 2,
"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,
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).
Deadline to pay
The maker bond hold invoice expires after the node's maker-bond payment timeout (operator setting maker_bond_payment_timeout_seconds, 900 seconds by default). The node does not advertise this timeout in its info event; a client reads it from the bolt11's expiry and can show the maker a countdown.
When the deadline passes, the Lightning node refuses any payment on the invoice, and Mostro closes the order as expired (in its database only), releases the bond and sends the maker canceled:
[
{
"order": {
"version": 2,
"id": "<Order Id>",
"action": "canceled",
"payload": null
}
},
null,
null
]
The message answers no request of the maker's, so it carries no request_id. A client should end the bond-payment screen when it arrives, or at the bolt11's expiry if it never does. Nodes that predate the deadline issued maker bond invoices with the Lightning node's default expiry (24 hours on LND), kept the order until its expires_at, and sent the maker nothing.
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-bond→expired, if the maker does not pay before the deadline, or the order reaches itsexpires_atfirst.waiting-maker-bond→canceled, if the maker sendscancelbefore paying.waiting-maker-bond→canceled-by-admin, if the operator cancels it.
None of the last three emits a NIP-33 event: the order was never published, so there is nothing to replace. Each releases the bond, which cancels its hold invoice. A bond that already locked wins over all three: its order is published as pending, and the maker then handles it as a published order.
Failure modes
- Maker never pays → at the deadline the invoice expires, the order closes as
expiredand the maker receivescanceled. No NIP-33 event was ever emitted, so the order book is unaffected. - Maker changes their mind before paying → the maker sends
cancel; the bond invoice is canceled and the order closes ascanceled, again without any NIP-33 event. - 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.