Skip to content

detect silent payment addresses and surface a clear error#644

Open
guptapratykshh wants to merge 1 commit into
bitcoinppl:masterfrom
guptapratykshh:fix/617-silent-payment-address-detection
Open

detect silent payment addresses and surface a clear error#644
guptapratykshh wants to merge 1 commit into
bitcoinppl:masterfrom
guptapratykshh:fix/617-silent-payment-address-detection

Conversation

@guptapratykshh

@guptapratykshh guptapratykshh commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

Fixes #617

blocks sending to silent payment addresses with a clear "not yet supported" message instead of a confusing "Invalid Address" error.

Summary by CodeRabbit

  • New Features

    • Detects and rejects unsupported silent-payment addresses (sp1.../tsp1...) when entered, scanned, or embedded in URs/QRs.
    • Shows a clear "Unsupported Address" alert explaining silent-payment addresses aren’t supported yet, then dismisses the alert and focuses the address field.
  • Bug Fixes

    • QR scanner and camera error handling present an explicit "Unsupported Address" message for silent-payment scans instead of a generic error.

@coderabbitai

coderabbitai Bot commented Apr 16, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Rejects BIP352 silent-payment addresses (sp1/tsp1) across Rust core, FFI, QR parsing, and Android/iOS UI. Adds a SilentPaymentNotSupported error variant, surfaces an "Unsupported Address" alert, and focuses the address input when the alert is dismissed.

Changes

Cohort / File(s) Summary
Rust: Address validation & tests
rust/crates/cove-types/src/address.rs
Add AddressError::SilentPaymentNotSupported, implement is_silent_payment_address(), return the error from parsing/uniffi constructor, and add tests for bech32m silent-payment variants.
Rust: Multi-format & QR mapping
rust/src/multi_format.rs, rust/src/qr_scanner.rs
Add MultiFormatError::SilentPaymentNotSupported and MultiQrError::SilentPaymentNotSupported; propagate silent-payment detection through multi-format and QR parsing paths instead of treating it as generic parse error.
Rust: Send-flow mapping
rust/src/manager/send_flow_manager.rs, rust/src/manager/send_flow_manager/error.rs
Add SendFlowError::SilentPaymentNotSupported; map AddressError::SilentPaymentNotSupported explicitly and refine address validation to preserve precise address-error mapping.
Android: FFI/Types
android/app/src/main/java/org/bitcoinppl/cove_core/cove.kt, android/app/src/main/java/org/bitcoinppl/cove_core/types/cove_types.kt
Insert SilentPaymentNotSupported variants into multiple sealed exception enums; update discriminants, allocation/serialization, and FFI (de)serialization to include the new variant.
Android: QR & Send UI
android/app/src/main/java/org/bitcoinppl/cove/QrCodeScanView.kt, android/app/src/main/java/org/bitcoinppl/cove/flows/SendFlow/SendFlowPresenter.kt
Change QR error callback to (title,message); handle SilentPaymentNotSupported to show "Unsupported Address" alert and clear/focus address field on dismiss.
iOS: QR & Send UI
ios/Cove/Flows/SendFlow/SendFlowPresenter.swift, ios/Cove/Flows/SendFlow/SetAmountScreen/QrCodeAddressView.swift
Handle .SilentPaymentNotSupported in send-flow and QR scan handlers: show "Unsupported Address" alert, dismiss scanner/view, and focus the address field on OK.

Sequence Diagram

sequenceDiagram
    participant User as User
    participant UI as "Android/iOS Presenter"
    participant QR as "QR Scanner"
    participant FFI as FFI Layer
    participant Rust as "Rust Core"

    User->>UI: Paste or scan address (sp1... / tsp1...)
    UI->>QR: (if scanned) deliver scanned string
    QR->>UI: return scanned string
    UI->>FFI: request parse/validate address
    FFI->>Rust: call AddressWithNetwork::try_new / Address::from_string
    Rust->>Rust: is_silent_payment_address() detects sp/tsp bech32m
    Rust-->>FFI: return SilentPaymentNotSupported error
    FFI-->>UI: deserialize as SilentPaymentNotSupported
    UI->>UI: present "Unsupported Address" alert and set focus to address field on dismiss
    UI-->>User: show alert
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I sniffed a sp1 beneath the moon,

