Skip to content

004 mostro p2p client - #59

Merged
grunch merged 4 commits into
mainfrom
004-mostro-p2p-client
Mar 30, 2026
Merged

004 mostro p2p client#59
grunch merged 4 commits into
mainfrom
004-mostro-p2p-client

Conversation

@grunch

@grunch grunch commented Mar 30, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features
    • Lightning invoice payment screen with QR code, copy and share actions
    • Wallet payment option with a full-width "Pay with Wallet" button
    • Seller trade workflow enhancements: Release, Cancel, Dispute, Contact actions
    • Release confirmation dialog when finalizing Bitcoin release
  • Chores
    • Enabled system sharing and URL handling support across platforms (share/launch)

grunch added 2 commits March 30, 2026 09:48
…tion

Rust:
- orders.rs: release_order(order_id) with FiatSent state validation

Dart:
- PayLightningInvoiceScreen: QR code via qr_flutter, copy/share
  buttons, cancel button, dev simulate-payment button
- NwcPaymentWidget: "Pay with Wallet" button stub (Phase 14)
- PayLightningInvoiceWidget: reusable QR + copy + share component
- ReleaseConfirmationDialog: centered modal with info icon,
  "Release Bitcoin" title, No/Yes buttons
- TradeDetailScreen: extended for seller flow — Active state shows
  CLOSE/CANCEL/DISPUTE/CONTACT; Fiat Sent shows RELEASE button
  with confirmation dialog → navigate to rate screen; updated
  _getInstructionText for seller-specific messages
- app_routes: wired PayLightningInvoiceScreen at /pay_invoice/:orderId
QR accessibility

- pay_lightning_invoice_widget: remove unused onSubmit/onCancel
  callbacks; await Clipboard.setData with mounted check
- pay_lightning_invoice_screen: await Clipboard.setData with mounted
  check; add semanticsLabel to QR code
@coderabbitai

coderabbitai Bot commented Mar 30, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@grunch has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 20 minutes and 50 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 20 minutes and 50 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dd6a57c8-626e-4fd7-a1ce-8b710b93ffae

📥 Commits

Reviewing files that changed from the base of the PR and between 48e8517 and 2a18c5b.

📒 Files selected for processing (1)
  • specs/004-mostro-p2p-client/tasks.md

Walkthrough

Replaces a route stub with a real PayLightningInvoice screen, adds UI/widgets for Lightning/NWC payments and a release confirmation dialog, extends trade-detail seller flows, adds Mostro fiat_sent/release action builders and a Rust release_order endpoint, updates specs, and registers/share+url plugins and dependency.

Changes

Cohort / File(s) Summary
Routing
lib/core/app_routes.dart
Replaced AppRoute.payInvoice stub with PayLightningInvoiceScreen builder extracting orderId from path parameters.
Screens — Buyer/Seller Flows
lib/features/order/screens/pay_lightning_invoice_screen.dart, lib/features/trades/screens/trade_detail_screen.dart
Added PayLightningInvoiceScreen (QR, copy/share, dev simulate). Expanded trade detail to render seller-specific instructions and action buttons (CLOSE, CANCEL, DISPUTE, CONTACT, RELEASE) and wire RELEASE -> confirmation -> navigation.
Widgets — Payment UI
lib/shared/widgets/pay_lightning_invoice_widget.dart, lib/shared/widgets/nwc_payment_widget.dart
Added PayLightningInvoiceWidget (QR, copy/share) and NwcPaymentWidget (Pay with Wallet button, stubbed NWC call with fallback callback).
Dialog
lib/features/trades/widgets/release_confirmation_dialog.dart
Added showReleaseConfirmationDialog() and _ReleaseConfirmationDialog UI returning bool confirmation.
Rust — Mostro & Orders API
rust/src/mostro/actions.rs, rust/src/api/orders.rs
Added Mostro action builders fiat_sent and release (NIP-59 gift-wrap). send_fiat_sent now builds the message. Added release_order(order_id) endpoint validating state and constructing release message (publishing TODO).
Specs / Tasks
specs/004-mostro-p2p-client/tasks.md
Marked T061–T068 updated/completed with notes about stubs, wiring gaps, and TODOs.
Platform plugin registration
linux/flutter/generated_plugin_registrant.cc, linux/flutter/generated_plugins.cmake, macos/Flutter/GeneratedPluginRegistrant.swift, windows/flutter/generated_plugin_registrant.cc, windows/flutter/generated_plugins.cmake
Registered/added url_launcher and share_plus platform plugins across desktop targets and updated generated CMake lists.
Dependency
pubspec.yaml
Added share_plus: ^12.0.1 dependency.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Seller as Seller (UI)
    participant TradeDetail as TradeDetailScreen
    participant ReleaseDialog as ReleaseConfirmationDialog
    participant RustAPI as Release API (Rust)
    participant Rating as RatingScreen

    Seller->>TradeDetail: Tap RELEASE (seller, fiatSent)
    TradeDetail->>ReleaseDialog: showReleaseConfirmationDialog()
    ReleaseDialog->>Seller: Display modal (Yes/No)
    Seller->>ReleaseDialog: Confirm (Yes)
    ReleaseDialog-->>TradeDetail: return true
    TradeDetail->>RustAPI: call release_order(orderId)
    RustAPI-->>TradeDetail: Result<()>
    alt success
        TradeDetail->>Rating: Navigate to /rate_user/:orderId
    else failure
        TradeDetail->>Seller: Show error SnackBar
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

