Skip to content

[NWC] Phase 5: Payment notifications and enhanced UX#472

Merged
grunch merged 2 commits intomainfrom
feature/nwc-phase5-notifications-ux
Feb 14, 2026
Merged

[NWC] Phase 5: Payment notifications and enhanced UX#472
grunch merged 2 commits intomainfrom
feature/nwc-phase5-notifications-ux

Conversation

@mostronator
Copy link
Collaborator

@mostronator mostronator commented Feb 14, 2026

Summary

Final phase of NWC integration: real-time payment notifications via NIP-47 kind 23196 events, enhanced payment UX with pre-flight balance checks and payment receipts, connection resilience with auto-reconnect, and wallet health monitoring.

Closes #460

Changes

Real-time Notifications (NIP-47 kind 23196)

  • Subscribe to payment_received and payment_sent notification events from the wallet
  • NwcNotificationListener at app level shows floating snackbar notifications for payment events
  • Auto-refresh balance when payment notifications arrive
  • Notifications are decrypted using the negotiated encryption mode and verified via p tag

Enhanced Payment UX

  • Pre-flight balance check: Before sending pay_invoice, verify sufficient balance with a fresh get_balance call
  • Payment receipt: After successful payment, show detailed receipt with amount, routing fees (if reported), total, timestamp, and preimage with copy button
  • lookup_invoice verification: After paying, cross-reference payment status on the wallet side for extra reliability
  • Connection health warnings: Show orange warning banner when connection is unstable
  • Low balance warnings: Show red warning when wallet balance < payment amount

Connection Resilience

  • Auto-reconnect: On connection drop, retry with exponential backoff (2s, 4s, 8s, 16s, 32s) up to 5 attempts
  • Periodic health checks: Every 30s, perform a lightweight get_balance to verify connection is alive
  • Periodic balance refresh: Every 60s, refresh cached balance
  • Graceful degradation: Connection unstable warnings + manual payment fallback always available
  • Connection health indicator: Green/orange dot in wallet settings based on health state

Wallet Balance

  • Balance refreshed on connect, every 60s, after payments, and on notification events
  • Low balance warning when balance < order amount (button disabled)
  • Balance unknown → button enabled (let wallet decide)

New Files

  • lib/shared/widgets/nwc_connection_status_indicator.dart — Compact connection health widget
  • lib/shared/widgets/nwc_payment_receipt_widget.dart — Payment receipt with amount breakdown
  • lib/shared/widgets/nwc_notification_listener.dart — App-level notification snackbar listener
  • docs/NWC_PHASE5_IMPLEMENTATION.md — Detailed implementation documentation

Modified Files

  • lib/services/nwc/nwc_client.dart — Notification subscription (kind 23196), NwcNotification model
  • lib/features/wallet/providers/nwc_provider.dart — Auto-reconnect, health checks, balance refresh timers, notification forwarding, preFlightBalanceCheck(), lookupInvoice()
  • lib/shared/widgets/nwc_payment_widget.dart — Pre-flight check, receipt, health/balance warnings
  • lib/features/wallet/screens/wallet_settings_screen.dart — Health indicator (green/orange)
  • lib/core/app.dartNwcNotificationListener integration
  • lib/l10n/intl_en.arb, intl_es.arb, intl_it.arb — 15 new strings

Localization

All 15 new strings added in EN, ES, and IT.

References

Summary by CodeRabbit

Release Notes

New Features

  • Real-time payment notifications from your connected wallet
  • Pre-flight balance checks before sending payments to prevent failed transactions
  • Detailed payment receipts displaying amounts, fees, and timestamps
  • Wallet connection health monitoring with automatic reconnection
  • Connection status indicator showing wallet stability

Improvements

  • Enhanced wallet connection resilience with automatic recovery
  • Better error messaging for insufficient balance scenarios
  • Invoice verification after payments for transaction confirmation

- Subscribe to NWC notification events (kind 23196) for real-time
  payment_received and payment_sent updates
- Add NwcNotificationListener at app level for in-app snackbar
  notifications on payment events
- Add pre-flight balance check before payment attempts
- Add payment receipt widget with amount breakdown, fees, preimage,
  and timestamp
- Add connection health monitoring with periodic checks (30s)
- Add auto-reconnect with exponential backoff on connection drops
- Add periodic balance refresh (60s)
- Add lookup_invoice verification after successful payments
- Add connection health indicator (green/orange) in wallet settings
- Add NwcConnectionStatusIndicator reusable widget
- Add low balance and connection unstable warnings in payment flow
- Add 15 new localization strings (EN, ES, IT)
- Add NWC_PHASE5_IMPLEMENTATION.md documentation

Closes #460
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 14, 2026

Warning

Rate limit exceeded

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

⌛ 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.

Walkthrough

Implements NWC Phase 5, adding real-time payment notifications (NIP-47), connection health monitoring with auto-reconnect, pre-flight balance verification, and enhanced payment receipts. Extends NwcClient with notification streaming, introduces three new UI widgets for status display and notifications, and integrates comprehensive lifecycle management into NwcNotifier.

Changes

Cohort / File(s) Summary
Core NWC Service
lib/services/nwc/nwc_client.dart
Added NwcNotification class and public notifications stream. Implemented private subscription to kind 23196 notifications with decryption and parsing. Integrated notification lifecycle into connect/disconnect.
NWC Provider & State Management
lib/features/wallet/providers/nwc_provider.dart
Extended NwcState with connectionHealthy and lastSuccessfulContact fields. Added notifications stream, preFlightBalanceCheck, and lookupInvoice public APIs. Implemented background health checks, periodic balance refresh, auto-reconnect with exponential backoff, and comprehensive lifecycle management (subscriptions, timers).
New Notification & Status Widgets
lib/shared/widgets/nwc_notification_listener.dart, lib/shared/widgets/nwc_connection_status_indicator.dart
Added NwcNotificationListener for SnackBar in-app notifications on payment events. Added NwcConnectionStatusIndicator to display connection status with optional label and balance display, reflecting health state with color-coded indicators.
Payment Receipt & Flow
lib/shared/widgets/nwc_payment_receipt_widget.dart, lib/shared/widgets/nwc_payment_widget.dart
Introduced NwcPaymentReceiptWidget with amount, fees, preimage, and timestamp display. Enhanced NwcPaymentWidget with new checking state, pre-flight balance checks, post-payment invoice verification, and receipt display integration.
App Integration & UX
lib/core/app.dart, lib/features/wallet/screens/wallet_settings_screen.dart
Wrapped app builder with NwcNotificationListener for global notification support. Updated wallet settings status indicator to reflect connection health (green/orange) and conditional status text.
Documentation & Localization
docs/NWC_PHASE5_IMPLEMENTATION.md, lib/l10n/intl_*.arb
Added Phase 5 implementation documentation. Extended EN, ES, IT localization with 15 new strings for notifications, health indicators, receipts, and pre-flight checks.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Mobile Client
    participant Notifier as NwcNotifier
    participant Service as NwcClient
    participant Relay as Nostr Relay
    participant Wallet as NWC Wallet

    Note over Client,Wallet: Connection & Initialization
    Client->>Notifier: connect(uri)
    Notifier->>Service: connect(uri)
    Service->>Relay: Connect WebSocket
    Relay-->>Service: Connected
    Service->>Relay: Subscribe to kind 23196 (notifications)
    Relay-->>Service: Subscribed
    Service->>Service: _startHealthChecks()
    Service->>Service: _startBalanceRefresh()
    Service-->>Notifier: Connected
    Notifier-->>Client: State updated (connected)

    Note over Client,Wallet: Real-time Notification Flow
    Wallet->>Relay: Send NWC notification (kind 23196)
    Relay->>Service: Relay notification event
    Service->>Service: Decrypt & parse notification
    Service->>Service: Emit NwcNotification via stream
    Notifier->>Service: Listen to notifications stream
    Notifier->>Notifier: Update connectionHealthy
    Notifier->>Notifier: Update lastSuccessfulContact
    Notifier->>Client: Trigger UI update
    Client->>Client: NwcNotificationListener shows SnackBar

    Note over Client,Wallet: Health Check Loop
    Service->>Service: _checkHealth() periodic timer
    Service->>Service: preFlightBalanceCheck()
    Service->>Wallet: Request balance via NWC
    Wallet-->>Service: Return balance
    Service->>Notifier: Update connectionHealthy
    Service->>Client: UI reflects health status
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • BraCR10
  • Catrya
  • grunch

