feat: add trezor receive - #1189

Open
ben-kaufman wants to merge 7 commits into
masterfrom
feat/trezor-receive
Open

feat: add trezor receive#1189
ben-kaufman wants to merge 7 commits into
masterfrom
feat/trezor-receive

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Description

This PR:

  1. Adds a Trezor tab to the Receive flow with the current next-unused native SegWit watcher address, falling back to the existing account scan when watcher state is unavailable.
  2. Supports on-chain-only amount and note editing without starting Lightning receive work.
  3. Lets users copy or share the Trezor payment request and verify the displayed address on the connected device.
  4. Matches hardware receive styling with a white selected-tab underline, blue Bitcoin mark, and blue action icons.

Stack

Linked Issues/Tasks

Fixes#1202

QA Notes

Manual Tests

  • 1. Paired Trezor → Home → Receive → Trezor: the current native SegWit address and QR load with the hardware-wallet styling.
  • 2. Trezor Receive → Show Details → Verify on Device: the button shows a loading state, the device address exactly matches Bitkit, and approval completes without changing the displayed address or showing an error.
  • 3. Trezor Receive → edit amount and note → Show QR → Show Details → Copy/Share: the edit returns directly to the Trezor QR without tags or Lightning setup, and the payment request contains the Trezor address with the entered amount and note.
  • 4. Passphrase Trezor → Receive → Show Details → Verify on Device → enter the passphrase: the wallet reconnects and address verification resumes.
  • 5.regression: Start Verify on Device → while device approval is pending, fund the displayed regtest address and advance the watcher: the stale verification is cancelled and Bitkit displays and copies the new receive address.

Automated Tests

  • Unit tests added or extended in HwWalletRepoTest.kt: cover watcher-backed receive-address selection, stored-xpub fallback, and device-address mismatch rejection.
  • Unit tests added in HwReceiveViewModelTest.kt: cover address loading and reset, passphrase reconnection, live watcher-address updates, and cancellation of stale verification.
  • Unit tests extended in ReceiveInvoiceUtilsTest.kt: cover the hardware-only BIP21 destination, shared amount and note details, and zero-amount omission.
  • Compose UI coverage added in EditInvoiceContentTest.kt: verifies the on-chain-only hardware edit callback and hidden tag actions.
  • Hardware-wallet journey coverage added in receive-onchain.xml: defines the Trezor tab, QR, details, and exact on-device address-verification flow.
  • GitHub CI build and the full testDevDebugUnitTest suite pass; lint and detekt pass.
  • git diff --check passes.

@ben-kaufmanben-kaufman mentioned this pull request Aug 27, 2026
6 tasks
@greptile-apps

Copy link
Copy Markdown

Greptile Summary

Adds hardware-wallet receiving to the existing receive sheet, including watcher-backed address resolution, BIP21 editing, and on-device Trezor verification.

  • Adds a Trezor receive tab with QR, copy, share, details, and device-verification actions.
  • Resolves the next unused watcher address with an account-scan fallback.
  • Adds passphrase-aware verification state and watcher event coverage.
  • Updates bitkit-core and adds repository, view-model, invoice utility, and journey tests.

Confidence Score: 4/5

The PR should not merge until receive amount and note state is scoped so Savings edits cannot silently alter the Trezor payment request.

The Trezor QR directly consumes the same BIP21 metadata updated by Savings editing, causing a request for one account to be displayed for another account with unintended payment details.

Files Needing Attention: app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt, app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt

Important Files Changed

FilenameOverview
app/src/main/java/to/bitkit/repositories/HwWalletRepo.ktAdds watcher-backed receive-address lookup, account-scan fallback, typed watcher address data, and identity-aware Trezor address verification.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/HwReceiveViewModel.ktCoordinates address loading, watcher updates, verification retries, passphrase prompts, cancellation, and user-facing errors.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.ktAdds the Trezor tab and its actions, but incorrectly sources its amount and note from primary-wallet BIP21 metadata.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.ktWires hardware receive navigation and editing into the shared receive sheet, including the shared metadata path implicated in the finding.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveInvoiceUtils.ktBuilds hardware-wallet BIP21 requests and selects the blue Bitcoin QR logo.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreen.ktAdds an on-chain-only editing path that avoids Lightning receive work and hides tags.

Sequence Diagram

sequenceDiagram
participant U as User
participant UI as Receive Sheet
participant VM as Hardware Receive VM
participant HW as Hardware Wallet Repo
participant W as Watcher
participant T as Trezor
U->>UI: Open hardware-wallet receive
UI->>VM: loadAddress(walletId)
VM->>HW: getReceiveAddress(walletId)
HW->>W: Read next unused address
alt Watcher address available
W-->>HW: Address and derivation path
else Watcher state unavailable
HW->>T: Scan public account
T-->>HW: First unused address
end
HW-->>VM: Hardware receive address
VM-->>UI: Display QR and details
U->>UI: Verify on device
UI->>VM: verifyAddress()
VM->>HW: verifyReceiveAddress()
HW->>T: Display address at derivation path
T-->>HW: Derived address
HW-->>VM: Match or mismatch
Loading

Reviews (1): Last reviewed commit: "feat: add trezor receive" | Re-trigger Greptile

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The receive flow can complete verification for an address that is no longer displayed. I also found two smaller gaps in the Details actions and editor coverage.

Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt Outdated
Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreen.kt Outdated
@ovitrif

ovitrif commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

PLS add QA notes and Manual Tests + Automated Tests sections with details like we usually do for apps PRs. (this is more about formatting than content, content is a bit already there, just not structured in the same format we usually do)

@ovitrifovitrif added this to the 2.5.0 milestone Aug 27, 2026
@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

Updated the PR description with structured QA Notes, Manual Tests, and Automated Tests sections. I left the manual checks unchecked until they are run on Android.

coreyphillips
coreyphillips previously approved these changes Aug 28, 2026
ovitrif

This comment was marked as resolved.

Base automatically changed from feat/trezor-send to masterAugust 28, 2026 21:41
@ovitrif
ovitrif dismissed coreyphillips’s stale reviewAugust 28, 2026 21:41

The base branch was changed.

@piotr-iohk

piotr-iohk commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Tested on emulator and device (Samsung S22 + Trezor Safe 7).

Generally all good. Able to present the receive address, verify the address on the device, etc.

One observation (looks intentional in code, but may be misleading to the user): with 2+ paired hardware wallets (e.g. standard + passphrase), Home → Receive does not show the Trezor tab, so there is no hardware receive address from that entry point. Fine to defer to a follow-up PR — if that's the case, let's create a ticket for this.

Steps to reproduce

  1. Pair a Trezor (standard wallet). Home should show one hardware wallet tile.
  2. Add a passphrase wallet on the same device (Paired → Passphrase → enter passphrase). Home should now show two hardware wallet tiles.
  3. From the main/home screen, tap Receive.
  4. Only Savings / Spending tabs are shown. No Trezor tab, so you cannot get a hardware receive address.

Expected (or less misleading)

Home → Receive either shows a Trezor tab (or a wallet picker) when more than one hardware wallet is paired, or makes it clear that hardware receive is only available from the specific wallet screen.

Workaround

Open the specific hardware wallet screen first, then Receive. That path still shows the address.

Recording

Screen_Recording_20260901_102214_Bitkit.Regtest.mp4

piotr-iohk
piotr-iohk previously approved these changes Sep 1, 2026

@piotr-iohkpiotr-iohk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approve. Single-wallet receive looks good on emulator and device. See the QA comment for the multi-wallet Home Receive note (fine to defer).

@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

The single-wallet hardware Receive flow is green and the earlier change requests are resolved. I filed #1204 for the requested Home Receive wallet picker when multiple hardware wallets are paired. @ovitrif please re-review the current head so the stale change-request state can be cleared.

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The initial hardware receive load can still revert to a stale watcher address. I also found two regression-coverage gaps in the addressed UI fixes.

Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt Outdated
Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt Outdated
@coreyphillips
coreyphillips self-requested a review September 2, 2026 00:18
coreyphillips
coreyphillips previously approved these changes Sep 2, 2026
@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

Fixed all three review findings in signed commit d42064c: preserved newer watcher addresses against the fallback race, added the hardware Edit Invoice return-path regression, and added receive-specific passphrase-copy coverage. The focused unit suite passes, the Compose test suite compiles, and detekt passes. @ovitrif please re-review when fresh CI is ready.

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

utACK

Sign up for freeto 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.

Receive to hardware wallet

5 participants

@ben-kaufman@ovitrif@piotr-iohk@coreyphillips@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat: add trezor receive - #1189