Poem

🐰 I hopped to the QR with a twitchy nose,

bolts and invoices in neat little rows.
Copy, share, then confirm with a cheer—
Release the sats, the rating draws near.
A rabbit applauds the trade's brave new pose.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title '004 mostro p2p client' is overly vague and generic, referencing only a spec document number without describing the actual changes made in the pull request. Consider a more descriptive title that captures the main functionality added, such as 'Add seller flow for Lightning invoice payment and order release' or similar.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 004-mostro-p2p-client

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

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

⚠️ Outside diff range comments (1)
lib/features/trades/screens/trade_detail_screen.dart (1)

46-50: ⚠️ Potential issue | 🔴 Critical

The new seller branches are dead code right now.

_isBuyer is hard-coded to true and _status is still a local mock, so the seller-only active/fiatSent branches below never render from real trade data. As-is the screen always boots into the buyer flow, which blocks the RELEASE UI entirely.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/features/trades/screens/trade_detail_screen.dart` around lines 46 - 50,
The screen currently hardcodes TradeStatus _status = TradeStatus.active and bool
_isBuyer = true which makes all seller-only branches dead; update
TradeDetailScreen to source real state instead of mocks by wiring _status and
_isBuyer to the actual trade provider / Rust bridge data (e.g., read from the
Trade model or provider inside initState/build or subscribe to the provider) and
remove the temporary hard-coded defaults/ignore comment so the UI uses the real
TradeStatus and buyer/seller flag (references: _status, _isBuyer, TradeStatus,
and the seller-specific branches in TradeDetailScreen) ensuring seller
active/fiatSent branches can render.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/features/order/screens/pay_lightning_invoice_screen.dart`:
- Around line 26-39: The screen is using a hardcoded _mockInvoice and only
advances via _simulatePaymentDetected, so replace the mock flow with real
invoice loading and real payment detection: fetch the invoice for widget.orderId
when the screen initializes (replace uses of _mockInvoice in QR/copy/share with
the fetched invoice string), implement payment confirmation by subscribing to
the real payment signal or polling the order/payment status and call
context.go(AppRoute.tradeDetailPath(widget.orderId)) only after a verified
payment, and keep _simulatePaymentDetected/_waiting behind a debug flag or
remove it entirely; update any UI bindings that reference _mockInvoice or
_waiting to use the new invoice and confirmed-payment state.

In `@lib/features/trades/screens/trade_detail_screen.dart`:
- Around line 403-415: The onPressed handler currently awaits
showReleaseConfirmationDialog then waits a fixed 500ms and navigates to
AppRoute.rateUserPath(widget.orderId) without calling the Rust release_order()
API or waiting for the SettledHoldInvoice/Success stream; replace the fixed
delay with an actual call to the Rust bridge release_order(orderId) (or the
appropriate method used in your bridge), await its result or subscribe to the
streamed SettledHoldInvoice/Success event and only navigate when the release is
confirmed successful, keeping the context.mounted guard before calling
context.push(AppRoute.rateUserPath(widget.orderId)); ensure errors from
release_order() are handled (show error/abort navigation) and remove the TODO
and artificial delay.

