feat(ui): shielded operations in the home transaction history#838
Merged
QuantumExplorer merged 4 commits intoJul 17, 2026
Conversation
The home history read only the Core SwiftData rows, so purely shielded operations — private receives and sends, Platform↔Shielded moves, shielded identity fundings — were invisible: the list showed at most the L1 legs. Merge the SDK's PersistentShieldedActivity timeline into the same day-grouped list. - ShieldedActivityItem: immutable projection of one activity row (credits→duffs, kind/direction/status enums, decoded text memo), with row display (title, route pill, shield icon + kind badge, signed amount, live fiat, Pending/Failed trailing status). - Kinds whose Core leg already renders are NOT projected — ShieldFromAssetLock (Transaction.isShieldedTransfer row) and Withdrawal (Transaction.isShieldedWithdrawalReceipt row) — so one user action never shows as two rows; entries are deduped by entryId across accounts (outgoing side wins). - New TransactionListDataItem.shieldedActivity case flows through the existing sort/group pipeline; the NSManagedObjectContextDidSave reload trigger already covers the shielded persister's saves. - The Shielded sent/received filter categories now match these rows (previously they only matched the Core legs). - Tapping opens ShieldedActivityDetailsView in the standard bottom sheet — deliberately simpler than TXDetailVC since a shielded entry has no addresses/inputs/outputs to enumerate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Platform↔Shielded moves carry the shielded pool's perspective in their recorded direction (a shield is "incoming"), but no funds were gained or lost — show them unsigned like self-transfers, in the row and the detail sheet. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A Platform↔Shielded row is self-originated by construction — the
shield/unshield kinds are only ever live-recorded for this wallet's
own operation; the restore-path scan can't prove origin and never
labels anything a shield (an old own-shield resurfaces as plain
Received). Surface that guarantee as explicit From/To rows ("Your
Platform balance" → "Your Shielded balance") in the detail sheet.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The withdrawal kind was excluded from the merged history on the assumption its Core receipt row always represents it — true only when the destination is one of the active wallet's own addresses. A withdrawal to an EXTERNAL Core address produces no wallet-side Core transaction at all, so the operation vanished from the timeline entirely (QA repro: a 2.45 DASH withdrawal to yQRyiz… was invisible). Fetch now decodes the entry's counterparty script and keeps the entry unless that address belongs to the active wallet's Core pools (active-wallet scoped on purpose: another on-device wallet's address is still external from this wallet's perspective). External withdrawals render as signed Sent rows with the shortened destination in the pill and the full address as the detail sheet's To row; undecodable-script withdrawals are shown rather than hidden — losing money from the timeline is the worse failure. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The home history reads only the Core SwiftData rows, so purely shielded operations were invisible. Private receives, private sends, Platform → Shielded moves, and shielded identity fundings never appeared — the list showed at most the L1 legs of shielded flows.
What this does
Merges the SDK's
PersistentShieldedActivitytimeline (live-recorded per operation, scan-derived on restore) into the same day-grouped history list as the Core rows.ShieldedActivityItem(ShieldedActivityHistory.swift): immutable projection of one activity row — credits→duffs, kind/direction/status, decoded 36-byte text memo — plus row display: kind title, route pill ("Platform → Shielded" / "Shielded → Platform" / "Shielded", memo wins when present), shield icon with a per-kind corner badge, signed amount, live fiat, Pending/Failed trailing status.Transaction.isShieldedTransfer), and Withdrawal only when its destination script is one of the active wallet's own Core addresses (the Core receipt viaisShieldedWithdrawalReceipt). A withdrawal to an EXTERNAL Core address produces no wallet-side Core transaction, so it stays in the merged list as a signed Sent row with the destination address (shortened in the row pill, full in the detail sheet). Entries are also deduped byentryIdacross accounts (an intra-wallet transfer writes Sent + Received rows for one operation; the initiating side wins).TransactionListDataItem.shieldedActivitycase flows through the existing filter → sort → day-group pipeline. TheNSManagedObjectContextDidSavereload trigger already fires on the shielded persister's saves, so rows appear live.ShieldedActivityDetailsViewin the standard bottom sheet — type, status, block, exact fee when recorded, copyable created-identity id, date, and the honest restore-path footnote for unclassifiableShieldedSpendresiduals. Deliberately simpler thanTXDetailVC: a shielded entry has no addresses or inputs/outputs to enumerate — that's the point of it.Test plan
🤖 Generated with Claude Code