Open
ben-kaufman wants to merge 7 commits into
masterfrom
feat/trezor-receive
Open

feat: add trezor receive#1189
ben-kaufman wants to merge 7 commits into
masterfrom
feat/trezor-receive

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Description

This PR:

  1. Adds a Trezor tab to the Receive flow with the current next-unused native SegWit watcher address, falling back to the existing account scan when watcher state is unavailable.
  2. Supports on-chain-only amount and note editing without starting Lightning receive work.
  3. Lets users copy or share the Trezor payment request and verify the displayed address on the connected device.
  4. Matches hardware receive styling with a white selected-tab underline, blue Bitcoin mark, and blue action icons.

Stack

Linked Issues/Tasks

Fixes#1202

QA Notes

Manual Tests

  • 1. Paired Trezor → Home → Receive → Trezor: the current native SegWit address and QR load with the hardware-wallet styling.
  • 2. Trezor Receive → Show Details → Verify on Device: the button shows a loading state, the device address exactly matches Bitkit, and approval completes without changing the displayed address or showing an error.
  • 3. Trezor Receive → edit amount and note → Show QR → Show Details → Copy/Share: the edit returns directly to the Trezor QR without tags or Lightning setup, and the payment request contains the Trezor address with the entered amount and note.
  • 4. Passphrase Trezor → Receive → Show Details → Verify on Device → enter the passphrase: the wallet reconnects and address verification resumes.
  • 5.regression: Start Verify on Device → while device approval is pending, fund the displayed regtest address and advance the watcher: the stale verification is cancelled and Bitkit displays and copies the new receive address.

Automated Tests

  • Unit tests added or extended in HwWalletRepoTest.kt: cover watcher-backed receive-address selection, stored-xpub fallback, and device-address mismatch rejection.
  • Unit tests added in HwReceiveViewModelTest.kt: cover address loading and reset, passphrase reconnection, live watcher-address updates, and cancellation of stale verification.
  • Unit tests extended in ReceiveInvoiceUtilsTest.kt: cover the hardware-only BIP21 destination, shared amount and note details, and zero-amount omission.
  • Compose UI coverage added in EditInvoiceContentTest.kt: verifies the on-chain-only hardware edit callback and hidden tag actions.
  • Hardware-wallet journey coverage added in receive-onchain.xml: defines the Trezor tab, QR, details, and exact on-device address-verification flow.
  • GitHub CI build and the full testDevDebugUnitTest suite pass; lint and detekt pass.
  • git diff --check passes.

@ben-kaufmanben-kaufman mentioned this pull request Aug 27, 2026
6 tasks
@greptile-apps

Copy link
Copy Markdown

Greptile Summary

Adds hardware-wallet receiving to the existing receive sheet, including watcher-backed address resolution, BIP21 editing, and on-device Trezor verification.

  • Adds a Trezor receive tab with QR, copy, share, details, and device-verification actions.
  • Resolves the next unused watcher address with an account-scan fallback.
  • Adds passphrase-aware verification state and watcher event coverage.
  • Updates bitkit-core and adds repository, view-model, invoice utility, and journey tests.

Confidence Score: 4/5

The PR should not merge until receive amount and note state is scoped so Savings edits cannot silently alter the Trezor payment request.

The Trezor QR directly consumes the same BIP21 metadata updated by Savings editing, causing a request for one account to be displayed for another account with unintended payment details.

Files Needing Attention: app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt, app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt

Important Files Changed

FilenameOverview
app/src/main/java/to/bitkit/repositories/HwWalletRepo.ktAdds watcher-backed receive-address lookup, account-scan fallback, typed watcher address data, and identity-aware Trezor address verification.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/HwReceiveViewModel.ktCoordinates address loading, watcher updates, verification retries, passphrase prompts, cancellation, and user-facing errors.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.ktAdds the Trezor tab and its actions, but incorrectly sources its amount and note from primary-wallet BIP21 metadata.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.ktWires hardware receive navigation and editing into the shared receive sheet, including the shared metadata path implicated in the finding.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveInvoiceUtils.ktBuilds hardware-wallet BIP21 requests and selects the blue Bitcoin QR logo.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreen.ktAdds an on-chain-only editing path that avoids Lightning receive work and hides tags.

Sequence Diagram

sequenceDiagram
participant U as User
participant UI as Receive Sheet
participant VM as Hardware Receive VM
participant HW as Hardware Wallet Repo
participant W as Watcher
participant T as Trezor
U->>UI: Open hardware-wallet receive
UI->>VM: loadAddress(walletId)
VM->>HW: getReceiveAddress(walletId)
HW->>W: Read next unused address
alt Watcher address available
W-->>HW: Address and derivation path
else Watcher state unavailable
HW->>T: Scan public account
T-->>HW: First unused address
end
HW-->>VM: Hardware receive address
VM-->>UI: Display QR and details
U->>UI: Verify on device
UI->>VM: verifyAddress()
VM->>HW: verifyReceiveAddress()
HW->>T: Display address at derivation path
T-->>HW: Derived address
HW-->>VM: Match or mismatch
Loading

Reviews (1): Last reviewed commit: "feat: add trezor receive" | Re-trigger Greptile

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The receive flow can complete verification for an address that is no longer displayed. I also found two smaller gaps in the Details actions and editor coverage.

Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt Outdated
Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreen.kt Outdated
@ovitrif

ovitrif commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

PLS add QA notes and Manual Tests + Automated Tests sections with details like we usually do for apps PRs. (this is more about formatting than content, content is a bit already there, just not structured in the same format we usually do)

@ovitrifovitrif added this to the 2.5.0 milestone Aug 27, 2026
@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

Updated the PR description with structured QA Notes, Manual Tests, and Automated Tests sections. I left the manual checks unchecked until they are run on Android.

coreyphillips
coreyphillips previously approved these changes Aug 28, 2026
ovitrif

This comment was marked as resolved.

Base automatically changed from feat/trezor-send to masterAugust 28, 2026 21:41
@ovitrif
ovitrif dismissed coreyphillips’s stale reviewAugust 28, 2026 21:41

The base branch was changed.

@piotr-iohk

piotr-iohk commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Tested on emulator and device (Samsung S22 + Trezor Safe 7).

Generally all good. Able to present the receive address, verify the address on the device, etc.

One observation (looks intentional in code, but may be misleading to the user): with 2+ paired hardware wallets (e.g. standard + passphrase), Home → Receive does not show the Trezor tab, so there is no hardware receive address from that entry point. Fine to defer to a follow-up PR — if that's the case, let's create a ticket for this.

Steps to reproduce

  1. Pair a Trezor (standard wallet). Home should show one hardware wallet tile.
  2. Add a passphrase wallet on the same device (Paired → Passphrase → enter passphrase). Home should now show two hardware wallet tiles.
  3. From the main/home screen, tap Receive.
  4. Only Savings / Spending tabs are shown. No Trezor tab, so you cannot get a hardware receive address.

Expected (or less misleading)

Home → Receive either shows a Trezor tab (or a wallet picker) when more than one hardware wallet is paired, or makes it clear that hardware receive is only available from the specific wallet screen.

Workaround

Open the specific hardware wallet screen first, then Receive. That path still shows the address.

Recording

Screen_Recording_20260901_102214_Bitkit.Regtest.mp4

piotr-iohk
piotr-iohk previously approved these changes Sep 1, 2026

@piotr-iohkpiotr-iohk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approve. Single-wallet receive looks good on emulator and device. See the QA comment for the multi-wallet Home Receive note (fine to defer).

@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

The single-wallet hardware Receive flow is green and the earlier change requests are resolved. I filed #1204 for the requested Home Receive wallet picker when multiple hardware wallets are paired. @ovitrif please re-review the current head so the stale change-request state can be cleared.

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The initial hardware receive load can still revert to a stale watcher address. I also found two regression-coverage gaps in the addressed UI fixes.

Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt Outdated
Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt Outdated
@coreyphillips
coreyphillips self-requested a review September 2, 2026 00:18
coreyphillips
coreyphillips previously approved these changes Sep 2, 2026
@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

Fixed all three review findings in signed commit d42064c: preserved newer watcher addresses against the fallback race, added the hardware Edit Invoice return-path regression, and added receive-specific passphrase-copy coverage. The focused unit suite passes, the Compose test suite compiles, and detekt passes. @ovitrif please re-review when fresh CI is ready.

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

utACK

Sign up for freeto 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.

Receive to hardware wallet

5 participants

@ben-kaufman@ovitrif@piotr-iohk@coreyphillips@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add trezor receive - #1189