In `@lib/shared/widgets/nwc_payment_widget.dart`:
- Around line 32-47: The _pay() implementation always falls back to manual;
change it so after calling the NWC payment API (replace the placeholder
Future.delayed with the actual nwc_api.pay_invoice(bolt11) Rust bridge call
inside _pay()), check the result and on successful payment invoke
widget.onPaymentSuccess() (or the appropriate success callback) instead of
widget.onFallbackToManual(), and only call widget.onFallbackToManual() in the
error branch or when the API indicates failure; keep the existing mounted checks
and the finally block that sets _paying back to false.

In `@lib/shared/widgets/pay_lightning_invoice_widget.dart`:
- Around line 78-84: The Share button in the FilledButton.icon currently only
shows a "coming soon" Snackbar; replace this no-op with a real system share
invocation (or hide/disable the button until implemented). Locate the
FilledButton.icon in pay_lightning_invoice_widget.dart (inside the
PayLightningInvoiceWidget / build method) and update its onPressed to call the
platform share API (e.g., use the share_plus package and call
Share.share(invoiceText) asynchronously), include necessary import and error
handling (try/catch and a Snackbar on failure), and ensure the button is
disabled or hidden when there is no invoice string available.

In `@rust/src/api/orders.rs`:
- Around line 347-365: The release_order function currently aborts after
validating order.status == OrderStatus::FiatSent by returning a hard
NotImplemented error; replace that with real dispatch: construct the Release
MostroMessage for the given order_id, wrap it according to NIP-59, publish/send
it to the Mostro daemon using the existing messaging/publish helper used
elsewhere in the repo, and then return Ok(()) (or handle/propagate publish
errors as Err). Locate release_order, the order_book() call and
OrderStatus::FiatSent check to insert the message construction/wrapping and the
publish call so the seller release flow actually sends the Release message and
allows the daemon to perform the SettledHoldInvoice → Success transition.

In `@specs/004-mostro-p2p-client/tasks.md`:
- Around line 211-218: The review points out T061–T068 are still stubbed: remove
dev mocks and wire real flows — replace the mock invoice and dev-bypass in
pay_lightning_invoice_screen.dart so it fetches the real invoice for :orderId
and uses the real decision path (use NwcPaymentWidget when NWC configured,
otherwise show pay_lightning_invoice_widget); implement NwcPaymentWidget
(lib/shared/widgets/nwc_payment_widget.dart) to call
nwc_api.pay_invoice(bolt11), show a loading spinner, and call onPaymentSuccess
or onFallbackToManual based on the Rust result; implement
pay_lightning_invoice_widget
(lib/shared/widgets/pay_lightning_invoice_widget.dart) to perform actual
copy/share and call onSubmit/onCancel rather than stubbing; implement
release_order(order_id) in rust/src/api/orders.rs to send the Release
MostroMessage, transition trade status to SettledHoldInvoice→Success and emit
on_trade_updated(order_id); and update the RELEASE button handler in
trade_detail_screen.dart to call release_order, show reactive loading, handle
success by navigating to /rate_user/:orderId, and surface errors instead of
using fixed delays or NotImplemented stubs.

---

Outside diff comments:
In `@lib/features/trades/screens/trade_detail_screen.dart`:
- Around line 46-50: The screen currently hardcodes TradeStatus _status =
TradeStatus.active and bool _isBuyer = true which makes all seller-only branches
dead; update TradeDetailScreen to source real state instead of mocks by wiring
_status and _isBuyer to the actual trade provider / Rust bridge data (e.g., read
from the Trade model or provider inside initState/build or subscribe to the
provider) and remove the temporary hard-coded defaults/ignore comment so the UI
uses the real TradeStatus and buyer/seller flag (references: _status, _isBuyer,
TradeStatus, and the seller-specific branches in TradeDetailScreen) ensuring
seller active/fiatSent branches can render.
🪄 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: ce971e4c-051c-4c2f-9b3d-84b9c9d99ee9

