Skip to content

feat(walletkit): multi-chain balances with zero-balance natives and redesigned rows#381

Open
ignaciosantise wants to merge 2 commits into
developfrom
add-zero-balance-native-tokens
Open

feat(walletkit): multi-chain balances with zero-balance natives and redesigned rows#381
ignaciosantise wants to merge 2 commits into
developfrom
add-zero-balance-native-tokens

Conversation

@ignaciosantise
Copy link
Copy Markdown
Collaborator

@ignaciosantise ignaciosantise commented Jun 1, 2026

Description

Reworks the sample wallet Balances page. It now fetches balances across all supported namespaces (eip155, solana, sui, ton, tron) — returning every EVM chain in a single call when chainId is omitted — filters out spam/airdrop tokens, always shows mainnet native tokens even at a 0 balance (so their address is visible), and adds per-token filter chips. Each row is redesigned to the TokenBalanceCard spec: token icon with chain badge on the left, compact amount (no inline USD value), a 6...6 truncated per-chain address, and a tap-to-copy card with a new CopySimple.svg copy icon and a confirmation toast. The single "Wallet address" header was removed since multiple chains/addresses are now supported.

Resolves # (issue)

How Has This Been Tested?

flutter analyze passes clean on the changed files. Verified manually by opening the Balances tab in the WalletKit example app: rows render icon-left with chain badges, amounts/addresses format correctly, and tapping a card copies its address and shows the toast.

Due Dilligence

  • Breaking change
  • Requires a documentation update

Copilot AI review requested due to automatic review settings June 1, 2026 19:20
@claude
Copy link
Copy Markdown

claude Bot commented Jun 1, 2026

Claude finished @ignaciosantise's task in 2m 5s —— View job


Code Review

  • Gather context
  • Read changed files
  • Analyze code
  • Post findings
Found 4 issue(s)

Issue 1: Type cast crash when API returns integer value

ID: blockchain-api-double-cast-f2c1
File: packages/reown_walletkit/example/lib/utils/blockchain_api_utils.dart:46
Severity: HIGH
Category: code_quality

Context:

  • Pattern: b['value'] as double? and a['value'] as double? in the sort comparator
  • Risk: In Dart, int cannot be cast to double — if the JSON response returns "value": 0 (integer literal), this throws TypeError: type 'int' is not a subtype of type 'double?' at runtime
  • Impact: The entire balance fetch crashes for any account where a token has an integer value field; since 0 is a common API value, this will fire on any account with zero-value tokens
  • Trigger: Any API response where value is a JSON integer rather than a float (very common for zero balances)

Recommendation: Use num? then .toDouble(), matching the pattern already used correctly in _processBalances:

final bValue = (b['value'] as num?)?.toDouble() ?? 0.0;
final aValue = (a['value'] as num?)?.toDouble() ?? 0.0;

Fix this →


Issue 2: Unsafe null map access on balance['quantity'] in build

ID: balances-page-quantity-null-access-a3d7
File: packages/reown_walletkit/example/lib/pages/balances_page.dart:383
Severity: MEDIUM
Category: code_quality

Context:

  • Pattern: double.tryParse(balance['quantity']['numeric']) — no null-safe access on balance['quantity']
  • Risk: If the API ever returns a balance entry without a quantity key (or with null), the inner ['numeric'] access throws Null check operator used on a null value. _processBalances does inject placeholder entries with a quantity, but raw API entries are not guaranteed to have it.
  • Impact: Throws Null exception during build, causing the widget tree to show a red error screen
  • Trigger: Any token returned from the API where the quantity field is absent or null

Recommendation: Use null-safe access matching the style already used in _processBalances line 275:

final quantity = double.tryParse(
  balance['quantity']?['numeric']?.toString() ?? '',
) ?? 0.0;

Fix this →


Issue 3: Empty state still gates on EVM-only check

ID: balances-page-evm-only-empty-state-b1e4
File: packages/reown_walletkit/example/lib/pages/balances_page.dart:317
Severity: LOW
Category: code_quality

Context:

  • Pattern: final chainKeys = _keysService.getKeysForChain('eip155'); ... chainKeys.isEmpty ? Center(child: Text('No EVM accounts found')) in build
  • Risk: A wallet with only Solana/Tron/TON keys (no EVM) will show "No EVM accounts found" and render nothing, even though multi-chain balances are now supported and those accounts have been fetched
  • Impact: Misleading UX; non-EVM-only wallets see a dead page

Recommendation:

// Replace lines 317-327 in build():
final hasAnyAccount = _addresses.isNotEmpty;
// ...
body: !hasAnyAccount
    ? Center(child: Text('No accounts found', ...))
    : RefreshIndicator(...)

Issue 4: _addresses getter calls _addressFor twice per namespace

ID: balances-page-double-keylookup-c9f2
File: packages/reown_walletkit/example/lib/pages/balances_page.dart:54
Severity: LOW
Category: performance

Context:

  • Pattern: if (_addressFor(ns) != null) ns: _addressFor(ns)! — each namespace does two getKeysForChain calls
  • Risk: Minor inefficiency; if getKeysForChain ever has side effects or cost (e.g., DB read), this doubles the work. Also fragile: a TOCTOU if the keystore changes between the two calls.

Recommendation:

Map<String, String> get _addresses => {
  for (final ns in _supportedNamespaces)
    if (_addressFor(ns) case final addr?) ns: addr,
};

Or store to a local variable: final addr = _addressFor(ns); if (addr != null) ns: addr.

…edesigned rows

Sample wallet balances page now fetches balances across all supported
namespaces (eip155, solana, sui, ton, tron), returning every EVM chain in a
single call when chainId is omitted. Filters out spam/airdrop tokens, always
shows mainnet native tokens (even at 0 balance) so their address is visible,
and adds per-token filter chips.

Redesigns each balance row to match the TokenBalanceCard spec: token icon with
chain badge on the left, compact amount (no USD value), 6...6 truncated
per-chain address, and a tap-to-copy card with a copy icon and toast. Removes
the single "Wallet address" header since multiple chains/addresses are now
supported.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ignaciosantise ignaciosantise force-pushed the add-zero-balance-native-tokens branch from 9eda5ca to 094928b Compare June 1, 2026 19:21
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR reworks the WalletKit example app’s Balances screen to support multi-namespace balance fetching and a redesigned, copy-to-clipboard row UI aligned with the TokenBalanceCard spec.

Changes:

  • Updated balance fetching to support optional chainId (enabling a single-call “all EVM chains” query when omitted) and to aggregate results across supported namespaces.
  • Added balance post-processing to filter spam/airdrop tokens and ensure mainnet native tokens are shown even at 0 balance.
  • Redesigned balance rows (chain badge, compact amount formatting, truncated per-chain address, tap-to-copy with new CopySimple.svg icon and toast).

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 2 comments.

File Description
packages/reown_walletkit/example/lib/utils/blockchain_api_utils.dart Makes chainId optional and omits the query param when absent to support multi-chain EVM balance fetches.
packages/reown_walletkit/example/lib/pages/balances_page.dart Implements multi-namespace fetching, spam filtering, native-token inclusion at 0 balance, and redesigned tappable balance rows with copy + toast.
packages/reown_walletkit/example/ios/Runner.xcodeproj/project.pbxproj Changes Xcode project objectVersion (appears incidental).
packages/reown_walletkit/example/assets/CopySimple.svg Adds a new SVG asset used for the copy icon in balance rows.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/reown_walletkit/example/lib/pages/balances_page.dart
Comment thread packages/reown_walletkit/example/lib/pages/balances_page.dart Outdated
- Use num.toDouble() in the balance sort to avoid a TypeError when the API
  returns an integer value (e.g. 0 for zero-value tokens).
- Null-safe quantity parsing in the row builder to avoid crashes when the
  API omits quantity or returns a non-string numeric.
- Generalize the empty state from EVM-only ("No EVM accounts found") to any
  supported namespace ("No accounts found"), matching multi-chain support.
- Resolve each supported namespace address once in the _addresses getter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ignaciosantise
Copy link
Copy Markdown
Collaborator Author

All 4 findings addressed in 1af443f:

Issue Action
1 — Type cast crash on integer value (blockchain_api_utils.dart) Fixed. Sort comparator now uses (… as num?)?.toDouble() ?? 0.0, so an integer 0 from the API no longer throws a TypeError. Matches the safe pattern in _processBalances.
2 — Unsafe balance['quantity']['numeric'] access Fixed. Now double.tryParse(balance['quantity']?['numeric']?.toString() ?? '') ?? 0.0 — null-safe and string-coerced.
3 — Empty state gates on EVM-only check Fixed. Generalized to _addresses.isNotEmpty with the message "No accounts found", so non-EVM wallets are no longer shown a dead "No EVM accounts found" page.
4 — _addresses calls _addressFor twice per namespace Fixed. Resolves each namespace once via if (_addressFor(ns) case final address?) ns: address, removing the double lookup and TOCTOU window.

flutter analyze is clean on both files.

@ignaciosantise ignaciosantise requested a review from jakubuid June 1, 2026 19:37
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