Open
ben-kaufman wants to merge 7 commits into
masterfrom
feat/trezor-receive
Open

feat: add trezor receive#1189
ben-kaufman wants to merge 7 commits into
masterfrom
feat/trezor-receive

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Description

This PR:

  1. Adds a Trezor tab to the Receive flow with the current next-unused native SegWit watcher address, falling back to the existing account scan when watcher state is unavailable.
  2. Supports on-chain-only amount and note editing without starting Lightning receive work.
  3. Lets users copy or share the Trezor payment request and verify the displayed address on the connected device.
  4. Matches hardware receive styling with a white selected-tab underline, blue Bitcoin mark, and blue action icons.

Stack

Linked Issues/Tasks

Fixes#1202

QA Notes

Manual Tests

  • 1. Paired Trezor → Home → Receive → Trezor: the current native SegWit address and QR load with the hardware-wallet styling.
  • 2. Trezor Receive → Show Details → Verify on Device: the button shows a loading state, the device address exactly matches Bitkit, and approval completes without changing the displayed address or showing an error.
  • 3. Trezor Receive → edit amount and note → Show QR → Show Details → Copy/Share: the edit returns directly to the Trezor QR without tags or Lightning setup, and the payment request contains the Trezor address with the entered amount and note.
  • 4. Passphrase Trezor → Receive → Show Details → Verify on Device → enter the passphrase: the wallet reconnects and address verification resumes.
  • 5.regression: Start Verify on Device → while device approval is pending, fund the displayed regtest address and advance the watcher: the stale verification is cancelled and Bitkit displays and copies the new receive address.

Automated Tests

  • Unit tests added or extended in HwWalletRepoTest.kt: cover watcher-backed receive-address selection, stored-xpub fallback, and device-address mismatch rejection.
  • Unit tests added in HwReceiveViewModelTest.kt: cover address loading and reset, passphrase reconnection, live watcher-address updates, and cancellation of stale verification.
  • Unit tests extended in ReceiveInvoiceUtilsTest.kt: cover the hardware-only BIP21 destination, shared amount and note details, and zero-amount omission.
  • Compose UI coverage added in EditInvoiceContentTest.kt: verifies the on-chain-only hardware edit callback and hidden tag actions.
  • Hardware-wallet journey coverage added in receive-onchain.xml: defines the Trezor tab, QR, details, and exact on-device address-verification flow.
  • GitHub CI build and the full testDevDebugUnitTest suite pass; lint and detekt pass.
  • git diff --check passes.

@ben-kaufmanben-kaufman mentioned this pull request Aug 27, 2026
6 tasks
@greptile-apps

Copy link
Copy Markdown

Greptile Summary

Adds hardware-wallet receiving to the existing receive sheet, including watcher-backed address resolution, BIP21 editing, and on-device Trezor verification.

  • Adds a Trezor receive tab with QR, copy, share, details, and device-verification actions.
  • Resolves the next unused watcher address with an account-scan fallback.
  • Adds passphrase-aware verification state and watcher event coverage.
  • Updates bitkit-core and adds repository, view-model, invoice utility, and journey tests.

Confidence Score: 4/5

The PR should not merge until receive amount and note state is scoped so Savings edits cannot silently alter the Trezor payment request.

The Trezor QR directly consumes the same BIP21 metadata updated by Savings editing, causing a request for one account to be displayed for another account with unintended payment details.

Files Needing Attention: app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt, app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt

Important Files Changed

FilenameOverview
app/src/main/java/to/bitkit/repositories/HwWalletRepo.ktAdds watcher-backed receive-address lookup, account-scan fallback, typed watcher address data, and identity-aware Trezor address verification.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/HwReceiveViewModel.ktCoordinates address loading, watcher updates, verification retries, passphrase prompts, cancellation, and user-facing errors.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.ktAdds the Trezor tab and its actions, but incorrectly sources its amount and note from primary-wallet BIP21 metadata.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.ktWires hardware receive navigation and editing into the shared receive sheet, including the shared metadata path implicated in the finding.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveInvoiceUtils.ktBuilds hardware-wallet BIP21 requests and selects the blue Bitcoin QR logo.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreen.ktAdds an on-chain-only editing path that avoids Lightning receive work and hides tags.

Sequence Diagram

sequenceDiagram
participant U as User
participant UI as Receive Sheet
participant VM as Hardware Receive VM
participant HW as Hardware Wallet Repo
participant W as Watcher
participant T as Trezor
U->>UI: Open hardware-wallet receive
UI->>VM: loadAddress(walletId)
VM->>HW: getReceiveAddress(walletId)
HW->>W: Read next unused address
alt Watcher address available
W-->>HW: Address and derivation path
else Watcher state unavailable
HW->>T: Scan public account
T-->>HW: First unused address
end
HW-->>VM: Hardware receive address
VM-->>UI: Display QR and details
U->>UI: Verify on device
UI->>VM: verifyAddress()
VM->>HW: verifyReceiveAddress()
HW->>T: Display address at derivation path
T-->>HW: Derived address
HW-->>VM: Match or mismatch
Loading

Reviews (1): Last reviewed commit: "feat: add trezor receive" | Re-trigger Greptile

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The receive flow can complete verification for an address that is no longer displayed. I also found two smaller gaps in the Details actions and editor coverage.

Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt Outdated
Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreen.kt Outdated
@ovitrif

ovitrif commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

PLS add QA notes and Manual Tests + Automated Tests sections with details like we usually do for apps PRs. (this is more about formatting than content, content is a bit already there, just not structured in the same format we usually do)

@ovitrifovitrif added this to the 2.5.0 milestone Aug 27, 2026
@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

Updated the PR description with structured QA Notes, Manual Tests, and Automated Tests sections. I left the manual checks unchecked until they are run on Android.

coreyphillips
coreyphillips previously approved these changes Aug 28, 2026
ovitrif

This comment was marked as resolved.

Base automatically changed from feat/trezor-send to masterAugust 28, 2026 21:41
@ovitrif
ovitrif dismissed coreyphillips’s stale reviewAugust 28, 2026 21:41

The base branch was changed.

@piotr-iohk

piotr-iohk commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Tested on emulator and device (Samsung S22 + Trezor Safe 7).

Generally all good. Able to present the receive address, verify the address on the device, etc.

One observation (looks intentional in code, but may be misleading to the user): with 2+ paired hardware wallets (e.g. standard + passphrase), Home → Receive does not show the Trezor tab, so there is no hardware receive address from that entry point. Fine to defer to a follow-up PR — if that's the case, let's create a ticket for this.

Steps to reproduce

  1. Pair a Trezor (standard wallet). Home should show one hardware wallet tile.
  2. Add a passphrase wallet on the same device (Paired → Passphrase → enter passphrase). Home should now show two hardware wallet tiles.
  3. From the main/home screen, tap Receive.
  4. Only Savings / Spending tabs are shown. No Trezor tab, so you cannot get a hardware receive address.

Expected (or less misleading)

Home → Receive either shows a Trezor tab (or a wallet picker) when more than one hardware wallet is paired, or makes it clear that hardware receive is only available from the specific wallet screen.

Workaround

Open the specific hardware wallet screen first, then Receive. That path still shows the address.

Recording

Screen_Recording_20260901_102214_Bitkit.Regtest.mp4

piotr-iohk
piotr-iohk previously approved these changes Sep 1, 2026

@piotr-iohkpiotr-iohk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approve. Single-wallet receive looks good on emulator and device. See the QA comment for the multi-wallet Home Receive note (fine to defer).

@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

The single-wallet hardware Receive flow is green and the earlier change requests are resolved. I filed #1204 for the requested Home Receive wallet picker when multiple hardware wallets are paired. @ovitrif please re-review the current head so the stale change-request state can be cleared.

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The initial hardware receive load can still revert to a stale watcher address. I also found two regression-coverage gaps in the addressed UI fixes.

Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt Outdated
Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt Outdated
@coreyphillips
coreyphillips self-requested a review September 2, 2026 00:18
coreyphillips
coreyphillips previously approved these changes Sep 2, 2026
@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

Fixed all three review findings in signed commit d42064c: preserved newer watcher addresses against the fallback race, added the hardware Edit Invoice return-path regression, and added receive-specific passphrase-copy coverage. The focused unit suite passes, the Compose test suite compiles, and detekt passes. @ovitrif please re-review when fresh CI is ready.

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

utACK

Sign up for freeto 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.

Receive to hardware wallet

5 participants

@ben-kaufman@ovitrif@piotr-iohk@coreyphillips@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add trezor receive - #1189