"Not yet," I whispered, hopped away soon.
An alert I set with gentle thump—
"Unsupported Address"—then back to the stump.
Hops for fixes, carrots for noon.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is incomplete. It lacks the required Testing, Platform Coverage, and Checklist sections specified in the template. Add Testing section with platform coverage checkboxes and confirm reading of CONTRIBUTING.md and ARCHITECTURE.md as required by the template.
Docstring Coverage ⚠️ Warning Docstring coverage is 65.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: detecting silent payment addresses and displaying an appropriate error message.
Linked Issues check ✅ Passed The PR successfully addresses issue #617 by detecting silent payment addresses and surfacing a clear 'not yet supported' error instead of a generic 'Invalid Address' error.
Out of Scope Changes check ✅ Passed All changes are directly related to the objective of detecting silent payment addresses and providing appropriate error handling across all platforms and formats.

✏️ 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.

@greptile-apps

greptile-apps Bot commented Apr 16, 2026

Copy link
Copy Markdown

Greptile Summary

Detects BIP352 silent payment addresses (sp1q/tsp1q prefixes) at the Rust layer and surfaces a dedicated SilentPaymentNotSupported error variant across the full stack (Rust → UniFFI → iOS/Android), replacing the previously confusing InvalidAddress fallback. The state management improvement — storing the typed address_error on SendFlowManagerState so validate_address can replay the specific error — is a clean fix that benefits all future address-type errors, not just silent payments.

Confidence Score: 5/5

Safe to merge — all findings are P2 style suggestions that do not affect correctness or the happy path.

The implementation is correct end-to-end: detection logic matches BIP352, the error propagates cleanly through UniFFI, lock handling is correct, and clear_address properly resets address_error. Both remaining comments are P2 (alert title wording and a missing unit test for Address::from_string).

No files require special attention beyond the P2 suggestions on the alert title and test coverage.

Important Files Changed

Filename Overview
rust/crates/cove-types/src/address.rs Adds SilentPaymentNotSupported to AddressError, derives Clone, and guards both AddressWithNetwork::try_new and Address::from_string with is_silent_payment_address; includes tests for try_new but not for from_string.
rust/src/manager/send_flow_manager.rs Stores the parsed AddressError as address_error on state so validate_address can surface the specific error (e.g. silent-payment) instead of a generic InvalidAddress; lock hygiene is correct with explicit drop.
rust/src/manager/send_flow_manager/error.rs Adds SilentPaymentNotSupported variant and maps it from AddressError in from_address_error; catch-all is still correct for other variants.
rust/src/manager/send_flow_manager/state.rs Adds address_error: Option<SendFlowError> field, properly initialised to None and cleared in clear_address.
ios/Cove/Flows/SendFlow/SendFlowPresenter.swift Adds SilentPaymentNotSupported to all three switch arms (title, message, buttons); title is grouped under "Invalid Address" which is slightly misleading given the descriptive body message.
android/app/src/main/java/org/bitcoinppl/cove/flows/SendFlow/SendFlowPresenter.kt Mirrors the iOS changes; SilentPaymentNotSupported handled in title, message, and button action; title is still "Invalid Address" rather than something like "Unsupported Address".

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[User pastes address string] --> B[handle_entering_address_changed]
    B --> C[Address::from_string]
    C --> D{is_silent_payment_address?}
    D -- yes --> E[Err: AddressError::SilentPaymentNotSupported]
    D -- no --> F[BDK address parse]
    F -- invalid --> G[Err: AddressError::InvalidAddress]
    F -- valid --> H[Ok: Address]
    E --> I[SendFlowError::SilentPaymentNotSupported stored in state.address_error]
    G --> J[SendFlowError::InvalidAddress stored in state.address_error]
    H --> K[state.address = Some, state.address_error = None]
    I --> L[validate_address called with display_alert=true]
    J --> L
    K --> M[Validation passes, send flow continues]
    L --> N[SetAlert with stored address_error]
    N --> O[iOS/Android: errorAlertTitle = 'Invalid Address', errorAlertMessage = SP-specific message]
Loading

Reviews (1): Last reviewed commit: "detect silent payment addresses and surf..." | Re-trigger Greptile

Comment thread rust/crates/cove-types/src/address.rs Outdated

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
rust/src/manager/send_flow_manager.rs (1)

422-427: Prefer scoped lock extraction over explicit drop(state).

Line 426 uses manual drop(state) just to release the mutex before sending. This can be expressed more idiomatically with a scoped block and avoids explicit-drop style drift.

♻️ Suggested refactor
-                let state = self.state.lock();
-                let error = state.address_error.clone().unwrap_or_else(|| {
-                    SendFlowError::InvalidAddress(state.entering_address.clone())
-                });
-                drop(state);
+                let error = {
+                    let state = self.state.lock();
+                    state.address_error.clone().unwrap_or_else(|| {
+                        SendFlowError::InvalidAddress(state.entering_address.clone())
+                    })
+                };
                 self.reconciler.send(Message::SetAlert(error.into()));

As per coding guidelines: "Prefer scoped blocks to release locks or borrows instead of explicit drop(...) unless explicit drop is actually needed".

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

In `@rust/src/manager/send_flow_manager.rs` around lines 422 - 427, The mutex lock
is released explicitly with drop(state); prefer a scoped block to limit the
lock's lifetime: create the error value inside a short scope that acquires
self.state.lock() (e.g., let error = { let state = self.state.lock();
state.address_error.clone().unwrap_or_else(||
SendFlowError::InvalidAddress(state.entering_address.clone())) };), then call
self.reconciler.send(Message::SetAlert(error.into())); this removes the explicit
drop and keeps the lock confined to the inner scope while preserving use of
SendFlowError, state.entering_address, and Message::SetAlert.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@rust/crates/cove-types/src/address.rs`:
- Around line 513-532: Add assertions that Address::from_string rejects
silent-payment addresses the same way as AddressWithNetwork::try_new by calling
Address::from_string with the same mainnet, testnet, and bitcoin: URI SP strings
and asserting Err(AddressError::SilentPaymentNotSupported); update or add a test
(alongside test_silent_payment_address_detection) to call Address::from_string
for the three example inputs and assert the SilentPaymentNotSupported error so
the send-flow path is covered.

---

Nitpick comments:
In `@rust/src/manager/send_flow_manager.rs`:
- Around line 422-427: The mutex lock is released explicitly with drop(state);
prefer a scoped block to limit the lock's lifetime: create the error value
inside a short scope that acquires self.state.lock() (e.g., let error = { let
state = self.state.lock(); state.address_error.clone().unwrap_or_else(||
SendFlowError::InvalidAddress(state.entering_address.clone())) };), then call
self.reconciler.send(Message::SetAlert(error.into())); this removes the explicit
drop and keeps the lock confined to the inner scope while preserving use of
SendFlowError, state.entering_address, and Message::SetAlert.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 518e7684-e7fd-415c-b119-1bc9fe0b34c0

📥 Commits

Reviewing files that changed from the base of the PR and between ea30e0c and 80881a8.

📒 Files selected for processing (6)
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SendFlow/SendFlowPresenter.kt
  • ios/Cove/Flows/SendFlow/SendFlowPresenter.swift
  • rust/crates/cove-types/src/address.rs
  • rust/src/manager/send_flow_manager.rs
  • rust/src/manager/send_flow_manager/error.rs
  • rust/src/manager/send_flow_manager/state.rs

Comment thread rust/crates/cove-types/src/address.rs

@praveenperera praveenperera 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.

also read CONTRIBUTING.md and follow the commit message format

Comment thread rust/crates/cove-types/src/address.rs Outdated
Comment thread rust/src/manager/send_flow_manager/state.rs Outdated
@guptapratykshh guptapratykshh force-pushed the fix/617-silent-payment-address-detection branch 2 times, most recently from 2ce66ac to 54253d7 Compare April 17, 2026 04:45

@praveenperera praveenperera 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.

  • Regenerate UniFFI bindings for the new send-flow error, read CONTRIBUTING.md
  • Use the URI-aware parser when surfacing silent-payment alerts send_flow_manager.rs:426-428 If the user pastes a BIP21 URI such as bitcoin:sp1... into the send field and then submits, this path reparses with Address::from_string, which only accepts raw addresses. In that scenario the new SilentPaymentNotSupported branch is never reached and the app still shows the generic invalid-address alert, even though AddressWithNetwork::try_new already recognizes silent-payment URIs and has tests for them.

@praveenperera praveenperera force-pushed the fix/617-silent-payment-address-detection branch from 54253d7 to 7f78fb8 Compare April 17, 2026 17:38
@guptapratykshh guptapratykshh force-pushed the fix/617-silent-payment-address-detection branch from d4d1862 to bae3f32 Compare April 17, 2026 18:27
@praveenperera praveenperera force-pushed the fix/617-silent-payment-address-detection branch 2 times, most recently from f8a5844 to edfa409 Compare April 20, 2026 18:29

@coderabbitai coderabbitai 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.

♻️ Duplicate comments (1)
rust/crates/cove-types/src/address.rs (1)

292-294: ⚠️ Potential issue | 🟡 Minor

Handle bitcoin: silent-payment URIs in Address::from_string too.

is_silent_payment_address("bitcoin:sp1...") is false, so this constructor still returns InvalidAddress for a BIP21 silent-payment URI. If this FFI constructor or address_is_valid_for_network sees raw user input, the clear unsupported message is lost for URI-form inputs.

🐛 Proposed fix
-        if is_silent_payment_address(address) {
+        let is_silent_payment = parse_bitcoin_uri(address)
+            .map(|(parsed_address, _)| is_silent_payment_address(&parsed_address))
+            .unwrap_or_else(|_| is_silent_payment_address(address));
+
+        if is_silent_payment {
             return Err(Error::SilentPaymentNotSupported);
         }

As per coding guidelines, “Verify correct functionality and logic consistency.”

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

In `@rust/crates/cove-types/src/address.rs` around lines 292 - 294,
Address::from_string currently misses BIP21 silent-payment URIs (e.g.,
"bitcoin:sp...") because is_silent_payment_address only recognizes raw
addresses, so add a check that treats URI-form inputs as silent-payment too: in
Address::from_string (and before calling address_is_valid_for_network) detect if
the input starts with "bitcoin:sp" (or parse a bitcoin: URI and inspect its
path) and if so return Err(Error::SilentPaymentNotSupported) so URI-form
silent-payment addresses get the same clear error as raw ones; reference
is_silent_payment_address, Address::from_string, and
address_is_valid_for_network when locating the change.
🧹 Nitpick comments (1)
android/app/src/main/java/org/bitcoinppl/cove_core/cove.kt (1)

43641-43642: Remove the empty default constructor.

This keeps the no-arg constructor while satisfying detekt.

Proposed cleanup
-    class SilentPaymentNotSupported(
-        ) : SendFlowException() {
+    class SilentPaymentNotSupported : SendFlowException() {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@android/app/src/main/java/org/bitcoinppl/cove_core/cove.kt` around lines
43641 - 43642, The class SilentPaymentNotSupported currently declares an
explicit empty primary constructor; remove the redundant empty constructor
declaration so the class is declared as a no-arg class inheriting
SendFlowException (i.e., change the declaration to omit the empty parentheses
after the class name), ensuring you keep the inheritance to SendFlowException
and satisfy detekt.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@rust/crates/cove-types/src/address.rs`:
- Around line 292-294: Address::from_string currently misses BIP21
silent-payment URIs (e.g., "bitcoin:sp...") because is_silent_payment_address
only recognizes raw addresses, so add a check that treats URI-form inputs as
silent-payment too: in Address::from_string (and before calling
address_is_valid_for_network) detect if the input starts with "bitcoin:sp" (or
parse a bitcoin: URI and inspect its path) and if so return
Err(Error::SilentPaymentNotSupported) so URI-form silent-payment addresses get
the same clear error as raw ones; reference is_silent_payment_address,
Address::from_string, and address_is_valid_for_network when locating the change.

---

Nitpick comments:
In `@android/app/src/main/java/org/bitcoinppl/cove_core/cove.kt`:
- Around line 43641-43642: The class SilentPaymentNotSupported currently
declares an explicit empty primary constructor; remove the redundant empty
constructor declaration so the class is declared as a no-arg class inheriting
SendFlowException (i.e., change the declaration to omit the empty parentheses
after the class name), ensuring you keep the inheritance to SendFlowException
and satisfy detekt.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: aa7e281c-e24c-491c-858d-4822fb93dcab

📥 Commits

Reviewing files that changed from the base of the PR and between 80881a8 and edfa409.

⛔ Files ignored due to path filters (2)
  • ios/CoveCore/Sources/CoveCore/generated/cove.swift is excluded by !**/generated/**
  • ios/CoveCore/Sources/CoveCore/generated/cove_types.swift is excluded by !**/generated/**
📒 Files selected for processing (7)
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SendFlow/SendFlowPresenter.kt
  • android/app/src/main/java/org/bitcoinppl/cove_core/cove.kt
  • android/app/src/main/java/org/bitcoinppl/cove_core/types/cove_types.kt
  • ios/Cove/Flows/SendFlow/SendFlowPresenter.swift
  • rust/crates/cove-types/src/address.rs
  • rust/src/manager/send_flow_manager.rs
  • rust/src/manager/send_flow_manager/error.rs
🚧 Files skipped from review as they are similar to previous changes (4)
  • rust/src/manager/send_flow_manager/error.rs
  • ios/Cove/Flows/SendFlow/SendFlowPresenter.swift
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SendFlow/SendFlowPresenter.kt
  • rust/src/manager/send_flow_manager.rs

@praveenperera praveenperera self-requested a review April 20, 2026 18:55

@praveenperera praveenperera 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.

@guptapratykshh Validate silent-payment candidates before surfacing unsupported crates/cove-types/src/address.rs

Any string that merely starts with sp1q or tsp1q is currently classified as SilentPaymentNotSupported, even if it is truncated, has a bad checksum, or is otherwise not a real silent-payment address. In those cases, users will see the new unsupported-address path instead of the existing invalid-address path, which is a user-visible validation regression. Please only return SilentPaymentNotSupported after confirming the input is a valid silent-payment encoding.

@guptapratykshh guptapratykshh force-pushed the fix/617-silent-payment-address-detection branch from edfa409 to 6414386 Compare April 21, 2026 17:10

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
android/app/src/main/java/org/bitcoinppl/cove_core/cove.kt (1)

43296-43297: Drop the empty constructor.

This trips detekt and adds no value; Kotlin can declare the payload-free variant directly.

♻️ Proposed cleanup
-    class SilentPaymentNotSupported(
-        ) : SendFlowException() {
+    class SilentPaymentNotSupported : SendFlowException() {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@android/app/src/main/java/org/bitcoinppl/cove_core/cove.kt` around lines
43296 - 43297, The class SilentPaymentNotSupported currently declares an empty
primary constructor; remove the empty parentheses and declare it as "class
SilentPaymentNotSupported : SendFlowException" (i.e., drop the redundant
constructor) to satisfy detekt and simplify the declaration.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@android/app/src/main/java/org/bitcoinppl/cove_core/cove.kt`:
- Around line 43357-43360: The discriminant mapping for the Rust enum variants
is off: change the numeric tag used to construct
SendFlowException.SilentPaymentNotSupported from 15 to 14 so it matches the Rust
discriminant order (so SilentPaymentNotSupported is handled without attempting
to read a string via FfiConverterString.read), and update the subsequent variant
tags accordingly (the block constructing
SendFlowException.UnableToGetFeeDetails,
SendFlowException.SilentPaymentNotSupported, and the following variant mappings
around the same switch/when that includes the code near FfiConverterString.read)
so all variant indices align with the Rust definition.

In `@rust/crates/cove-types/src/address.rs`:
- Around line 539-560: Run rustfmt on the updated tests and reformat the long
assert_eq! statements in the test_silent_payment_address_from_string and the
surrounding assertions (references: AddressWithNetwork::try_new,
Address::from_string, test_silent_payment_address_from_string) so lines fit the
project's rustfmt rules (wrap long arguments/expected values across lines).
After formatting, re-run cargo fmt / rustfmt to ensure CI passes.

---

Nitpick comments:
In `@android/app/src/main/java/org/bitcoinppl/cove_core/cove.kt`:
- Around line 43296-43297: The class SilentPaymentNotSupported currently
declares an empty primary constructor; remove the empty parentheses and declare
it as "class SilentPaymentNotSupported : SendFlowException" (i.e., drop the
redundant constructor) to satisfy detekt and simplify the declaration.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fe7e40a3-7a7b-449b-87db-f970b50a5123

📥 Commits

Reviewing files that changed from the base of the PR and between edfa409 and 6414386.

⛔ Files ignored due to path filters (2)
  • ios/CoveCore/Sources/CoveCore/generated/cove.swift is excluded by !**/generated/**
  • ios/CoveCore/Sources/CoveCore/generated/cove_types.swift is excluded by !**/generated/**
📒 Files selected for processing (7)
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SendFlow/SendFlowPresenter.kt
  • android/app/src/main/java/org/bitcoinppl/cove_core/cove.kt
  • android/app/src/main/java/org/bitcoinppl/cove_core/types/cove_types.kt
  • ios/Cove/Flows/SendFlow/SendFlowPresenter.swift
  • rust/crates/cove-types/src/address.rs
  • rust/src/manager/send_flow_manager.rs
  • rust/src/manager/send_flow_manager/error.rs
🚧 Files skipped from review as they are similar to previous changes (4)
  • rust/src/manager/send_flow_manager/error.rs
  • ios/Cove/Flows/SendFlow/SendFlowPresenter.swift
  • rust/src/manager/send_flow_manager.rs
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SendFlow/SendFlowPresenter.kt

Comment thread android/app/src/main/java/org/bitcoinppl/cove_core/cove.kt
Comment thread rust/crates/cove-types/src/address.rs Outdated
@guptapratykshh guptapratykshh force-pushed the fix/617-silent-payment-address-detection branch from 6414386 to 0291efb Compare April 21, 2026 17:17

@praveenperera praveenperera 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.

rust/src/multi_format.rs:113-120 does not handle the new AddressError::SilentPaymentNotSupported. The shared scanner still goes through MultiFormat::try_from_string() (rust/src/qr_scanner.rs:218, :276, :399), so an sp1... QR now fails as a generic parse error before Send Flow reaches handle_scan_code_changed() (rust/src/manager/send_flow_manager.rs:1493-1497). On iOS that lands in the generic QR error path in ios/Cove/Flows/SendFlow/SetAmountScreen/QrCodeAddressView.swift:99-111, and on Android Send Flow only accepts MultiFormat. Address in android/app/src/main/java/org/bitcoinppl/cove/flows/SendFlow/SendFlowContainer.kt:289-307. The new unsupported-address copy therefore works for manual entry, but not for scanned silent-payment addresses.

Please thread the new error through the shared scanner path, or otherwise let Send Flow see the raw scanned string.rust/crates/cove-types/src/address.rs:217-225 uses bitcoin::bech32::decode() as the validator.

That API accepts either Bech32 or Bech32m checksums, so a checksummed-but-non-Bech32m sp1.../tsp1... string will be reported as SilentPaymentNotSupported instead of InvalidAddress. Silent payment detection needs a Bech32m-only checksum check here.I

@guptapratykshh guptapratykshh force-pushed the fix/617-silent-payment-address-detection branch from 0291efb to 79b59d8 Compare April 22, 2026 14:25

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (2)
android/app/src/main/java/org/bitcoinppl/cove/QrCodeScanView.kt (1)

494-498: Silence detekt SwallowedException (or log the exception).

detekt flags this catch because the bound e is never used. Since the exception type itself carries the semantic meaning, you can either drop the binding or log it for diagnostics.

♻️ Proposed fix
-    } catch (e: MultiQrException.SilentPaymentNotSupported) {
+    } catch (_: MultiQrException.SilentPaymentNotSupported) {
         onError(
             "Unsupported Address",
             "Sending to silent payment addresses (sp1...) is not yet supported. Support is coming soon.",
         )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@android/app/src/main/java/org/bitcoinppl/cove/QrCodeScanView.kt` around lines
494 - 498, The catch block for MultiQrException.SilentPaymentNotSupported in
QrCodeScanView.kt binds the exception to e but never uses it, triggering
detekt's SwallowedException; fix this by either removing the binding (change to
catch ( _: MultiQrException.SilentPaymentNotSupported ) { ... }) or log the
exception for diagnostics before calling onError (e.g., use your existing logger
or Android Log.e/Timber.e to record e), keeping the rest of the onError call
unchanged so the user-facing message remains the same.
rust/src/qr_scanner.rs (1)

63-64: LGTM — new variant and map_multi_format_err centralize the SP translation correctly.

All three sites (parse_ur single-part, BBQr UnicodeText/Json, and scan_first plain-string) now funnel through map_multi_format_err, so a silent-payment address arriving via any transport surfaces as MultiQrError::SilentPaymentNotSupported rather than a generic ParseError.

Optional follow-up (not part of this PR): other structured MultiFormatError variants — PsbtNotSigned, TaprootNotSupported, UnsupportedNetworkAddress, InvalidSeedQr — are still collapsed into MultiQrError::ParseError(other.to_string()) and lose their identity at the FFI boundary. Since this function is now the single mapping point, it would be a good place to propagate those as distinct variants the next time the UI needs to branch on them.

Also applies to: 220-220, 278-278, 283-289, 408-408

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

In `@rust/src/qr_scanner.rs` around lines 63 - 64, The mapping function
map_multi_format_err currently converts MultiFormatError variants into a generic
MultiQrError::ParseError except for SilentPaymentNotSupported; update
map_multi_format_err to map additional structured MultiFormatError variants
(PsbtNotSigned, TaprootNotSupported, UnsupportedNetworkAddress, InvalidSeedQr)
to new distinct MultiQrError variants (add those variants to the MultiQrError
enum if missing) so the FFI boundary preserves their identity; change the match
arm in map_multi_format_err to return the specific MultiQrError::<Variant> for
each corresponding MultiFormatError::<Variant> and keep ParseError as the
fallback for truly unknown cases.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@android/app/src/main/java/org/bitcoinppl/cove/QrCodeScanView.kt`:
- Around line 494-498: The catch block for
MultiQrException.SilentPaymentNotSupported in QrCodeScanView.kt binds the
exception to e but never uses it, triggering detekt's SwallowedException; fix
this by either removing the binding (change to catch ( _:
MultiQrException.SilentPaymentNotSupported ) { ... }) or log the exception for
diagnostics before calling onError (e.g., use your existing logger or Android
Log.e/Timber.e to record e), keeping the rest of the onError call unchanged so
the user-facing message remains the same.

In `@rust/src/qr_scanner.rs`:
- Around line 63-64: The mapping function map_multi_format_err currently
converts MultiFormatError variants into a generic MultiQrError::ParseError
except for SilentPaymentNotSupported; update map_multi_format_err to map
additional structured MultiFormatError variants (PsbtNotSigned,
TaprootNotSupported, UnsupportedNetworkAddress, InvalidSeedQr) to new distinct
MultiQrError variants (add those variants to the MultiQrError enum if missing)
so the FFI boundary preserves their identity; change the match arm in
map_multi_format_err to return the specific MultiQrError::<Variant> for each
corresponding MultiFormatError::<Variant> and keep ParseError as the fallback
for truly unknown cases.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0ff249e9-7c29-4b33-a9e8-f86f09d48e8c

📥 Commits

Reviewing files that changed from the base of the PR and between 6414386 and 79b59d8.

⛔ Files ignored due to path filters (2)
  • ios/CoveCore/Sources/CoveCore/generated/cove.swift is excluded by !**/generated/**
  • ios/CoveCore/Sources/CoveCore/generated/cove_types.swift is excluded by !**/generated/**
📒 Files selected for processing (11)
  • android/app/src/main/java/org/bitcoinppl/cove/QrCodeScanView.kt
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SendFlow/SendFlowPresenter.kt
  • android/app/src/main/java/org/bitcoinppl/cove_core/cove.kt
  • android/app/src/main/java/org/bitcoinppl/cove_core/types/cove_types.kt
  • ios/Cove/Flows/SendFlow/SendFlowPresenter.swift
  • ios/Cove/Flows/SendFlow/SetAmountScreen/QrCodeAddressView.swift
  • rust/crates/cove-types/src/address.rs
  • rust/src/manager/send_flow_manager.rs
  • rust/src/manager/send_flow_manager/error.rs
  • rust/src/multi_format.rs
  • rust/src/qr_scanner.rs
✅ Files skipped from review due to trivial changes (1)
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SendFlow/SendFlowPresenter.kt
🚧 Files skipped from review as they are similar to previous changes (3)
  • rust/src/manager/send_flow_manager/error.rs
  • ios/Cove/Flows/SendFlow/SendFlowPresenter.swift
  • rust/src/manager/send_flow_manager.rs

@praveenperera praveenperera 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.

looks good, but need some small changes

Comment thread rust/src/qr_scanner.rs Outdated
@guptapratykshh guptapratykshh force-pushed the fix/617-silent-payment-address-detection branch from 79b59d8 to 8102b8e Compare April 24, 2026 19:40

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@rust/src/manager/send_flow_manager.rs`:
- Around line 422-426: The code currently treats any successful
AddressWithNetwork::try_new(&entering) result as InvalidAddress; instead, in
send_flow_manager.rs where you handle let entering =
self.state.lock().entering_address.clone() and match
AddressWithNetwork::try_new(&entering), add a network equality check on the
Ok(path) branch: compare the returned AddressWithNetwork's network (e.g.,
addr.network or AddressWithNetwork::network()) against the expected network for
the current flow (derive expected network from the state or wallet context used
elsewhere in SendFlowManager), and if they differ return the appropriate
SendFlowError variant for wrong network (use the existing SendFlowError variant
for wrong-network addresses) otherwise proceed as a valid address; keep the
Err(e) branch using SendFlowError::from_address_error(e, entering) unchanged.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b7d7f907-7f45-422d-b32b-4c2a154dba0d

📥 Commits

Reviewing files that changed from the base of the PR and between 79b59d8 and 8102b8e.

⛔ Files ignored due to path filters (2)
  • ios/CoveCore/Sources/CoveCore/generated/cove.swift is excluded by !**/generated/**
  • ios/CoveCore/Sources/CoveCore/generated/cove_types.swift is excluded by !**/generated/**
📒 Files selected for processing (11)
  • android/app/src/main/java/org/bitcoinppl/cove/QrCodeScanView.kt
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SendFlow/SendFlowPresenter.kt
  • android/app/src/main/java/org/bitcoinppl/cove_core/cove.kt
  • android/app/src/main/java/org/bitcoinppl/cove_core/types/cove_types.kt
  • ios/Cove/Flows/SendFlow/SendFlowPresenter.swift
  • ios/Cove/Flows/SendFlow/SetAmountScreen/QrCodeAddressView.swift
  • rust/crates/cove-types/src/address.rs
  • rust/src/manager/send_flow_manager.rs
  • rust/src/manager/send_flow_manager/error.rs
  • rust/src/multi_format.rs
  • rust/src/qr_scanner.rs
🚧 Files skipped from review as they are similar to previous changes (4)
  • ios/Cove/Flows/SendFlow/SetAmountScreen/QrCodeAddressView.swift
  • rust/src/manager/send_flow_manager/error.rs
  • ios/Cove/Flows/SendFlow/SendFlowPresenter.swift
  • rust/src/multi_format.rs

Comment thread rust/src/manager/send_flow_manager.rs Outdated
Pasting or scanning a BIP352 silent payment address (sp1... /
tsp1...) into the send field surfaces a generic "Invalid Address"
error today, which is confusing because the string looks like
valid bech32m.

Detect the SP prefixes in both AddressWithNetwork::try_new and
Address::from_string and raise a dedicated SilentPaymentNotSupported
error. Validation requires a successful bech32m-only decode (via
CheckedHrpstring::new::<Bech32m>) with the "sp" or "tsp" HRP, so
truncated strings and strings with a bech32 (not bech32m) checksum
fall through to the existing InvalidAddress path.

The QR scanner shares MultiFormat::try_from_string, so propagate
the new error through MultiFormatError and MultiQrError. Both iOS
QrCodeAddressView and Android QrCodeScanView catch the typed error
and show the same "Unsupported Address" alert as manual entry,
including for bitcoin:sp1... URIs and scanned QR codes.

Regenerated UniFFI bindings for the new error variants on both
iOS and Android.

Refs bitcoinppl#617
@guptapratykshh guptapratykshh force-pushed the fix/617-silent-payment-address-detection branch from 8102b8e to 6fc6ce1 Compare April 24, 2026 19:48
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.

Add support for sending to silent payment addresses

2 participants