Skip to content

feat(cashu): Track C — cooperative cancel in Cashu mode#764

Open
ifuensan wants to merge 2 commits into
MostroP2P:feat/cashu-mostro-core-0.12from
ifuensan:feat/cashu-mostro-core-0.12
Open

feat(cashu): Track C — cooperative cancel in Cashu mode#764
ifuensan wants to merge 2 commits into
MostroP2P:feat/cashu-mostro-core-0.12from
ifuensan:feat/cashu-mostro-core-0.12

Conversation

@ifuensan
Copy link
Copy Markdown

@ifuensan ifuensan commented May 30, 2026

Track C · Cooperative cancel (Cashu 2-of-3 escrow)

Wires cooperative cancel for Cashu escrow mode, per docs/CASHU_ESCROW_ARCHITECTURE.md. In Cashu mode Mostro is only a coordinator and never takes custody, so there is no hold invoice to cancel: the daemon records the cancel and transitions state, while the buyer hands their signature to the seller P2P (NIP-59 DM) so the seller reconstructs a P_S + P_B 2-of-3 swap to reclaim the locked ecash. Lightning behavior is unchanged.

Depends on F1 (mostro-core protocol) and F3 (EscrowBackend seam). Independent of Tracks A/B/D.

What's in this PR

  • src/app/cancel.rs
    • New return_escrow_to_seller helper: the single place that returns escrowed funds on a cancel. Lightning cancels the seller's hold invoice (custodial); Cashu is a no-op (non-custodial, P2P reclaim). All three cancel sites (cooperative, taker-cancel, maker-cancel) route through it, so fund-return follows one consistent mode rule.
    • New cancel_action_cashu entry point: drives the same cancel state machine without an LND client, using a no-op CashuBackend as the CancelLightning impl.
  • src/app.rsrun_cashu now routes Action::Cancel to cancel_action_cashu instead of rejecting it with InvalidAction. Other trade actions (NewOrder/TakeSell/TakeBuy/AddInvoice/Release/Admin*) stay rejected until their tracks land.

Notes

  • No new mostro-core actions/payloads: the cancel signature is exchanged client↔client over NIP-59, never relayed through Mostro.
  • A follow-up consolidation PR can converge cancel/release onto the F3 EscrowBackend trait (today cancel.rs uses the older local CancelLightning trait) once Tracks A/B/D are in and the full pattern is visible.

Tests

  • cargo test --bin mostrod cancel green, incl. new cashu_backend_cancel_hold_invoice_is_noop.

Summary by CodeRabbit

  • Bug Fixes

    • Cancelling orders in Cashu mode now routes and completes reliably; cooperative cancels work without external payment services.
    • Escrowed funds from cancelled orders are returned appropriately based on your payment mode.
  • Refactor

    • Cashu client and verification flows were streamlined for more robust mint connectivity and token validation.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 30, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8e1d263a-936a-48b1-94a8-bd5701783bee

📥 Commits

Reviewing files that changed from the base of the PR and between 4d27848 and 0fecce2.

📒 Files selected for processing (3)
  • src/app.rs
  • src/app/cancel.rs
  • src/cashu/mod.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/cancel.rs

Walkthrough

Cashu-mode cancel processing is now supported through a mode-aware escrow abstraction: CashuBackend provides a cancel no-op, cancel paths use return_escrow_to_seller, and run_cashu dispatches Action::Cancel to cancel_action_cashu which injects CashuBackend (no LND).

Changes

Cashu-mode cancel routing with escrow abstraction

Layer / File(s) Summary
Escrow mode abstraction and CashuBackend implementation
src/app/cancel.rs
Imports include Settings/EscrowMode. CashuBackend implements CancelLightning::cancel_hold_invoice as a defensive no-op. New return_escrow_to_seller routes escrow returns by mode (cancel hold invoice in Lightning mode; log no-op in Cashu). Unit test asserts no-op returns Ok(()).
Cancel paths refactored to use escrow helper
src/app/cancel.rs
Cooperative cancel step 2, taker cancel, and maker cancel flows replace direct hold-invoice cancellation with return_escrow_to_seller, centralizing mode-dependent escrow-return logic.
Cashu-mode dispatcher and public entrypoint
src/app.rs, src/app/cancel.rs
src/app.rs imports cancel_action_cashu, updates run_cashu docs and dispatch to route Action::Cancel to it (removing Cancel from the unsupported-escrow list). Adds pub async fn cancel_action_cashu(...) which verifies EscrowMode::Cashu and runs the generic cancel router with an injected CashuBackend. Includes a test that it errors outside Cashu mode.
Cashu client wiring and verification cleanup
src/cashu/mod.rs
CashuClient no longer stores mint_url; connect is linearized to build the HTTP client then perform mint info check. verify_2of3_condition, check_state, verify_token_dleq, and sign_with_pm are reformatted/clarified while preserving existing validation and verification behavior.

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

  • MostroP2P/mostro#760: Extends the Cashu/LN escrow abstraction; related to the EscrowBackend/CashuBackend seam used here.
  • MostroP2P/mostro#758: Introduced Cashu no-LN event loop wiring that this PR routes Action::Cancel through.
  • MostroP2P/mostro#428: Overlaps in cancel/hold-invoice logic in src/app/cancel.rs.

Suggested reviewers

  • grunch
  • ermeme

Poem

🐰
I hop through code with tiny paws,
Routing cancels without a fuss or claws.
Cashu nods, Lightning lets go—
Helper directs the graceful flow.
A carrot cheer for routing laws.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective: implementing cooperative cancel for Cashu escrow mode, which is the primary focus across all three modified files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

@ifuensan
Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 30, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@ifuensan
Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/app.rs (1)