Open
ben-kaufman wants to merge 7 commits into
masterfrom
feat/trezor-receive
Open

feat: add trezor receive#1189
ben-kaufman wants to merge 7 commits into
masterfrom
feat/trezor-receive

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Description

This PR:

  1. Adds a Trezor tab to the Receive flow with the current next-unused native SegWit watcher address, falling back to the existing account scan when watcher state is unavailable.
  2. Supports on-chain-only amount and note editing without starting Lightning receive work.
  3. Lets users copy or share the Trezor payment request and verify the displayed address on the connected device.
  4. Matches hardware receive styling with a white selected-tab underline, blue Bitcoin mark, and blue action icons.

Stack

Linked Issues/Tasks

Fixes#1202

QA Notes

Manual Tests

  • 1. Paired Trezor → Home → Receive → Trezor: the current native SegWit address and QR load with the hardware-wallet styling.
  • 2. Trezor Receive → Show Details → Verify on Device: the button shows a loading state, the device address exactly matches Bitkit, and approval completes without changing the displayed address or showing an error.
  • 3. Trezor Receive → edit amount and note → Show QR → Show Details → Copy/Share: the edit returns directly to the Trezor QR without tags or Lightning setup, and the payment request contains the Trezor address with the entered amount and note.
  • 4. Passphrase Trezor → Receive → Show Details → Verify on Device → enter the passphrase: the wallet reconnects and address verification resumes.
  • 5.regression: Start Verify on Device → while device approval is pending, fund the displayed regtest address and advance the watcher: the stale verification is cancelled and Bitkit displays and copies the new receive address.

Automated Tests

  • Unit tests added or extended in HwWalletRepoTest.kt: cover watcher-backed receive-address selection, stored-xpub fallback, and device-address mismatch rejection.
  • Unit tests added in HwReceiveViewModelTest.kt: cover address loading and reset, passphrase reconnection, live watcher-address updates, and cancellation of stale verification.
  • Unit tests extended in ReceiveInvoiceUtilsTest.kt: cover the hardware-only BIP21 destination, shared amount and note details, and zero-amount omission.
  • Compose UI coverage added in EditInvoiceContentTest.kt: verifies the on-chain-only hardware edit callback and hidden tag actions.
  • Hardware-wallet journey coverage added in receive-onchain.xml: defines the Trezor tab, QR, details, and exact on-device address-verification flow.
  • GitHub CI build and the full testDevDebugUnitTest suite pass; lint and detekt pass.
  • git diff --check passes.

@ben-kaufmanben-kaufman mentioned this pull request Aug 27, 2026
6 tasks
@greptile-apps

Copy link
Copy Markdown

Greptile Summary

Adds hardware-wallet receiving to the existing receive sheet, including watcher-backed address resolution, BIP21 editing, and on-device Trezor verification.

  • Adds a Trezor receive tab with QR, copy, share, details, and device-verification actions.
  • Resolves the next unused watcher address with an account-scan fallback.
  • Adds passphrase-aware verification state and watcher event coverage.
  • Updates bitkit-core and adds repository, view-model, invoice utility, and journey tests.

Confidence Score: 4/5

The PR should not merge until receive amount and note state is scoped so Savings edits cannot silently alter the Trezor payment request.

The Trezor QR directly consumes the same BIP21 metadata updated by Savings editing, causing a request for one account to be displayed for another account with unintended payment details.

Files Needing Attention: app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt, app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt

Important Files Changed

FilenameOverview
app/src/main/java/to/bitkit/repositories/HwWalletRepo.ktAdds watcher-backed receive-address lookup, account-scan fallback, typed watcher address data, and identity-aware Trezor address verification.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/HwReceiveViewModel.ktCoordinates address loading, watcher updates, verification retries, passphrase prompts, cancellation, and user-facing errors.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.ktAdds the Trezor tab and its actions, but incorrectly sources its amount and note from primary-wallet BIP21 metadata.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.ktWires hardware receive navigation and editing into the shared receive sheet, including the shared metadata path implicated in the finding.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveInvoiceUtils.ktBuilds hardware-wallet BIP21 requests and selects the blue Bitcoin QR logo.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreen.ktAdds an on-chain-only editing path that avoids Lightning receive work and hides tags.

Sequence Diagram

sequenceDiagram
participant U as User
participant UI as Receive Sheet
participant VM as Hardware Receive VM
participant HW as Hardware Wallet Repo
participant W as Watcher
participant T as Trezor
U->>UI: Open hardware-wallet receive
UI->>VM: loadAddress(walletId)
VM->>HW: getReceiveAddress(walletId)
HW->>W: Read next unused address
alt Watcher address available
W-->>HW: Address and derivation path
else Watcher state unavailable
HW->>T: Scan public account
T-->>HW: First unused address
end
HW-->>VM: Hardware receive address
VM-->>UI: Display QR and details
U->>UI: Verify on device
UI->>VM: verifyAddress()
VM->>HW: verifyReceiveAddress()
HW->>T: Display address at derivation path
T-->>HW: Derived address
HW-->>VM: Match or mismatch
Loading

Reviews (1): Last reviewed commit: "feat: add trezor receive" | Re-trigger Greptile

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The receive flow can complete verification for an address that is no longer displayed. I also found two smaller gaps in the Details actions and editor coverage.

Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt Outdated
Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreen.kt Outdated
@ovitrif

ovitrif commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

PLS add QA notes and Manual Tests + Automated Tests sections with details like we usually do for apps PRs. (this is more about formatting than content, content is a bit already there, just not structured in the same format we usually do)

@ovitrifovitrif added this to the 2.5.0 milestone Aug 27, 2026
@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

Updated the PR description with structured QA Notes, Manual Tests, and Automated Tests sections. I left the manual checks unchecked until they are run on Android.

coreyphillips
coreyphillips previously approved these changes Aug 28, 2026
ovitrif

This comment was marked as resolved.

Base automatically changed from feat/trezor-send to masterAugust 28, 2026 21:41
@ovitrif
ovitrif dismissed coreyphillips’s stale reviewAugust 28, 2026 21:41

The base branch was changed.

@piotr-iohk

piotr-iohk commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Tested on emulator and device (Samsung S22 + Trezor Safe 7).

Generally all good. Able to present the receive address, verify the address on the device, etc.

One observation (looks intentional in code, but may be misleading to the user): with 2+ paired hardware wallets (e.g. standard + passphrase), Home → Receive does not show the Trezor tab, so there is no hardware receive address from that entry point. Fine to defer to a follow-up PR — if that's the case, let's create a ticket for this.

Steps to reproduce

  1. Pair a Trezor (standard wallet). Home should show one hardware wallet tile.
  2. Add a passphrase wallet on the same device (Paired → Passphrase → enter passphrase). Home should now show two hardware wallet tiles.
  3. From the main/home screen, tap Receive.
  4. Only Savings / Spending tabs are shown. No Trezor tab, so you cannot get a hardware receive address.

Expected (or less misleading)

Home → Receive either shows a Trezor tab (or a wallet picker) when more than one hardware wallet is paired, or makes it clear that hardware receive is only available from the specific wallet screen.

Workaround

Open the specific hardware wallet screen first, then Receive. That path still shows the address.

Recording

Screen_Recording_20260901_102214_Bitkit.Regtest.mp4

piotr-iohk
piotr-iohk previously approved these changes Sep 1, 2026

@piotr-iohkpiotr-iohk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approve. Single-wallet receive looks good on emulator and device. See the QA comment for the multi-wallet Home Receive note (fine to defer).

@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

The single-wallet hardware Receive flow is green and the earlier change requests are resolved. I filed #1204 for the requested Home Receive wallet picker when multiple hardware wallets are paired. @ovitrif please re-review the current head so the stale change-request state can be cleared.

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The initial hardware receive load can still revert to a stale watcher address. I also found two regression-coverage gaps in the addressed UI fixes.

Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt Outdated
Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt Outdated
@coreyphillips
coreyphillips self-requested a review September 2, 2026 00:18
coreyphillips
coreyphillips previously approved these changes Sep 2, 2026
@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

Fixed all three review findings in signed commit d42064c: preserved newer watcher addresses against the fallback race, added the hardware Edit Invoice return-path regression, and added receive-specific passphrase-copy coverage. The focused unit suite passes, the Compose test suite compiles, and detekt passes. @ovitrif please re-review when fresh CI is ready.

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

utACK

Sign up for freeto 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.

Receive to hardware wallet

5 participants

@ben-kaufman@ovitrif@piotr-iohk@coreyphillips@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat: add trezor receive - #1189

Open
ben-kaufman wants to merge 7 commits into
masterfrom
feat/trezor-receive
Open

