Skip to content

feat(cashu): take flow escrow request + unblock creation — Track A TA-2#830

Open
grunch wants to merge 1 commit into
feat/cashu-ta1-lock-handlerfrom
feat/cashu-ta2-take-flow
Open

feat(cashu): take flow escrow request + unblock creation — Track A TA-2#830
grunch wants to merge 1 commit into
feat/cashu-ta1-lock-handlerfrom
feat/cashu-ta2-take-flow

Conversation

@grunch

@grunch grunch commented Jul 20, 2026

Copy link
Copy Markdown
Member

Stacked on #829 (TA-1) → #828 (CF-5). Review/merge those first; the base retargets as the stack lands. The diff shown is TA-2 only.

What & why

Completes the Cashu lock flow end-to-end with TA-1 (docs/cashu/02-track-a-lock.md §5). A taken order on a cashu node now asks the seller to lock a 2-of-3 escrow instead of paying a hold invoice, and unblocks order creation + the take flow in dispatch_cashu.

Creation and taking ship together: unblocking NewOrder any earlier would populate the book with orders that can never be taken to completion (no escrow) — the orphan-order hazard CF-5's rationale warns about.

Changes

  • util::show_cashu_escrow_request (new, the Cashu analogue of show_hold_invoice): advance the order to WaitingPayment (where the TA-1 CAS expects it), record both trade pubkeys, publish the order event, and enqueue:
    • to the sellerAction::WaitingSellerToPay + Payload::Order(SmallOrder) carrying amount + buyer_trade_pubkey + seller_trade_pubkey (everything the client needs to build the 2-of-3);
    • to the buyer — a bare "waiting for the seller" notice.
  • take_sell / take_buy: early-return through show_cashu_escrow_request when is_cashu_enabled(), skipping the hold-invoice / buyer-invoice path. The buyer redeems ecash directly, so there is no buyer payout invoice (a supplied one is ignored). Lightning path byte-for-byte unchanged.
  • dispatch_cashu: NewOrder/TakeBuy/TakeSellhandle_message_action_no_ln (their real handlers). The CF-5 gate test drops them from the InvalidAction list.

Design notes

  • Amount: the escrow locks order.amount exactly — the Mostro fee is a separate token (Option 2, TA-1f).
  • Mint URL + locktime are not carried in the request payload (the 0.14.0 protocol has no field for them). They are node policy; the daemon enforces them authoritatively when the seller submits (add_cashu_escrow_action §5/§7), so a client funding against the wrong mint or too short a locktime is simply rejected and retries.
  • The escrow request reuses Action::WaitingSellerToPay + Payload::Order (with the trade pubkeys set) — on a cashu node the seller's client reads that as "lock the escrow", the same convention the first-attempt branch used.

Tests

  • show_cashu_escrow_request advances the status to WaitingPayment, records both trade pubkeys, and enqueues the seller escrow request (asserting the Order payload carries the trade pubkeys + bare amount, no buyer invoice) and the buyer notice.

Checklist

  • cargo fmt --check
  • cargo clippy --all-targets --all-features -- -D warnings
  • cargo test — 1027 passed
  • Off-by-default: no behaviour change when Cashu is disabled

Depends on #829 (TA-1), #828 (CF-5). Refs: docs/cashu/02-track-a-lock.md (TA-2).

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (1)
  • develop

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 86b910fa-4c07-42fc-b647-229826597a27

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cashu-ta2-take-flow

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6652b7079f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/util.rs
Comment on lines +1090 to +1092
order_updated
.update(pool)
.await

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Guard Cashu take updates with a CAS

When two TakeBuy/TakeSell events for the same pending Cashu order run concurrently, both handlers can hold a stale Pending copy and reach this unconditional full-row update. If the first request has already let the seller submit AddCashuEscrow and the CAS has advanced the row to Active with cashu_* fields populated, the later stale update can rewrite the row back to WaitingPayment and clear the persisted escrow while notifications have already gone out. The take transition should be conditional on the current status/empty escrow before enqueueing the request, or re-read and abort once the order has moved on.

Useful? React with 👍 / 👎.

Add the Cashu branch to `take_sell_action`/`take_buy_action` and the
`show_cashu_escrow_request` helper (docs/cashu/02-track-a-lock.md §5), and
unblock `NewOrder`/`TakeBuy`/`TakeSell` in `dispatch_cashu`. A taken order on
a cashu node now asks the SELLER to lock a 2-of-3 escrow instead of paying a
hold invoice, leaving the order in `WaitingPayment` where the TA-1 CAS
expects it. Creatable and takeable ship together so the book never fills with
untakeable orders (the orphan-order hazard CF-5 warns about).

- `util::show_cashu_escrow_request`: advance to `WaitingPayment`, record both
  trade pubkeys, publish the order event, and enqueue an escrow request to the
  seller (`Action::WaitingSellerToPay` + `Payload::Order` carrying
  `amount`/`buyer_trade_pubkey`/`seller_trade_pubkey`) plus a bare "waiting for
  the seller" notice to the buyer. The buyer redeems ecash directly, so there
  is no buyer payout invoice. The escrow locks `order.amount` exactly (the fee
  is a separate token in TA-1f); the mint URL + locktime floor are node policy
  the daemon enforces authoritatively at lock validation (TA-1 §5/§7), so they
  are not carried in the request (the 0.14.0 protocol has no field for them).
- `take_sell`/`take_buy`: early-return through `show_cashu_escrow_request` when
  `is_cashu_enabled()`, skipping the hold-invoice / buyer-invoice path. A
  supplied buyer invoice is ignored in Cashu mode. Lightning path unchanged.
- `dispatch_cashu`: route `NewOrder`/`TakeBuy`/`TakeSell` to
  `handle_message_action_no_ln` (their real handlers); the gate test drops them
  from the `InvalidAction` list accordingly.

Test: `show_cashu_escrow_request` advances the status, records both pubkeys,
and enqueues the seller request (with the trade pubkeys + bare amount) and the
buyer notice.

Depends on CF-5 (+ TA-1 for the full e2e lock). Base: feat/cashu-ta1-lock-handler
Refs: docs/cashu/02-track-a-lock.md (TA-2)
@grunch
grunch force-pushed the feat/cashu-ta1-lock-handler branch from e2f032a to 760467f Compare July 21, 2026 01:50
@grunch
grunch force-pushed the feat/cashu-ta2-take-flow branch from 6652b70 to a16c745 Compare July 21, 2026 01:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant