Skip to content

fix(swift-sdk): show combined wallet balance on Wallets list#3537

Merged
QuantumExplorer merged 1 commit into
v3.1-devfrom
claude/awesome-gauss-e7fced
Apr 25, 2026
Merged

fix(swift-sdk): show combined wallet balance on Wallets list#3537
QuantumExplorer merged 1 commit into
v3.1-devfrom
claude/awesome-gauss-e7fced

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented Apr 25, 2026

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

On the Wallets tab the wallet row showed "Empty" and "No Core balance" even when the wallet had a non-zero Platform balance (visible in BalanceCardView on the wallet detail screen). The summary row was inconsistent with the detail card and hid funds from users.

What was done?

Updated WalletRowView in CoreContentView.swift to mirror BalanceCardView's balance logic:

  • Added a @Query for PersistentPlatformAddress filtered by walletId so the row picks up BLAST-synced address credits (with the existing identity-credit sum kept as a fallback for the pre-sync state).
  • Replaced the totalCoreBalance == 0 ? "Empty" check at the top-right with a combined Core + Platform balance rendered in DASH. "Empty" is only shown when both Core and Platform balances are zero.
  • Extracted a formatDash(_:) helper so duff- and credit-derived amounts share the same formatter (Core uses 1e8 duffs/DASH; Platform uses 1e11 credits/DASH).

Row 5 ("Platform: X DASH • walletId") now also picks up BLAST-synced balances via the same platformBalance computation.

How Has This Been Tested?

  • xcodebuild -project SwiftExampleApp/SwiftExampleApp.xcodeproj -scheme SwiftExampleApp -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 17 Pro,arch=arm64' build succeeds.
  • Manually verified against a testnet wallet (Wallet1, ID 73c5dc…98c4e2) that previously showed "Empty" / "No Core balance" despite holding 0.24581622 DASH on the Platform side; the row now shows the combined DASH total at the top-right.

Breaking Changes

None — UI-only change in the example app.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved wallet balance display to accurately show combined values from multiple sources.
    • Enhanced balance calculation and formatting for better accuracy.
    • Refined empty wallet state display and visual styling.

The wallet row used only Core balance to decide whether to display
"Empty" and only summed identity credits for Platform — so a wallet
funded via Platform Payment addresses (no identities) showed
"Empty" even when BalanceCardView showed a non-zero Platform
Balance.

Mirror BalanceCardView's logic on the row: query
PersistentPlatformAddress by walletId for BLAST-synced credits
(falling back to identity credits), and render the combined
Core+Platform total in DASH at the top-right. "Empty" is only
shown when both sides are zero.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added this to the v3.1.0 milestone Apr 25, 2026
@coderabbitai

coderabbitai Bot commented Apr 25, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

WalletRowView now integrates platform-derived balances from BLAST-synced address records with core balances. The view queries per-wallet PersistentPlatformAddress records and computes combined DASH values from both core (duffs) and platform (credits) using explicit scaling constants, with platform balance preferred when address-derived credits exist. New formatDash(_:) helper and updated balance formatting logic.

Changes

Cohort / File(s) Summary
WalletRowView Balance Integration
packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CoreContentView.swift
Updated balance computation to query per-wallet PersistentPlatformAddress records, compute platform-derived balances, and display combined DASH values from core and platform sources. Added formatDash(_:) helper and updated display logic to prefer platform balance when credits are available. Text display and color now depend on combined balance state.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 With BLAST and credits now aligned,
The wallet's riches, both entwined,
Platform balances gently blend,
With core and duffs that comprehend,
A DASH of format, balanced and refined! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: combining wallet balances (Core + Platform) to display on the Wallets list view, directly addressing the issue where Platform balances were hidden.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/awesome-gauss-e7fced

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@thepastaclaw

thepastaclaw commented Apr 25, 2026

Copy link
Copy Markdown
Collaborator

🕓 Ready for review — 12 ahead in queue (commit 2a99e9d)
Queue position: 13/18

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CoreContentView.swift (1)

685-690: Centralize duff/credit conversion constants.

100_000_000.0 and 100_000_000_000.0 are now repeated across formatBalance, combinedDashAmount, formatCredits (here and in the CoreContentView extension at lines 1014–1026). A single private constant pair (e.g. private static let duffsPerDash = 100_000_000.0, creditsPerDash = 100_000_000_000.0) would prevent future drift between the row and detail formatters.

Also applies to: 715-734

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

In
`@packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CoreContentView.swift`
around lines 685 - 690, Replace repeated numeric literals with centralized
constants by adding two private static constants on CoreContentView (e.g.,
private static let duffsPerDash = 100_000_000.0 and private static let
creditsPerDash = 100_000_000_000.0) and update all uses to reference these
constants: combinedDashAmount, formatBalance, formatCredits, and the
CoreContentView extension formatting methods. Ensure you use
CoreContentView.duffsPerDash and .creditsPerDash (or self.) consistently so both
row and detail formatters share the same conversion factors.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CoreContentView.swift`:
- Around line 685-694: The header can show "0 DASH" for tiny platform-only
balances because combinedDashAmount is formatted with formatDash (max 8 fraction
digits) while platform credits resolve to 1e‑11 DASH; update the header
formatting to handle platform-only balances by detecting the platform-only case
(totalCoreBalance == 0 && platformBalance > 0) and either (A) format using
higher precision (raise maximumFractionDigits to cover 1e‑11 when computing
combinedDashAmount for display) or (B) display the platform amount using
credits/formatCredits instead of DASH; locate and change the logic around
combinedDashAmount and hasAnyBalance to branch the header formatting accordingly
so the header is consistent with row formatting.
- Around line 669-678: platformBalance incorrectly falls back to identity
credits whenever blastBalance == 0, but must only do so if the wallet has never
synced; locate the platformBalance computed property and modify its logic to
query PersistentSyncState (e.g. access syncStates similar to BalanceCardView) to
detect whether the wallet has been synced at least once — if blastBalance > 0
return blastBalance, else if the wallet has a syncState indicating it has
previously synced return 0, otherwise fall back to summing identitiesForWallet
balances; ensure you reference the same sync state key/lookup used by
BalanceCardView so behavior is consistent.

---

Nitpick comments:
In
`@packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CoreContentView.swift`:
- Around line 685-690: Replace repeated numeric literals with centralized
constants by adding two private static constants on CoreContentView (e.g.,
private static let duffsPerDash = 100_000_000.0 and private static let
creditsPerDash = 100_000_000_000.0) and update all uses to reference these
constants: combinedDashAmount, formatBalance, formatCredits, and the
CoreContentView extension formatting methods. Ensure you use
CoreContentView.duffsPerDash and .creditsPerDash (or self.) consistently so both
row and detail formatters share the same conversion factors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1898d8f1-c414-43e4-a4f9-957531f7eeb5

📥 Commits

Reviewing files that changed from the base of the PR and between 32edf1c and 2a99e9d.

📒 Files selected for processing (1)
  • packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CoreContentView.swift

Comment on lines +669 to 678
/// Platform balance in credits: prefer BLAST address sync, fall
/// back to summing identity credits when no addresses have been
/// synced yet.
private var platformBalance: UInt64 {
identitiesForWallet.reduce(0) { $0 + UInt64(bitPattern: $1.balance) }
let blastBalance = addressBalances.reduce(UInt64(0)) { $0 + $1.balance }
if blastBalance > 0 { return blastBalance }
return identitiesForWallet.reduce(UInt64(0)) {
$0 + UInt64(bitPattern: $1.balance)
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -t f BalanceCardView.swift packages/swift-sdk | xargs -I{} sh -c 'echo "=== {} ==="; cat "{}"'

Repository: dashpay/platform

Length of output: 42


🏁 Script executed:

# Search for BalanceCardView references in the codebase
rg -i "BalanceCardView" packages/swift-sdk --type swift

Repository: dashpay/platform

Length of output: 459


🏁 Script executed:

# List all Swift view files in the core views directory
fd -t f "\.swift$" packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views | head -20

Repository: dashpay/platform

Length of output: 1097


🏁 Script executed:

# Check the full platformBalance context in CoreContentView.swift
sed -n '650,700p' packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CoreContentView.swift

Repository: dashpay/platform

Length of output: 1995


🏁 Script executed:

# Find and read WalletDetailView.swift, focusing on BalanceCardView
fd -t f WalletDetailView.swift packages/swift-sdk | xargs -I{} sh -c 'wc -l "{}"; echo ""; cat -n "{}"' | head -300

Repository: dashpay/platform

Length of output: 13278


🏁 Script executed:

# Get the BalanceCardView struct implementation
sed -n '400,600p' packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/WalletDetailView.swift

Repository: dashpay/platform

Length of output: 7577


🏁 Script executed:

# Get the full BalanceCardView platformBalance implementation
sed -n '530,560p' packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/WalletDetailView.swift

Repository: dashpay/platform

Length of output: 1390


🏁 Script executed:

# Check if CoreContentView has any syncStates query or similar
grep -n "syncStates\|PersistentSyncState\|hasSynced" packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CoreContentView.swift

Repository: dashpay/platform

Length of output: 42


🏁 Script executed:

# Get lines around platformBalance in BalanceCardView
sed -n '530,555p' packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/WalletDetailView.swift

Repository: dashpay/platform

Length of output: 1096


🏁 Script executed:

# Get the complete BalanceCardView struct with more lines
sed -n '500,580p' packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/WalletDetailView.swift

Repository: dashpay/platform

Length of output: 3234


🏁 Script executed:

# Get the platformBalance method in BalanceCardView
sed -n '575,610p' packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/WalletDetailView.swift

Repository: dashpay/platform

Length of output: 1384


🏁 Script executed:

# Confirm the CoreContentView platformBalance and check if syncStates exists
sed -n '650,680p' packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CoreContentView.swift

Repository: dashpay/platform

Length of output: 1273


Implementation does not achieve parity with BalanceCardView — missing sync state tracking.

The platformBalance logic in CoreContentView (lines 669–678) falls back to identity credits whenever blastBalance == 0, but BalanceCardView only falls back when the wallet has never synced. BalanceCardView queries PersistentSyncState to distinguish "synced with zero balance" from "not yet synced", and returns zero credits in the synced-but-empty case. CoreContentView lacks this distinction, so it will incorrectly display stale identity credits on a wallet that has been BLAST-synced but now holds zero platform credits.

To match BalanceCardView, add the syncStates query and check:

♻️ Proposed change
    `@Query` private var addressBalances: [PersistentPlatformAddress]

+   `@Query` private var syncStates: [PersistentSyncState]

    init(wallet: PersistentWallet) {
        self.wallet = wallet
        let walletId = wallet.walletId
+       let networkName = wallet.network
        _addressBalances = Query(
            filter: `#Predicate`<PersistentPlatformAddress> { $0.walletId == walletId }
        )