feat: add trezor receive#1189
ben-kaufman wants to merge 7 commits into
masterfrom
feat/trezor-receive

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Description

This PR:

  1. Adds a Trezor tab to the Receive flow with the current next-unused native SegWit watcher address, falling back to the existing account scan when watcher state is unavailable.
  2. Supports on-chain-only amount and note editing without starting Lightning receive work.
  3. Lets users copy or share the Trezor payment request and verify the displayed address on the connected device.
  4. Matches hardware receive styling with a white selected-tab underline, blue Bitcoin mark, and blue action icons.

Stack

Linked Issues/Tasks

Fixes#1202

QA Notes

Manual Tests

  • 1. Paired Trezor → Home → Receive → Trezor: the current native SegWit address and QR load with the hardware-wallet styling.
  • 2. Trezor Receive → Show Details → Verify on Device: the button shows a loading state, the device address exactly matches Bitkit, and approval completes without changing the displayed address or showing an error.
  • 3. Trezor Receive → edit amount and note → Show QR → Show Details → Copy/Share: the edit returns directly to the Trezor QR without tags or Lightning setup, and the payment request contains the Trezor address with the entered amount and note.
  • 4. Passphrase Trezor → Receive → Show Details → Verify on Device → enter the passphrase: the wallet reconnects and address verification resumes.
  • 5.regression: Start Verify on Device → while device approval is pending, fund the displayed regtest address and advance the watcher: the stale verification is cancelled and Bitkit displays and copies the new receive address.

Automated Tests

  • Unit tests added or extended in HwWalletRepoTest.kt: cover watcher-backed receive-address selection, stored-xpub fallback, and device-address mismatch rejection.
  • Unit tests added in HwReceiveViewModelTest.kt: cover address loading and reset, passphrase reconnection, live watcher-address updates, and cancellation of stale verification.
  • Unit tests extended in ReceiveInvoiceUtilsTest.kt: cover the hardware-only BIP21 destination, shared amount and note details, and zero-amount omission.
  • Compose UI coverage added in EditInvoiceContentTest.kt: verifies the on-chain-only hardware edit callback and hidden tag actions.
  • Hardware-wallet journey coverage added in receive-onchain.xml: defines the Trezor tab, QR, details, and exact on-device address-verification flow.
  • GitHub CI build and the full testDevDebugUnitTest suite pass; lint and detekt pass.
  • git diff --check passes.

@ben-kaufmanben-kaufman mentioned this pull request Aug 27, 2026
6 tasks
@greptile-apps

Copy link
Copy Markdown

Greptile Summary

Adds hardware-wallet receiving to the existing receive sheet, including watcher-backed address resolution, BIP21 editing, and on-device Trezor verification.

  • Adds a Trezor receive tab with QR, copy, share, details, and device-verification actions.
  • Resolves the next unused watcher address with an account-scan fallback.
  • Adds passphrase-aware verification state and watcher event coverage.
  • Updates bitkit-core and adds repository, view-model, invoice utility, and journey tests.

Confidence Score: 4/5

The PR should not merge until receive amount and note state is scoped so Savings edits cannot silently alter the Trezor payment request.

The Trezor QR directly consumes the same BIP21 metadata updated by Savings editing, causing a request for one account to be displayed for another account with unintended payment details.

Files Needing Attention: app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt, app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt

Important Files Changed

FilenameOverview
app/src/main/java/to/bitkit/repositories/HwWalletRepo.ktAdds watcher-backed receive-address lookup, account-scan fallback, typed watcher address data, and identity-aware Trezor address verification.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/HwReceiveViewModel.ktCoordinates address loading, watcher updates, verification retries, passphrase prompts, cancellation, and user-facing errors.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.ktAdds the Trezor tab and its actions, but incorrectly sources its amount and note from primary-wallet BIP21 metadata.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.ktWires hardware receive navigation and editing into the shared receive sheet, including the shared metadata path implicated in the finding.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveInvoiceUtils.ktBuilds hardware-wallet BIP21 requests and selects the blue Bitcoin QR logo.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreen.ktAdds an on-chain-only editing path that avoids Lightning receive work and hides tags.

Sequence Diagram

sequenceDiagram
participant U as User
participant UI as Receive Sheet
participant VM as Hardware Receive VM
participant HW as Hardware Wallet Repo
participant W as Watcher
participant T as Trezor
U->>UI: Open hardware-wallet receive
UI->>VM: loadAddress(walletId)
VM->>HW: getReceiveAddress(walletId)
HW->>W: Read next unused address
alt Watcher address available
W-->>HW: Address and derivation path
else Watcher state unavailable
HW->>T: Scan public account
T-->>HW: First unused address
end
HW-->>VM: Hardware receive address
VM-->>UI: Display QR and details
U->>UI: Verify on device
UI->>VM: verifyAddress()
VM->>HW: verifyReceiveAddress()
HW->>T: Display address at derivation path
T-->>HW: Derived address
HW-->>VM: Match or mismatch
Loading

Reviews (1): Last reviewed commit: "feat: add trezor receive" | Re-trigger Greptile

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The receive flow can complete verification for an address that is no longer displayed. I also found two smaller gaps in the Details actions and editor coverage.

Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt Outdated
Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreen.kt Outdated
@ovitrif

ovitrif commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

PLS add QA notes and Manual Tests + Automated Tests sections with details like we usually do for apps PRs. (this is more about formatting than content, content is a bit already there, just not structured in the same format we usually do)

@ovitrifovitrif added this to the 2.5.0 milestone Aug 27, 2026
@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

Updated the PR description with structured QA Notes, Manual Tests, and Automated Tests sections. I left the manual checks unchecked until they are run on Android.

coreyphillips
coreyphillips previously approved these changes Aug 28, 2026
ovitrif

This comment was marked as resolved.

Base automatically changed from feat/trezor-send to masterAugust 28, 2026 21:41
@ovitrif
ovitrif dismissed coreyphillips’s stale reviewAugust 28, 2026 21:41

The base branch was changed.

@piotr-iohk

piotr-iohk commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Tested on emulator and device (Samsung S22 + Trezor Safe 7).

Generally all good. Able to present the receive address, verify the address on the device, etc.

One observation (looks intentional in code, but may be misleading to the user): with 2+ paired hardware wallets (e.g. standard + passphrase), Home → Receive does not show the Trezor tab, so there is no hardware receive address from that entry point. Fine to defer to a follow-up PR — if that's the case, let's create a ticket for this.

Steps to reproduce

  1. Pair a Trezor (standard wallet). Home should show one hardware wallet tile.
  2. Add a passphrase wallet on the same device (Paired → Passphrase → enter passphrase). Home should now show two hardware wallet tiles.
  3. From the main/home screen, tap Receive.
  4. Only Savings / Spending tabs are shown. No Trezor tab, so you cannot get a hardware receive address.

Expected (or less misleading)

Home → Receive either shows a Trezor tab (or a wallet picker) when more than one hardware wallet is paired, or makes it clear that hardware receive is only available from the specific wallet screen.

Workaround

Open the specific hardware wallet screen first, then Receive. That path still shows the address.

Recording

Screen_Recording_20260901_102214_Bitkit.Regtest.mp4

piotr-iohk
piotr-iohk previously approved these changes Sep 1, 2026

@piotr-iohkpiotr-iohk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approve. Single-wallet receive looks good on emulator and device. See the QA comment for the multi-wallet Home Receive note (fine to defer).

@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

The single-wallet hardware Receive flow is green and the earlier change requests are resolved. I filed #1204 for the requested Home Receive wallet picker when multiple hardware wallets are paired. @ovitrif please re-review the current head so the stale change-request state can be cleared.

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The initial hardware receive load can still revert to a stale watcher address. I also found two regression-coverage gaps in the addressed UI fixes.

Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt Outdated
Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt Outdated
@coreyphillips
coreyphillips self-requested a review September 2, 2026 00:18
coreyphillips
coreyphillips previously approved these changes Sep 2, 2026
@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

Fixed all three review findings in signed commit d42064c: preserved newer watcher addresses against the fallback race, added the hardware Edit Invoice return-path regression, and added receive-specific passphrase-copy coverage. The focused unit suite passes, the Compose test suite compiles, and detekt passes. @ovitrif please re-review when fresh CI is ready.

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

utACK

Sign up for freeto 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.

Receive to hardware wallet

5 participants

@ben-kaufman@ovitrif@piotr-iohk@coreyphillips@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add trezor receive - #1189

Open
ben-kaufman wants to merge 7 commits into
masterfrom
feat/trezor-receive
Open