Poem

🐰 Hops through notifications swift and bright,
Health checks pinging through the night,
Receipts blooming, reconnections mend,
Phase Five's here—let wallets transcend! 🪙✨

🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: implementing NWC Phase 5 with payment notifications and enhanced UX features.
Linked Issues check ✅ Passed All core requirements from #460 are implemented: real-time notifications, pre-flight balance checks, payment receipts, balance display, auto-reconnect with health checks, and lookup_invoice verification.
Out of Scope Changes check ✅ Passed All changes directly support Phase 5 objectives; no unrelated modifications detected in the PR scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/nwc-phase5-notifications-ux

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.

@mostronator
Copy link
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 14, 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.

Copy link
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: 5

🤖 Fix all issues with AI agents
In `@docs/NWC_PHASE5_IMPLEMENTATION.md`:
- Around line 168-186: The localization table declares 15 new strings but only
lists 14; add the missing keys (at minimum nwcConnectionError,
nwcPaymentSuccess, and nwcPreimageLabel) to the EN/ES/IT localization entries so
the table actually contains all 15 items, include appropriate translations for
each language, update the table header/count to match 15, and verify references
in nwc_connection_status_indicator.dart and nwc_payment_receipt_widget.dart
still match the exact key names.

In `@lib/features/wallet/providers/nwc_provider.dart`:
- Around line 286-310: _handleConnectionDrop currently cancels timers via
connect->_cleanup and can be re-entered concurrently causing orphaned timers and
double-incremented _reconnectAttempts; fix by adding a reentrancy guard (e.g. a
private bool _isReconnecting) at the top of _handleConnectionDrop to return
early if already reconnecting, then convert _handleConnectionDrop into an
internal retry loop that increments _reconnectAttempts once per attempted
reconnect and performs exponential backoff internally (use Duration(seconds: 1
<< _reconnectAttempts)); to avoid _cleanup cancelling timers on failed attempts,
either add a connect parameter (e.g. skipCleanup: true) or implement a private
connect variant that does not call _cleanup so that failed attempts do not stop
the health/balance timers — only on final success or when giving up should
normal cleanup/reset logic run; ensure you reference and update
_reconnectAttempts, _maxReconnectAttempts, mounted, state.status,
_healthCheckTimer and _balanceRefreshTimer accordingly.

In `@lib/services/nwc/nwc_client.dart`:
- Around line 203-216: In _subscribeToNotifications add a since parameter to the
NostrFilter used in the NostrRequest so the subscription only fetches new events
(prevent replay of historical kind 23196 notifications); update the NostrFilter
(the one with kinds: const [23196], authors: [connection.walletPubkey]) to
include since: DateTime.now().millisecondsSinceEpoch (or convert to the expected
unix-timestamp type) when constructing the NostrRequest in order to subscribe
from "now" onward.