+       _syncStates = Query(
+           filter: `#Predicate`<PersistentSyncState> { $0.network == networkName }
+       )
    }

    /// Platform balance in credits: prefer BLAST address sync, fall
-   /// back to summing identity credits when no addresses have been
-   /// synced yet.
+   /// back to summing identity credits only when no BLAST sync
+   /// has occurred yet.
    private var platformBalance: UInt64 {
        let blastBalance = addressBalances.reduce(UInt64(0)) { $0 + $1.balance }
-       if blastBalance > 0 { return blastBalance }
+       let hasSynced = syncStates.first.map { $0.syncHeight > 0 || $0.syncTimestamp > 0 }
+           ?? false
+       if blastBalance > 0 || hasSynced {
+           return blastBalance
+       }
        return identitiesForWallet.reduce(UInt64(0)) {
            $0 + UInt64(bitPattern: $1.balance)
        }
    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CoreContentView.swift`
around lines 669 - 678, platformBalance incorrectly falls back to identity
credits whenever blastBalance == 0, but must only do so if the wallet has never
synced; locate the platformBalance computed property and modify its logic to
query PersistentSyncState (e.g. access syncStates similar to BalanceCardView) to
detect whether the wallet has been synced at least once — if blastBalance > 0
return blastBalance, else if the wallet has a syncState indicating it has
previously synced return 0, otherwise fall back to summing identitiesForWallet
balances; ensure you reference the same sync state key/lookup used by
BalanceCardView so behavior is consistent.

Comment on lines +685 to +694
/// Combined wallet balance expressed in DASH. Core uses 1e8
/// duffs/DASH; Platform uses 1e11 credits/DASH.
private var combinedDashAmount: Double {
Double(totalCoreBalance) / 100_000_000.0
+ Double(platformBalance) / 100_000_000_000.0
}

private var hasAnyBalance: Bool {
totalCoreBalance > 0 || platformBalance > 0
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Header may render “0 DASH” for tiny platform balances despite hasAnyBalance == true.

formatDash caps at maximumFractionDigits = 8, but Platform credits resolve to 1e‑11 DASH. Any platform-only balance under 1000 credits (≈ 1e‑8 DASH) rounds to 0 and the header shows “0 DASH” while hasAnyBalance is true — which is inconsistent with the “Empty”/non-empty intent and with row 5 (formatCredits uses %.4f and would also display 0.0000 DASH). Consider raising precision when only platform credits are present, or showing the credits unit directly:

♻️ One option
-    private func formatDash(_ dash: Double) -> String {
+    private func formatDash(_ dash: Double, maxFractionDigits: Int = 8) -> String {
         let formatter = NumberFormatter()
         formatter.numberStyle = .decimal
         formatter.minimumFractionDigits = 0
-        formatter.maximumFractionDigits = 8
+        formatter.maximumFractionDigits = maxFractionDigits
         if let formatted = formatter.string(from: NSNumber(value: dash)) {
             return "\(formatted) DASH"
         }
-        return String(format: "%.8f DASH", dash)
+        return String(format: "%.\(maxFractionDigits)f DASH", dash)
     }

Also applies to: 787-790

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

In
`@packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CoreContentView.swift`
around lines 685 - 694, The header can show "0 DASH" for tiny platform-only
balances because combinedDashAmount is formatted with formatDash (max 8 fraction
digits) while platform credits resolve to 1e‑11 DASH; update the header
formatting to handle platform-only balances by detecting the platform-only case
(totalCoreBalance == 0 && platformBalance > 0) and either (A) format using
higher precision (raise maximumFractionDigits to cover 1e‑11 when computing
combinedDashAmount for display) or (B) display the platform amount using
credits/formatCredits instead of DASH; locate and change the logic around
combinedDashAmount and hasAnyBalance to branch the header formatting accordingly
so the header is consistent with row formatting.

@github-actions

Copy link
Copy Markdown
Contributor

✅ DashSDKFFI.xcframework built for this PR.

SwiftPM (host the zip at a stable URL, then use):

.binaryTarget(
  name: "DashSDKFFI",
  url: "https://your.cdn.example/DashSDKFFI.xcframework.zip",
  checksum: "d41895f9d84c54f252b985756226d23920420d563cb8a71269d14130cac2963d"
)

Xcode manual integration:

  • Download 'DashSDKFFI.xcframework' artifact from the run link above.
  • Drag it into your app target (Frameworks, Libraries & Embedded Content) and set Embed & Sign.
  • If using the Swift wrapper package, point its binaryTarget to the xcframework location or add the package and place the xcframework at the expected path.

@QuantumExplorer
QuantumExplorer merged commit 2b3486a into v3.1-dev Apr 25, 2026
37 checks passed
@QuantumExplorer
QuantumExplorer deleted the claude/awesome-gauss-e7fced branch April 25, 2026 12:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants