Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
4434872
specs: automatic dust UTXO classification and manual spendability man…
Parsh May 19, 2026
64c3a79
refactor: remove "Includes Do Not Spend coins" warning line from Wall…
Parsh May 19, 2026
b89558e
feat: add spendability and manual override properties to UTXO interfa…
Parsh May 19, 2026
ac4250d
feat: implement dust limit protection by adding spendability manageme…
Parsh May 19, 2026
44cb913
feat: implement UTXO spendability management and enhance UI with Do N…
Parsh May 19, 2026
f70ce9b
feat: add unit tests for spendability lookup logic in useUTXOSpendabi…
Parsh May 19, 2026
5e0ab46
fix: enhance UTXO management with live wallet updates and improved wa…
Parsh May 19, 2026
5bb7703
specs: implement Do Not Spend UTXO restrictions in coin selection and…
Parsh May 19, 2026
7a39804
feat: implement Do Not Spend coin handling in UTXO management and enh…
Parsh May 19, 2026
5310c0d
feat: remove insufficient spendable balance warning in send flow and …
Parsh May 20, 2026
5e81bb2
specs: "Donate Dust" feature to clear Do Not Spend UTXOs with a singl…
Parsh May 20, 2026
f7fda77
feat: implement "Donate Dust" feature to handle Do Not Spend UTXOs an…
Parsh May 20, 2026
433fdbc
spec(dust-classification): Implement address-level taint model for du…
Parsh May 25, 2026
f279ada
feat: add potential dust spend indicators and enhance UTXO management…
Parsh May 25, 2026
28b03be
feat: implement address-level taint classification for dust UTXOs and…
Parsh May 25, 2026
76c6e4f
feat: refactor dust classification tests to use classifyDustByAddress…
Parsh May 25, 2026
baad04b
specs: Dust Report feature with scanning, reporting, and donation cap…
Parsh May 26, 2026
c70848b
feat: add Dust Report feature with localization, scanning, and donati…
Parsh May 26, 2026
4ad1392
feat: enhance Dust Report integration in Vault Settings and localizat…
Parsh May 26, 2026
b5771a4
Merge pull request #6988 from KeeperCommunity/feat/dust-analysis-report
Parsh May 26, 2026
7718a6c
feat: preserve doNotSpend classification during soft/hard refresh in …
Parsh May 26, 2026
ac02277
Merge pull request #6985 from KeeperCommunity/feat/dust-descendant-cl…
Parsh May 26, 2026
5080a33
Merge pull request #6978 from KeeperCommunity/feat/dust-donation
Parsh May 26, 2026
4bd0420
Merge pull request #6976 from KeeperCommunity/feat/dust-utxo-spend
Parsh May 26, 2026
815e6f0
feat: add dust protection flows for classification, donation, and ana…
Parsh May 26, 2026
32c25e1
Merge branch 'sprint' into feat/dust-limit-protection
Parsh May 26, 2026
2699646
feat: update dust report terminology for clarity in linked coins section
Parsh May 27, 2026
bc0b179
feat: simplify dust report terminology and enhance UI indicators for …
Parsh May 27, 2026
5971376
feat: enhance dust report with additional information and modal for u…
Parsh May 27, 2026
eaf85d9
feat: enhance UTXO and transaction details display with additional id…
Parsh May 27, 2026
6f648bc
fix: do not spend labels in UTXO labeling
Parsh May 27, 2026
f093be5
Merge pull request #6993 from KeeperCommunity/feat/dust-analysis-report
Parsh May 27, 2026
21af15e
feat: removed extra horizontal gutter in DustReportScreen
cakesoft-vaibhav May 27, 2026
d97d513
fix: include manually marked Do Not Spend coins(w/ no dust reason) in…
Parsh May 27, 2026
162ff78
feat: update dust report descriptions for clarity and user guidance
Parsh May 27, 2026
bde58ae
Merge pull request #6994 from KeeperCommunity/feat/dust-analysis-report
Parsh May 27, 2026
2a02f45
feat: refactor getSpendableUTXOs method for automatic coin selection
Parsh May 28, 2026
c9940a1
Merge branch 'sprint' into feat/dust-limit-protection
Parsh May 29, 2026
473caa3
archived: dust-utxo-classification
Parsh May 29, 2026
bec79a2
archive: dust spend restirctions
Parsh May 29, 2026
4fed456
adds: unified dust-protection spec
Parsh May 29, 2026
2be2ec6
archive: dust-donation
Parsh May 29, 2026
5c1c2ee
archive: dust-descendant-classification
Parsh May 29, 2026
97faa99
archive: dust-analysis-report
Parsh May 29, 2026
7e41aeb
Merge branch 'sprint' into feat/dust-limit-protection
Parsh Jun 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 156 additions & 0 deletions flows/dustAnalysisReport.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
appId: io.hexawallet.keeper
---
# Tests the complete Dust Report flow available from Wallet Settings.
# Covers: settings entry point, start screen, scanning phase, result screens
# (findings and empty state), error state cancel path, and the inline
# Donate Dust confirmation sheet.