398-403: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update run_cashu's contract comment.

This branch now handles Action::Cancel, but the run_cashu doc block above still says cancel falls through and is ignored. Please refresh it so the public API description matches the dispatch table. As per coding guidelines "Document non-obvious public APIs with /// doc comments".

Also applies to: 460-471

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app.rs` around lines 398 - 403, Update the doc comment for the public
function run_cashu so it accurately reflects the current dispatch behavior:
state that Action::Cancel is now handled (via handle_message_action_no_ln)
instead of falling through/being ignored, and clarify which actions still fall
through to the `_` arm (e.g., Release, AdminCancel, AdminSettle) until
EscrowBackend is implemented; make the same wording update in the other similar
doc block that describes the cashu-mode event loop so the public API docs match
the actual dispatch table.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/app/cancel.rs`:
- Around line 521-528: Add an upfront mode guard in cancel_action_cashu to fail
fast when the app is not running in Cashu-only escrow mode: before calling
cancel_action_generic, check Settings::escrow_mode() (or the app config
accessor) and return an appropriate MostroError (or Err variant) if the mode is
not the Cashu variant; this prevents injecting CashuBackend and proceeding when
Lightning mode is configured and ensures you don’t noop cancel_hold_invoice
while marking an order canceled.

---

Outside diff comments:
In `@src/app.rs`:
- Around line 398-403: Update the doc comment for the public function run_cashu
so it accurately reflects the current dispatch behavior: state that
Action::Cancel is now handled (via handle_message_action_no_ln) instead of
falling through/being ignored, and clarify which actions still fall through to
the `_` arm (e.g., Release, AdminCancel, AdminSettle) until EscrowBackend is
implemented; make the same wording update in the other similar doc block that
describes the cashu-mode event loop so the public API docs match the actual
dispatch table.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1bcf5c0e-16bb-4dee-8c6e-4a1d8b883e0d

📥 Commits

Reviewing files that changed from the base of the PR and between c445946 and 4d27848.

📒 Files selected for processing (2)
  • src/app.rs
  • src/app/cancel.rs

Comment thread src/app/cancel.rs
@AndreaDiazCorreia
Copy link
Copy Markdown
Member

@codex review

@ifuensan ifuensan force-pushed the feat/cashu-mostro-core-0.12 branch from 4d27848 to 998b88d Compare May 31, 2026 13:49
Copy link
Copy Markdown
Contributor

@mostronatorcoder mostronatorcoder Bot left a comment

Choose a reason for hiding this comment

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

I reviewed the current head of this PR and I am requesting changes.

There are two blocking issues.

  1. CI / quality bar: clippy is red on this branch.

cargo clippy --all-targets --all-features -- -D warnings fails in src/cashu/mod.rs, including:

  • dead code on CashuClient::mint_url
  • useless same-type conversions like let err: cdk::error::Error = e.into();
  • Error::Client(cdk::error::Error::from(e))

That alone makes the branch not ready to merge.

  1. The PR claims Cashu mode means "LND not required", but the codebase still has important Lightning-specific paths instantiated directly outside a fully enforced backend seam.

Examples from this head:

  • src/main.rs logs Starting in Cashu escrow mode (LND not required)
  • but src/util.rs still has direct LndConnector::new().await? paths in show_hold_invoice and invoice_subscribe
  • src/app/bond/flow.rs still creates LndConnector directly
  • scheduler jobs are partially gated, but the broader codebase is still in a mixed mode state rather than a fully enforced backend boundary

So even though this PR is much closer than the earlier Cashu groundwork, I still do not think the current state cleanly matches the operational claim that Cashu mode does not require LND. The mode split and the backend seam are still not applied consistently enough for me to approve this yet.

Copy link
Copy Markdown

@ermeme ermeme Bot left a comment

Choose a reason for hiding this comment

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

Code Review Summary

Verdict: Changes Requested

Blocking

  • src/cashu/mod.rs still has clippy failures that will trip the branch quality gate (cargo clippy --all-targets --all-features -- -D warnings). The concrete offenders reported by the existing review are the unused CashuClient::mint_url field and redundant error conversions in connect(), check_state(), and verify_token_dleq(). Please fix those before merge.

Non-blocking

  • The earlier Cashu-mode guard concern appears resolved; I’m not re-flagging it.
  • src/app.rs still has a stale doc comment for run_cashu that says Action::Cancel falls through, even though the branch now handles it explicitly.

@ifuensan ifuensan force-pushed the feat/cashu-mostro-core-0.12 branch from 998b88d to 0fecce2 Compare May 31, 2026 20:48
@ifuensan
Copy link
Copy Markdown
Author

ifuensan commented May 31, 2026

Addressed in the latest push:

  • clippy/fmt red: fixed in a separate commit — dropped the dead mint_url field and the redundant cdk::Error conversions in cashu/mod.rs, ran fmt. clippy --all-targets --all-features -D warnings and fmt --check now green.
  • stale run_cashu doc: updated to match the dispatch table (Cancel handled, the rest rejected with CantDo).
  • mode guard: already in cancel_action_cashu.

On the LND seam: agreed it isn't fully enforced (util.rs/bond/release/scheduler still call LndConnector::new() directly), but that's the F3 EscrowBackend consolidation, not Track C — which only wires cooperative cancel through the existing seam. Proposing to track it as a separate consolidation PR after A/B/D so the tracks don't serialize. OK @grunch ?

@ifuensan
Copy link
Copy Markdown
Author

ifuensan commented Jun 2, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 2, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@ifuensan
Copy link
Copy Markdown
Author

ifuensan commented Jun 2, 2026

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

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.

2 participants