feat: add trezor receive#1189
ben-kaufman wants to merge 7 commits into
masterfrom
feat/trezor-receive

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Description

This PR:

  1. Adds a Trezor tab to the Receive flow with the current next-unused native SegWit watcher address, falling back to the existing account scan when watcher state is unavailable.
  2. Supports on-chain-only amount and note editing without starting Lightning receive work.
  3. Lets users copy or share the Trezor payment request and verify the displayed address on the connected device.
  4. Matches hardware receive styling with a white selected-tab underline, blue Bitcoin mark, and blue action icons.

Stack

Linked Issues/Tasks

Fixes#1202

QA Notes

Manual Tests

  • 1. Paired Trezor → Home → Receive → Trezor: the current native SegWit address and QR load with the hardware-wallet styling.
  • 2. Trezor Receive → Show Details → Verify on Device: the button shows a loading state, the device address exactly matches Bitkit, and approval completes without changing the displayed address or showing an error.
  • 3. Trezor Receive → edit amount and note → Show QR → Show Details → Copy/Share: the edit returns directly to the Trezor QR without tags or Lightning setup, and the payment request contains the Trezor address with the entered amount and note.
  • 4. Passphrase Trezor → Receive → Show Details → Verify on Device → enter the passphrase: the wallet reconnects and address verification resumes.
  • 5.regression: Start Verify on Device → while device approval is pending, fund the displayed regtest address and advance the watcher: the stale verification is cancelled and Bitkit displays and copies the new receive address.

Automated Tests

  • Unit tests added or extended in HwWalletRepoTest.kt: cover watcher-backed receive-address selection, stored-xpub fallback, and device-address mismatch rejection.
  • Unit tests added in HwReceiveViewModelTest.kt: cover address loading and reset, passphrase reconnection, live watcher-address updates, and cancellation of stale verification.
  • Unit tests extended in ReceiveInvoiceUtilsTest.kt: cover the hardware-only BIP21 destination, shared amount and note details, and zero-amount omission.
  • Compose UI coverage added in EditInvoiceContentTest.kt: verifies the on-chain-only hardware edit callback and hidden tag actions.
  • Hardware-wallet journey coverage added in receive-onchain.xml: defines the Trezor tab, QR, details, and exact on-device address-verification flow.
  • GitHub CI build and the full testDevDebugUnitTest suite pass; lint and detekt pass.
  • git diff --check passes.

@ben-kaufmanben-kaufman mentioned this pull request Aug 27, 2026
6 tasks
@greptile-apps

Copy link
Copy Markdown

Greptile Summary

Adds hardware-wallet receiving to the existing receive sheet, including watcher-backed address resolution, BIP21 editing, and on-device Trezor verification.

  • Adds a Trezor receive tab with QR, copy, share, details, and device-verification actions.
  • Resolves the next unused watcher address with an account-scan fallback.
  • Adds passphrase-aware verification state and watcher event coverage.
  • Updates bitkit-core and adds repository, view-model, invoice utility, and journey tests.

Confidence Score: 4/5

The PR should not merge until receive amount and note state is scoped so Savings edits cannot silently alter the Trezor payment request.

The Trezor QR directly consumes the same BIP21 metadata updated by Savings editing, causing a request for one account to be displayed for another account with unintended payment details.

Files Needing Attention: app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt, app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt

Important Files Changed

FilenameOverview
app/src/main/java/to/bitkit/repositories/HwWalletRepo.ktAdds watcher-backed receive-address lookup, account-scan fallback, typed watcher address data, and identity-aware Trezor address verification.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/HwReceiveViewModel.ktCoordinates address loading, watcher updates, verification retries, passphrase prompts, cancellation, and user-facing errors.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.ktAdds the Trezor tab and its actions, but incorrectly sources its amount and note from primary-wallet BIP21 metadata.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.ktWires hardware receive navigation and editing into the shared receive sheet, including the shared metadata path implicated in the finding.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveInvoiceUtils.ktBuilds hardware-wallet BIP21 requests and selects the blue Bitcoin QR logo.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreen.ktAdds an on-chain-only editing path that avoids Lightning receive work and hides tags.

Sequence Diagram

sequenceDiagram
participant U as User
participant UI as Receive Sheet
participant VM as Hardware Receive VM
participant HW as Hardware Wallet Repo
participant W as Watcher
participant T as Trezor
U->>UI: Open hardware-wallet receive
UI->>VM: loadAddress(walletId)
VM->>HW: getReceiveAddress(walletId)
HW->>W: Read next unused address
alt Watcher address available
W-->>HW: Address and derivation path
else Watcher state unavailable
HW->>T: Scan public account
T-->>HW: First unused address
end
HW-->>VM: Hardware receive address
VM-->>UI: Display QR and details
U->>UI: Verify on device
UI->>VM: verifyAddress()
VM->>HW: verifyReceiveAddress()
HW->>T: Display address at derivation path
T-->>HW: Derived address
HW-->>VM: Match or mismatch
Loading

Reviews (1): Last reviewed commit: "feat: add trezor receive" | Re-trigger Greptile

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The receive flow can complete verification for an address that is no longer displayed. I also found two smaller gaps in the Details actions and editor coverage.

Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt Outdated
Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreen.kt Outdated
@ovitrif

ovitrif commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

PLS add QA notes and Manual Tests + Automated Tests sections with details like we usually do for apps PRs. (this is more about formatting than content, content is a bit already there, just not structured in the same format we usually do)

@ovitrifovitrif added this to the 2.5.0 milestone Aug 27, 2026
@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

Updated the PR description with structured QA Notes, Manual Tests, and Automated Tests sections. I left the manual checks unchecked until they are run on Android.

coreyphillips
coreyphillips previously approved these changes Aug 28, 2026
ovitrif

This comment was marked as resolved.

Base automatically changed from feat/trezor-send to masterAugust 28, 2026 21:41
@ovitrif
ovitrif dismissed coreyphillips’s stale reviewAugust 28, 2026 21:41

The base branch was changed.

@piotr-iohk

piotr-iohk commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Tested on emulator and device (Samsung S22 + Trezor Safe 7).

Generally all good. Able to present the receive address, verify the address on the device, etc.

One observation (looks intentional in code, but may be misleading to the user): with 2+ paired hardware wallets (e.g. standard + passphrase), Home → Receive does not show the Trezor tab, so there is no hardware receive address from that entry point. Fine to defer to a follow-up PR — if that's the case, let's create a ticket for this.

Steps to reproduce

  1. Pair a Trezor (standard wallet). Home should show one hardware wallet tile.
  2. Add a passphrase wallet on the same device (Paired → Passphrase → enter passphrase). Home should now show two hardware wallet tiles.
  3. From the main/home screen, tap Receive.
  4. Only Savings / Spending tabs are shown. No Trezor tab, so you cannot get a hardware receive address.

Expected (or less misleading)

Home → Receive either shows a Trezor tab (or a wallet picker) when more than one hardware wallet is paired, or makes it clear that hardware receive is only available from the specific wallet screen.

Workaround

Open the specific hardware wallet screen first, then Receive. That path still shows the address.

Recording

Screen_Recording_20260901_102214_Bitkit.Regtest.mp4

piotr-iohk
piotr-iohk previously approved these changes Sep 1, 2026

@piotr-iohkpiotr-iohk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approve. Single-wallet receive looks good on emulator and device. See the QA comment for the multi-wallet Home Receive note (fine to defer).

@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

The single-wallet hardware Receive flow is green and the earlier change requests are resolved. I filed #1204 for the requested Home Receive wallet picker when multiple hardware wallets are paired. @ovitrif please re-review the current head so the stale change-request state can be cleared.

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The initial hardware receive load can still revert to a stale watcher address. I also found two regression-coverage gaps in the addressed UI fixes.

Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt Outdated
Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt Outdated
@coreyphillips
coreyphillips self-requested a review September 2, 2026 00:18
coreyphillips
coreyphillips previously approved these changes Sep 2, 2026
@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

Fixed all three review findings in signed commit d42064c: preserved newer watcher addresses against the fallback race, added the hardware Edit Invoice return-path regression, and added receive-specific passphrase-copy coverage. The focused unit suite passes, the Compose test suite compiles, and detekt passes. @ovitrif please re-review when fresh CI is ready.

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

utACK

Sign up for freeto 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.

Receive to hardware wallet

5 participants

@ben-kaufman@ovitrif@piotr-iohk@coreyphillips@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add trezor receive - #1189

Open
ben-kaufman wants to merge 7 commits into
masterfrom
feat/trezor-receive
Open