# ── Navigate to Wallet Settings ───────────────────────────────────────────
- tapOn:
id: 'view_wallet_0'
index: 0
- waitForAnimationToEnd:
timeout: 3000
- swipe:
from:
id: 'list_transactions'
direction: DOWN
duration: 2000
- waitForAnimationToEnd:
timeout: 5000
- repeat:
while:
visible:
id: 'icon_unconfirmed_0'
commands:
- runFlow: refreshwallet.yaml
- tapOn:
id: 'btn_Settings'
- waitForAnimationToEnd:
timeout: 1000

# ── Wallet Settings: assert Dust Report row ───────────────────────────────
- assertVisible: 'Dust Report'
- assertVisible: 'View potential dust activity for this wallet'

# ── Open Dust Report ──────────────────────────────────────────────────────
- tapOn:
id: 'btn_setting_Dust Report'
- waitForAnimationToEnd:
timeout: 2000

# ── Start screen assertions ───────────────────────────────────────────────
- assertTrue: ${output.text_header_title = "Dust Report"}
- assertVisible: 'Keeper can scan this wallet for dust activity and show coins that may reduce privacy if spent.'
- assertVisible:
id: 'btn_primaryText'
- assertVisible:
id: 'btn_secondaryText'

# ── Cancel from start screen ──────────────────────────────────────────────
- tapOn:
id: 'btn_secondaryText'
- waitForAnimationToEnd:
timeout: 1000
# Back on Wallet Settings
- assertVisible: 'Dust Report'

# ── Re-open and Run Report ────────────────────────────────────────────────
- tapOn:
id: 'btn_setting_Dust Report'
- waitForAnimationToEnd:
timeout: 2000
- tapOn:
id: 'btn_primaryText'
- waitForAnimationToEnd:
timeout: 2000

# ── Scanning phase assertions ─────────────────────────────────────────────
- assertTrue: ${output.text_header_title = "Scanning Wallet"}
- assertVisible: 'Keeper is checking this wallet for potential dust activity. This may take a few minutes.'

# Wait up to 90 s for the scan to finish (Electrum round-trip + backfill)
- extendedWaitUntil:
notVisible: 'Scanning Wallet'
timeout: 90000
- waitForAnimationToEnd:
timeout: 2000

# ── Result screen: findings or empty state ────────────────────────────────
- runFlow:
when:
visible: 'Dust Report'
commands:
# ── Findings result ─────────────────────────────────────────────────
- runFlow:
when:
visible: 'Keeper found coins or transactions that may reduce wallet privacy.'
commands:
- assertVisible: 'Keeper found coins or transactions that may reduce wallet privacy.'
# Summary card
- assertVisible: 'Do Not Spend coins'
- assertVisible: 'Amount'
- assertVisible: 'Past dust spends'
- assertVisible: 'Last scanned'
# Section headers
- assertVisible: 'Active Dust'
- assertVisible: 'Linked Coins'
- assertVisible: 'Past Dust Spends'
# Inline Donate Dust CTA (only when eligible DNS UTXOs exist)
- runFlow:
when:
id: 'btn_secondaryText'
commands:
- tapOn:
id: 'btn_secondaryText'
- waitForAnimationToEnd:
timeout: 1000
# Donate Dust confirmation modal
- assertVisible: 'Donate Dust'
- assertVisible: 'Donating can help clear dust / Do Not Spend coins for better privacy.'
# Dismiss via Cancel
- tapOn:
id: 'btn_secondaryText'
- waitForAnimationToEnd:
timeout: 1000
# Done CTA
- tapOn:
id: 'btn_primaryText'
- waitForAnimationToEnd:
timeout: 1000