In `@lib/shared/widgets/nwc_notification_listener.dart`:
- Around line 41-44: _subscribe currently captures a single notifier instance
via ref.read(nwcProvider.notifier) so the _subscription will point to a stale
stream if the nwcProvider is invalidated; change the logic to react to provider
changes by using ref.listen on the provider (or on a dedicated notifications
stream provider) and re-subscribe to the new notifier's notifications stream,
cancelling the previous _subscription before assigning the new one (keep using
_onNotification as the listener); ensure the resubscribe happens whenever
nwcProvider.notifier changes so the listener always attaches to the live stream.

In `@lib/shared/widgets/nwc_payment_widget.dart`:
- Around line 109-113: The code fires _verifyPayment() without awaiting and then
immediately calls widget.onPaymentSuccess, which can lead to
ref.read(nwcProvider.notifier) running after the ConsumerState is disposed;
update the flow so _verifyPayment is either awaited before calling
widget.onPaymentSuccess OR add a mounted guard at the start of _verifyPayment to
return early if the state is no longer mounted, and additionally check mounted
immediately before any use of ref (e.g., before calling
ref.read(nwcProvider.notifier)) to avoid accessing ref on a disposed
ConsumerState.
🧹 Nitpick comments (5)
lib/shared/widgets/nwc_notification_listener.dart (1)

110-117: _formatSats is duplicated across four files.

The identical helper appears in nwc_notification_listener.dart, nwc_connection_status_indicator.dart, nwc_payment_receipt_widget.dart, and nwc_payment_widget.dart. Extract it to a shared utility (e.g., lib/shared/utils/format_utils.dart).

lib/services/nwc/nwc_client.dart (2)

74-76: _notificationController is never closed.

The broadcast StreamController is created in the constructor but not closed in disconnect(). If the NwcClient is discarded after disconnect, this leaks. If the client is meant to be reconnectable (reconnect after disconnect), closing it in disconnect() would break that. Consider adding a dispose() method for final teardown, or closing it in disconnect() and recreating on connect().


11-23: NwcNotification is a simple data class — consider making it immutable with @immutable annotation.

Minor nit: the class is effectively immutable already (both fields are final), but adding @immutable annotation documents the intent and enables analyzer checks.

lib/shared/widgets/nwc_payment_receipt_widget.dart (1)

215-218: Timestamp format is hardcoded and not locale-aware.

_formatTimestamp always produces YYYY-MM-DD HH:mm regardless of the user's locale. For a payment receipt this is generally acceptable, but consider using DateFormat from intl for locale-sensitive formatting if the project already depends on it.

lib/features/wallet/providers/nwc_provider.dart (1)

261-283: Non-timeout health-check failures leave connection marked unhealthy with no recovery path.

When _checkHealth catches a non-timeout exception (line 279), it sets connectionHealthy: false but does not call _handleConnectionDrop. If the error persists, the health timer keeps firing and marking the connection unhealthy, but no reconnect is ever attempted. Consider whether persistent non-timeout failures (e.g., decryption errors, unexpected wallet responses) should also eventually trigger a reconnect.

- Add 'since: DateTime.now()' filter to notification subscription to
  prevent replaying historical events on connect
- Add reentrancy guard (_isReconnecting) to _handleConnectionDrop and
  convert to internal retry loop to prevent orphaned timers and
  double-incremented reconnect attempts
- Re-subscribe to notification stream when NWC provider reconnects
  to prevent stale subscription after disconnect/reconnect cycle
- Add mounted guard in _verifyPayment() to prevent accessing ref
  after widget disposal
- Fix documentation: correct localization string count (14 new, not 15)
  and note that nwcConnectionError, nwcPaymentSuccess, nwcPreimageLabel
  were added in earlier phases
Copy link
Member

@grunch grunch left a comment

Choose a reason for hiding this comment

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

tACK

@grunch grunch merged commit 0da34dc into main Feb 14, 2026
2 checks passed
@grunch grunch deleted the feature/nwc-phase5-notifications-ux branch February 14, 2026 20:32
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.

[NWC] Phase 5: Payment notifications and enhanced UX

2 participants