📥 Commits

Reviewing files that changed from the base of the PR and between 541fa34 and a8699c4.

📒 Files selected for processing (8)
  • lib/core/app_routes.dart
  • lib/features/order/screens/pay_lightning_invoice_screen.dart
  • lib/features/trades/screens/trade_detail_screen.dart
  • lib/features/trades/widgets/release_confirmation_dialog.dart
  • lib/shared/widgets/nwc_payment_widget.dart
  • lib/shared/widgets/pay_lightning_invoice_widget.dart
  • rust/src/api/orders.rs
  • specs/004-mostro-p2p-client/tasks.md

Comment thread lib/features/order/screens/pay_lightning_invoice_screen.dart Outdated
Comment on lines +403 to +415
onPressed: () async {
final confirmed =
await showReleaseConfirmationDialog(context);
if (confirmed != true || !context.mounted) return;
// TODO: Call release_order() via Rust bridge.
await Future.delayed(
const Duration(milliseconds: 500),
);
if (context.mounted) {
context.push(
AppRoute.rateUserPath(widget.orderId),
);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Don’t navigate to rating before the release actually succeeds.

This handler waits 500 ms and pushes /rate_user/:orderId without calling the Rust release_order() API or waiting for a streamed SettledHoldInvoice/Success update. That lets the UI report a completed release even when no sats were released.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/features/trades/screens/trade_detail_screen.dart` around lines 403 - 415,
The onPressed handler currently awaits showReleaseConfirmationDialog then waits
a fixed 500ms and navigates to AppRoute.rateUserPath(widget.orderId) without
calling the Rust release_order() API or waiting for the
SettledHoldInvoice/Success stream; replace the fixed delay with an actual call
to the Rust bridge release_order(orderId) (or the appropriate method used in
your bridge), await its result or subscribe to the streamed
SettledHoldInvoice/Success event and only navigate when the release is confirmed
successful, keeping the context.mounted guard before calling
context.push(AppRoute.rateUserPath(widget.orderId)); ensure errors from
release_order() are handled (show error/abort navigation) and remove the TODO
and artificial delay.

Comment on lines +32 to +47
Future<void> _pay() async {
setState(() => _paying = true);
try {
// TODO: Call nwc_api.pay_invoice(bolt11) via Rust bridge.
await Future.delayed(const Duration(seconds: 1));

if (!mounted) return;
// Placeholder — fall back to manual until NWC is wired.
widget.onFallbackToManual();
} catch (e) {
debugPrint('NWC payment failed: $e');
if (!mounted) return;
widget.onFallbackToManual();
} finally {
if (mounted) setState(() => _paying = false);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

onPaymentSuccess can never fire from this widget.

Even on the no-error path, _pay() waits and then calls onFallbackToManual(). Once this is wired into a screen, it will always force the manual path instead of ever surfacing an NWC payment success.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/shared/widgets/nwc_payment_widget.dart` around lines 32 - 47, The _pay()
implementation always falls back to manual; change it so after calling the NWC
payment API (replace the placeholder Future.delayed with the actual
nwc_api.pay_invoice(bolt11) Rust bridge call inside _pay()), check the result
and on successful payment invoke widget.onPaymentSuccess() (or the appropriate
success callback) instead of widget.onFallbackToManual(), and only call
widget.onFallbackToManual() in the error branch or when the API indicates
failure; keep the existing mounted checks and the finally block that sets
_paying back to false.

Comment thread lib/shared/widgets/pay_lightning_invoice_widget.dart
Comment thread rust/src/api/orders.rs Outdated
Comment thread specs/004-mostro-p2p-client/tasks.md Outdated
…dling

Add release() and fiat_sent() action builders to mostro/actions.rs
following the existing take_buy/take_sell pattern. Wire release_order()
and send_fiat_sent() in orders.rs to build NIP-59 wrapped messages
instead of returning NotImplemented errors.

Add share_plus dependency and replace "coming soon" share button stubs
with real system share sheet invocations in both invoice widgets.

Wrap RELEASE button handler in try/catch with error snackbar. Clarify
bridge TODOs for mock invoice, trade state, and NWC payment paths.
Update T061–T068 task descriptions with partial-wiring annotations.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
specs/004-mostro-p2p-client/tasks.md (1)

211-218: Consider using a distinct marker for partial implementations.

The Partial and Note annotations clarify the implementation state, which is an improvement. However, using [x] (complete) alongside "Partial" can be ambiguous for tracking purposes.

A clearer convention might be:

  • [x] for fully complete tasks
  • [~] or [partial] for tasks with known gaps
  • [ ] for not started

This would make it easier to filter and identify work that still needs attention.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@specs/004-mostro-p2p-client/tasks.md` around lines 211 - 218, The checklist
uses [x] for items that are still partial/annotated which is ambiguous; update
the task markers for any entries that include "Partial" or "Note" (e.g., T061,
T062, T063, T064, T065, T066, T067, T068) from [x] to a distinct partial marker
like [~] or [partial], and add or update a legend at the top of the tasks
document explaining the three states ([x]=done, [~]=partial, [ ]=not started);
ensure the textual "Partial"/"Note" annotations remain in the task descriptions
so reviewers can see why it’s partial and, if you have any parsing scripts that
read the checklist, adjust them to recognize the new [~]/[partial] marker.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@specs/004-mostro-p2p-client/tasks.md`:
- Around line 211-218: The checklist uses [x] for items that are still
partial/annotated which is ambiguous; update the task markers for any entries
that include "Partial" or "Note" (e.g., T061, T062, T063, T064, T065, T066,
T067, T068) from [x] to a distinct partial marker like [~] or [partial], and add
or update a legend at the top of the tasks document explaining the three states
([x]=done, [~]=partial, [ ]=not started); ensure the textual "Partial"/"Note"
annotations remain in the task descriptions so reviewers can see why it’s
partial and, if you have any parsing scripts that read the checklist, adjust
them to recognize the new [~]/[partial] marker.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8a2472a4-9299-49c8-a528-a751a7f33691

📥 Commits

Reviewing files that changed from the base of the PR and between a8699c4 and 48e8517.

📒 Files selected for processing (13)
  • lib/features/order/screens/pay_lightning_invoice_screen.dart
  • lib/features/trades/screens/trade_detail_screen.dart
  • lib/shared/widgets/nwc_payment_widget.dart
  • lib/shared/widgets/pay_lightning_invoice_widget.dart
  • linux/flutter/generated_plugin_registrant.cc
  • linux/flutter/generated_plugins.cmake
  • macos/Flutter/GeneratedPluginRegistrant.swift
  • pubspec.yaml
  • rust/src/api/orders.rs
  • rust/src/mostro/actions.rs
  • specs/004-mostro-p2p-client/tasks.md
  • windows/flutter/generated_plugin_registrant.cc
  • windows/flutter/generated_plugins.cmake
✅ Files skipped from review due to trivial changes (7)
  • macos/Flutter/GeneratedPluginRegistrant.swift
  • pubspec.yaml
  • linux/flutter/generated_plugins.cmake
  • linux/flutter/generated_plugin_registrant.cc
  • windows/flutter/generated_plugins.cmake
  • windows/flutter/generated_plugin_registrant.cc
  • lib/features/trades/screens/trade_detail_screen.dart
🚧 Files skipped from review as they are similar to previous changes (4)
  • lib/shared/widgets/pay_lightning_invoice_widget.dart
  • lib/shared/widgets/nwc_payment_widget.dart
  • lib/features/order/screens/pay_lightning_invoice_screen.dart
  • rust/src/api/orders.rs

Introduce a three-state legend ([ ]=not started, [~]=partial, [x]=done)
near the top of tasks.md. Change T061, T062, T066, T067, T068 from [x]
to [~] since they carry Partial annotations in their descriptions.
T063, T064, T065 remain [x] as fully implemented.
@grunch
grunch merged commit 23b39bd into main Mar 30, 2026
1 check passed
@grunch
grunch deleted the 004-mostro-p2p-client branch March 30, 2026 13:27
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