- runFlow:
when:
visible: 'No Dust Found'
commands:
# ── Empty state ─────────────────────────────────────────────────────
- assertTrue: ${output.text_header_title = "No Dust Found"}
- assertVisible: 'Keeper did not find potential dust activity in this wallet.'
# No "Donate Dust" secondary button in empty state
- assertNotVisible: 'Donate Dust'
- tapOn:
id: 'btn_primaryText'
- waitForAnimationToEnd:
timeout: 1000

# ── Error state path (separate run) ──────────────────────────────────────
# This block is skipped unless a network failure causes the scan to fail.
- runFlow:
when:
visible: 'Report Not Completed'
commands:
- assertTrue: ${output.text_header_title = "Report Not Completed"}
- assertVisible: 'Keeper could not complete the dust report. Try again.'
- assertVisible: 'Try Again'
- assertVisible: 'Cancel'
# Cancel returns to Wallet Settings
- tapOn:
id: 'btn_secondaryText'
- waitForAnimationToEnd:
timeout: 1000

# ── Navigate back to Home ─────────────────────────────────────────────────
- tapOn:
id: 'btn_back'
repeat: 2
delay: 500
69 changes: 69 additions & 0 deletions flows/dustDescendantClassification.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
appId: io.hexawallet.keeper
---
# Precondition: Wallet at index 0 must have UTXOs with the full address-taint
# model applied (dust-descendant-classification). This requires:
# - At least one UTXO with dustReason 'descendant' or 'adjacent' (classified
# via BFS forward propagation from an initially tainted address)
# - At least one transaction tagged 'potential-dust-spend' in the wallet's
# transaction history
# Run a full dust scan (hardRefresh + dustScan: true) before this flow.

# ── Navigate to Wallet Details ─────────────────────────────────────────────
- tapOn:
id: 'view_wallet_0'
index: 0
- waitForAnimationToEnd:
timeout: 3000

# ── Open Manage Coins (UTXOManagement) ────────────────────────────────────
- tapOn: 'View All Coins'
- waitForAnimationToEnd:
timeout: 3000

# ── Descendant / adjacent UTXOs show "Do Not Spend" chip ─────────────────
- assertVisible: 'Do Not Spend'

# ── Tap a Do Not Spend UTXO that carries a descendant or adjacent reason ──
# We tap the second occurrence to increase the chance of hitting a non-initial
# UTXO. Adjust the index if the wallet layout differs.
- tapOn:
text: 'Do Not Spend'
index: 1
- waitForAnimationToEnd:
timeout: 2000

# ── UTXO Details: descendant reason string ───────────────────────────────
# A descendant/adjacent UTXO shows "Linked to potential dust spend" as its
# reason. If only initial UTXOs are present the assertion is skipped via runFlow.
- runFlow:
when:
visible: 'Linked to potential dust spend'
commands:
- assertVisible: 'Linked to potential dust spend'
- assertVisible: 'Keeper marked this coin Do Not Spend to help protect wallet privacy.'
- assertVisible: 'Mark Spendable'

# ── Navigate back to Wallet Details ──────────────────────────────────────
- tapOn:
id: 'btn_back'
- waitForAnimationToEnd:
timeout: 1000

# ── Transaction history: assert Potential dust spend label ────────────────
# Scroll the transaction list to surface labelled transactions.
- swipe:
from:
id: 'list_transactions'
direction: UP
duration: 1000
- waitForAnimationToEnd:
timeout: 2000
- runFlow:
when:
visible: 'Potential dust spend'
commands:
- assertVisible: 'Potential dust spend'