feat: add trezor receive#1189
ben-kaufman wants to merge 7 commits into
masterfrom
feat/trezor-receive

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Description

This PR:

  1. Adds a Trezor tab to the Receive flow with the current next-unused native SegWit watcher address, falling back to the existing account scan when watcher state is unavailable.
  2. Supports on-chain-only amount and note editing without starting Lightning receive work.
  3. Lets users copy or share the Trezor payment request and verify the displayed address on the connected device.
  4. Matches hardware receive styling with a white selected-tab underline, blue Bitcoin mark, and blue action icons.

Stack

Linked Issues/Tasks

Fixes#1202

QA Notes

Manual Tests

  • 1. Paired Trezor → Home → Receive → Trezor: the current native SegWit address and QR load with the hardware-wallet styling.
  • 2. Trezor Receive → Show Details → Verify on Device: the button shows a loading state, the device address exactly matches Bitkit, and approval completes without changing the displayed address or showing an error.
  • 3. Trezor Receive → edit amount and note → Show QR → Show Details → Copy/Share: the edit returns directly to the Trezor QR without tags or Lightning setup, and the payment request contains the Trezor address with the entered amount and note.
  • 4. Passphrase Trezor → Receive → Show Details → Verify on Device → enter the passphrase: the wallet reconnects and address verification resumes.
  • 5.regression: Start Verify on Device → while device approval is pending, fund the displayed regtest address and advance the watcher: the stale verification is cancelled and Bitkit displays and copies the new receive address.

Automated Tests

  • Unit tests added or extended in HwWalletRepoTest.kt: cover watcher-backed receive-address selection, stored-xpub fallback, and device-address mismatch rejection.
  • Unit tests added in HwReceiveViewModelTest.kt: cover address loading and reset, passphrase reconnection, live watcher-address updates, and cancellation of stale verification.
  • Unit tests extended in ReceiveInvoiceUtilsTest.kt: cover the hardware-only BIP21 destination, shared amount and note details, and zero-amount omission.
  • Compose UI coverage added in EditInvoiceContentTest.kt: verifies the on-chain-only hardware edit callback and hidden tag actions.
  • Hardware-wallet journey coverage added in receive-onchain.xml: defines the Trezor tab, QR, details, and exact on-device address-verification flow.
  • GitHub CI build and the full testDevDebugUnitTest suite pass; lint and detekt pass.
  • git diff --check passes.

@ben-kaufmanben-kaufman mentioned this pull request Aug 27, 2026
6 tasks
@greptile-apps

Copy link
Copy Markdown

Greptile Summary

Adds hardware-wallet receiving to the existing receive sheet, including watcher-backed address resolution, BIP21 editing, and on-device Trezor verification.

  • Adds a Trezor receive tab with QR, copy, share, details, and device-verification actions.
  • Resolves the next unused watcher address with an account-scan fallback.
  • Adds passphrase-aware verification state and watcher event coverage.
  • Updates bitkit-core and adds repository, view-model, invoice utility, and journey tests.

Confidence Score: 4/5

The PR should not merge until receive amount and note state is scoped so Savings edits cannot silently alter the Trezor payment request.

The Trezor QR directly consumes the same BIP21 metadata updated by Savings editing, causing a request for one account to be displayed for another account with unintended payment details.

Files Needing Attention: app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt, app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt

Important Files Changed

FilenameOverview
app/src/main/java/to/bitkit/repositories/HwWalletRepo.ktAdds watcher-backed receive-address lookup, account-scan fallback, typed watcher address data, and identity-aware Trezor address verification.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/HwReceiveViewModel.ktCoordinates address loading, watcher updates, verification retries, passphrase prompts, cancellation, and user-facing errors.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.ktAdds the Trezor tab and its actions, but incorrectly sources its amount and note from primary-wallet BIP21 metadata.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.ktWires hardware receive navigation and editing into the shared receive sheet, including the shared metadata path implicated in the finding.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveInvoiceUtils.ktBuilds hardware-wallet BIP21 requests and selects the blue Bitcoin QR logo.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreen.ktAdds an on-chain-only editing path that avoids Lightning receive work and hides tags.

Sequence Diagram

sequenceDiagram
participant U as User
participant UI as Receive Sheet
participant VM as Hardware Receive VM
participant HW as Hardware Wallet Repo
participant W as Watcher
participant T as Trezor
U->>UI: Open hardware-wallet receive
UI->>VM: loadAddress(walletId)
VM->>HW: getReceiveAddress(walletId)
HW->>W: Read next unused address
alt Watcher address available
W-->>HW: Address and derivation path
else Watcher state unavailable
HW->>T: Scan public account
T-->>HW: First unused address
end
HW-->>VM: Hardware receive address
VM-->>UI: Display QR and details
U->>UI: Verify on device
UI->>VM: verifyAddress()
VM->>HW: verifyReceiveAddress()
HW->>T: Display address at derivation path
T-->>HW: Derived address
HW-->>VM: Match or mismatch
Loading

Reviews (1): Last reviewed commit: "feat: add trezor receive" | Re-trigger Greptile

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The receive flow can complete verification for an address that is no longer displayed. I also found two smaller gaps in the Details actions and editor coverage.

Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt Outdated
Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreen.kt Outdated
@ovitrif

ovitrif commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

PLS add QA notes and Manual Tests + Automated Tests sections with details like we usually do for apps PRs. (this is more about formatting than content, content is a bit already there, just not structured in the same format we usually do)

@ovitrifovitrif added this to the 2.5.0 milestone Aug 27, 2026
@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

Updated the PR description with structured QA Notes, Manual Tests, and Automated Tests sections. I left the manual checks unchecked until they are run on Android.

coreyphillips
coreyphillips previously approved these changes Aug 28, 2026
ovitrif

This comment was marked as resolved.

Base automatically changed from feat/trezor-send to masterAugust 28, 2026 21:41
@ovitrif
ovitrif dismissed coreyphillips’s stale reviewAugust 28, 2026 21:41

The base branch was changed.

@piotr-iohk

piotr-iohk commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Tested on emulator and device (Samsung S22 + Trezor Safe 7).

Generally all good. Able to present the receive address, verify the address on the device, etc.

One observation (looks intentional in code, but may be misleading to the user): with 2+ paired hardware wallets (e.g. standard + passphrase), Home → Receive does not show the Trezor tab, so there is no hardware receive address from that entry point. Fine to defer to a follow-up PR — if that's the case, let's create a ticket for this.

Steps to reproduce

  1. Pair a Trezor (standard wallet). Home should show one hardware wallet tile.
  2. Add a passphrase wallet on the same device (Paired → Passphrase → enter passphrase). Home should now show two hardware wallet tiles.
  3. From the main/home screen, tap Receive.
  4. Only Savings / Spending tabs are shown. No Trezor tab, so you cannot get a hardware receive address.

Expected (or less misleading)

Home → Receive either shows a Trezor tab (or a wallet picker) when more than one hardware wallet is paired, or makes it clear that hardware receive is only available from the specific wallet screen.

Workaround

Open the specific hardware wallet screen first, then Receive. That path still shows the address.

Recording

Screen_Recording_20260901_102214_Bitkit.Regtest.mp4

piotr-iohk
piotr-iohk previously approved these changes Sep 1, 2026

@piotr-iohkpiotr-iohk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approve. Single-wallet receive looks good on emulator and device. See the QA comment for the multi-wallet Home Receive note (fine to defer).

@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

The single-wallet hardware Receive flow is green and the earlier change requests are resolved. I filed #1204 for the requested Home Receive wallet picker when multiple hardware wallets are paired. @ovitrif please re-review the current head so the stale change-request state can be cleared.

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The initial hardware receive load can still revert to a stale watcher address. I also found two regression-coverage gaps in the addressed UI fixes.

Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt Outdated
Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt Outdated
@coreyphillips
coreyphillips self-requested a review September 2, 2026 00:18
coreyphillips
coreyphillips previously approved these changes Sep 2, 2026
@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

Fixed all three review findings in signed commit d42064c: preserved newer watcher addresses against the fallback race, added the hardware Edit Invoice return-path regression, and added receive-specific passphrase-copy coverage. The focused unit suite passes, the Compose test suite compiles, and detekt passes. @ovitrif please re-review when fresh CI is ready.

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

utACK

Sign up for freeto 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.

Receive to hardware wallet

5 participants

@ben-kaufman@ovitrif@piotr-iohk@coreyphillips@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat: add trezor receive - #1189

Open
ben-kaufman wants to merge 7 commits into
masterfrom
feat/trezor-receive
Open