# ── Navigate back to Home ─────────────────────────────────────────────────
- tapOn:
id: 'btn_back'
80 changes: 80 additions & 0 deletions flows/dustDonation.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
appId: io.hexawallet.keeper
---
# Precondition: Wallet at index 0 must have at least one UTXO classified as
# doNotSpend so that the Donate Dust footer CTA and the confirmation sheet are
# available. This flow exercises the donation confirmation UI and the cancel
# path. The actual broadcast is not triggered so no test funds are spent.

# ── Navigate to Wallet Details ─────────────────────────────────────────────
- tapOn:
id: 'view_wallet_0'
index: 0
- waitForAnimationToEnd:
timeout: 3000

# ── Open Manage Coins ─────────────────────────────────────────────────────
- tapOn: 'View All Coins'
- waitForAnimationToEnd:
timeout: 3000

# ── Assert Donate Dust footer CTA is visible ─────────────────────────────
- assertVisible:
id: 'btn_Donate Dust'

# ── Tap Donate Dust to open confirmation sheet ────────────────────────────
- tapOn:
id: 'btn_Donate Dust'
- waitForAnimationToEnd:
timeout: 2000

# ── Assert confirmation modal content ────────────────────────────────────
- assertVisible: 'Donate Dust?'
- assertVisible: 'Donating can help clear dust / Do Not Spend coins for better privacy.'

# ── Cancel path: sheet closes without navigating ─────────────────────────
- tapOn:
id: 'btn_secondaryText'
- waitForAnimationToEnd:
timeout: 1000
# Modal dismissed; Manage Coins screen is still visible
- assertVisible:
id: 'btn_Donate Dust'

# ── Confirm path: tap Donate Dust primary button ──────────────────────────
- tapOn:
id: 'btn_Donate Dust'
- waitForAnimationToEnd:
timeout: 2000
- assertVisible: 'Donate Dust?'
- tapOn:
id: 'btn_primaryText'
- waitForAnimationToEnd:
timeout: 5000

# After confirming, one of two outcomes occurs:
# 1. Navigation to SendConfirmation (donation amount > fee)
# 2. Toast "These coins are too small to donate" (amount <= fee)
- runFlow:
when:
visible: 'Sending to address'
commands:
# Donation mode: fee priority switcher must NOT be visible (locked to Low)
- assertNotVisible: 'Transaction Priority'
# Navigate back without broadcasting
- tapOn:
id: 'btn_back'
- waitForAnimationToEnd:
timeout: 1000
- runFlow:
when:
visible: 'These coins are too small to donate on their own.'
commands:
- assertVisible: 'These coins are too small to donate on their own.'

# ── Navigate back to Home ─────────────────────────────────────────────────
- tapOn:
id: 'btn_back'
- waitForAnimationToEnd:
timeout: 500
- tapOn:
id: 'btn_back'
31 changes: 31 additions & 0 deletions flows/dustSanity.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
appId: io.hexawallet.keeper
---
# Sanity flow that exercises the full dust protection feature suite in order.
# Requires: wallet at index 0 has at least one dust UTXO (< 5,000 sats on a
# reused or out-of-order address) that has been classified as doNotSpend by a
# prior refresh. Run refreshwallet.yaml first if needed.
#
# Flows exercised (in dependency order):
# 1. dustUTXOClassification — detection, UI indicators, manual overrides
# 2. dustDescendantClassification — BFS taint propagation + tx labels
# 3. dustSpendRestrictions — balance filter + selection warning modal
# 4. dustDonation — Donate Dust CTA + confirmation sheet
# 5. dustAnalysisReport — Wallet Settings entry → full report flow

- runFlow: dustUTXOClassification.yaml
- waitForAnimationToEnd:
timeout: 2000

- runFlow: dustDescendantClassification.yaml
- waitForAnimationToEnd:
timeout: 2000

- runFlow: dustSpendRestrictions.yaml
- waitForAnimationToEnd:
timeout: 2000

- runFlow: dustDonation.yaml
- waitForAnimationToEnd:
timeout: 2000

- runFlow: dustAnalysisReport.yaml
Loading
Loading