feat: add trezor receive#1189
ben-kaufman wants to merge 7 commits into
masterfrom
feat/trezor-receive

Conversation

@ben-kaufman

@ben-kaufmanben-kaufman commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Description

This PR:

  1. Adds a Trezor tab to the Receive flow with the current next-unused native SegWit watcher address, falling back to the existing account scan when watcher state is unavailable.
  2. Supports on-chain-only amount and note editing without starting Lightning receive work.
  3. Lets users copy or share the Trezor payment request and verify the displayed address on the connected device.
  4. Matches hardware receive styling with a white selected-tab underline, blue Bitcoin mark, and blue action icons.

Stack

Linked Issues/Tasks

Fixes#1202

QA Notes

Manual Tests

  • 1. Paired Trezor → Home → Receive → Trezor: the current native SegWit address and QR load with the hardware-wallet styling.
  • 2. Trezor Receive → Show Details → Verify on Device: the button shows a loading state, the device address exactly matches Bitkit, and approval completes without changing the displayed address or showing an error.
  • 3. Trezor Receive → edit amount and note → Show QR → Show Details → Copy/Share: the edit returns directly to the Trezor QR without tags or Lightning setup, and the payment request contains the Trezor address with the entered amount and note.
  • 4. Passphrase Trezor → Receive → Show Details → Verify on Device → enter the passphrase: the wallet reconnects and address verification resumes.
  • 5.regression: Start Verify on Device → while device approval is pending, fund the displayed regtest address and advance the watcher: the stale verification is cancelled and Bitkit displays and copies the new receive address.

Automated Tests

  • Unit tests added or extended in HwWalletRepoTest.kt: cover watcher-backed receive-address selection, stored-xpub fallback, and device-address mismatch rejection.
  • Unit tests added in HwReceiveViewModelTest.kt: cover address loading and reset, passphrase reconnection, live watcher-address updates, and cancellation of stale verification.
  • Unit tests extended in ReceiveInvoiceUtilsTest.kt: cover the hardware-only BIP21 destination, shared amount and note details, and zero-amount omission.
  • Compose UI coverage added in EditInvoiceContentTest.kt: verifies the on-chain-only hardware edit callback and hidden tag actions.
  • Hardware-wallet journey coverage added in receive-onchain.xml: defines the Trezor tab, QR, details, and exact on-device address-verification flow.
  • GitHub CI build and the full testDevDebugUnitTest suite pass; lint and detekt pass.
  • git diff --check passes.

@ben-kaufmanben-kaufman mentioned this pull request Aug 27, 2026
6 tasks
@greptile-apps

Copy link
Copy Markdown

Greptile Summary

Adds hardware-wallet receiving to the existing receive sheet, including watcher-backed address resolution, BIP21 editing, and on-device Trezor verification.

  • Adds a Trezor receive tab with QR, copy, share, details, and device-verification actions.
  • Resolves the next unused watcher address with an account-scan fallback.
  • Adds passphrase-aware verification state and watcher event coverage.
  • Updates bitkit-core and adds repository, view-model, invoice utility, and journey tests.

Confidence Score: 4/5

The PR should not merge until receive amount and note state is scoped so Savings edits cannot silently alter the Trezor payment request.

The Trezor QR directly consumes the same BIP21 metadata updated by Savings editing, causing a request for one account to be displayed for another account with unintended payment details.

Files Needing Attention: app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt, app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt

Important Files Changed

FilenameOverview
app/src/main/java/to/bitkit/repositories/HwWalletRepo.ktAdds watcher-backed receive-address lookup, account-scan fallback, typed watcher address data, and identity-aware Trezor address verification.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/HwReceiveViewModel.ktCoordinates address loading, watcher updates, verification retries, passphrase prompts, cancellation, and user-facing errors.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.ktAdds the Trezor tab and its actions, but incorrectly sources its amount and note from primary-wallet BIP21 metadata.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.ktWires hardware receive navigation and editing into the shared receive sheet, including the shared metadata path implicated in the finding.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveInvoiceUtils.ktBuilds hardware-wallet BIP21 requests and selects the blue Bitcoin QR logo.
app/src/main/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreen.ktAdds an on-chain-only editing path that avoids Lightning receive work and hides tags.

Sequence Diagram

sequenceDiagram
participant U as User
participant UI as Receive Sheet
participant VM as Hardware Receive VM
participant HW as Hardware Wallet Repo
participant W as Watcher
participant T as Trezor
U->>UI: Open hardware-wallet receive
UI->>VM: loadAddress(walletId)
VM->>HW: getReceiveAddress(walletId)
HW->>W: Read next unused address
alt Watcher address available
W-->>HW: Address and derivation path
else Watcher state unavailable
HW->>T: Scan public account
T-->>HW: First unused address
end
HW-->>VM: Hardware receive address
VM-->>UI: Display QR and details
U->>UI: Verify on device
UI->>VM: verifyAddress()
VM->>HW: verifyReceiveAddress()
HW->>T: Display address at derivation path
T-->>HW: Derived address
HW-->>VM: Match or mismatch
Loading

Reviews (1): Last reviewed commit: "feat: add trezor receive" | Re-trigger Greptile

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The receive flow can complete verification for an address that is no longer displayed. I also found two smaller gaps in the Details actions and editor coverage.

Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt Outdated
Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreen.kt Outdated
@ovitrif

ovitrif commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

PLS add QA notes and Manual Tests + Automated Tests sections with details like we usually do for apps PRs. (this is more about formatting than content, content is a bit already there, just not structured in the same format we usually do)

@ovitrifovitrif added this to the 2.5.0 milestone Aug 27, 2026
@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

Updated the PR description with structured QA Notes, Manual Tests, and Automated Tests sections. I left the manual checks unchecked until they are run on Android.

coreyphillips
coreyphillips previously approved these changes Aug 28, 2026
ovitrif

This comment was marked as resolved.

Base automatically changed from feat/trezor-send to masterAugust 28, 2026 21:41
@ovitrif
ovitrif dismissed coreyphillips’s stale reviewAugust 28, 2026 21:41

The base branch was changed.

@piotr-iohk

piotr-iohk commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Tested on emulator and device (Samsung S22 + Trezor Safe 7).

Generally all good. Able to present the receive address, verify the address on the device, etc.

One observation (looks intentional in code, but may be misleading to the user): with 2+ paired hardware wallets (e.g. standard + passphrase), Home → Receive does not show the Trezor tab, so there is no hardware receive address from that entry point. Fine to defer to a follow-up PR — if that's the case, let's create a ticket for this.

Steps to reproduce

  1. Pair a Trezor (standard wallet). Home should show one hardware wallet tile.
  2. Add a passphrase wallet on the same device (Paired → Passphrase → enter passphrase). Home should now show two hardware wallet tiles.
  3. From the main/home screen, tap Receive.
  4. Only Savings / Spending tabs are shown. No Trezor tab, so you cannot get a hardware receive address.

Expected (or less misleading)

Home → Receive either shows a Trezor tab (or a wallet picker) when more than one hardware wallet is paired, or makes it clear that hardware receive is only available from the specific wallet screen.

Workaround

Open the specific hardware wallet screen first, then Receive. That path still shows the address.

Recording

Screen_Recording_20260901_102214_Bitkit.Regtest.mp4

piotr-iohk
piotr-iohk previously approved these changes Sep 1, 2026

@piotr-iohkpiotr-iohk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approve. Single-wallet receive looks good on emulator and device. See the QA comment for the multi-wallet Home Receive note (fine to defer).

@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

The single-wallet hardware Receive flow is green and the earlier change requests are resolved. I filed #1204 for the requested Home Receive wallet picker when multiple hardware wallets are paired. @ovitrif please re-review the current head so the stale change-request state can be cleared.

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The initial hardware receive load can still revert to a stale watcher address. I also found two regression-coverage gaps in the addressed UI fixes.

Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt Outdated
Comment threadapp/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt Outdated
@coreyphillips
coreyphillips self-requested a review September 2, 2026 00:18
coreyphillips
coreyphillips previously approved these changes Sep 2, 2026
@ben-kaufman

Copy link
Copy Markdown
ContributorAuthor

Fixed all three review findings in signed commit d42064c: preserved newer watcher addresses against the fallback race, added the hardware Edit Invoice return-path regression, and added receive-specific passphrase-copy coverage. The focused unit suite passes, the Compose test suite compiles, and detekt passes. @ovitrif please re-review when fresh CI is ready.

@ovitrifovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

utACK

Sign up for freeto 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.

Receive to hardware wallet

5 participants

@ben-kaufman@ovitrif@piotr-iohk@coreyphillips@jvsena42