fix: SPL token balance display for xstocks and non-6-decimal tokens (#3052)

David Adegoke committed Mar 13, 2026 at 02:02 UTC 4d26b4ee6b42d2937faad4d8b6dec67410913148
3 files changed +17 -11
cw_solana/lib/solana_balance.dart
+5 -2
@@ -7,12 +7,15 @@ class SolanaBalance extends Balance {
7 BigInt.from(int.tryParse(balance.toStringAsFixed(isToken ? 6 : 9).replaceFirst(".", "")) ?? 0),
8 BigInt.from(int.tryParse(balance.toStringAsFixed(isToken ? 6 : 9).replaceFirst(".", "")) ?? 0));
9
10 + // Using raw amount from RPC to avoid decimals mismatch for SPL tokens.
11 + SolanaBalance.forToken(BigInt rawAmount, double uiAmount)
12 + : balance = uiAmount,
13 + super(rawAmount, rawAmount);
14 +
15 final double balance;
16
12 - @override
17 String get formattedAdditionalBalance => _balanceFormatted();
18
15 - @override
19 String get formattedAvailableBalance => _balanceFormatted();
20
21 String _balanceFormatted() {
cw_solana/lib/solana_client.dart
+9 -7
@@ -111,22 +111,24 @@ class SolanaWalletClient {
111 return null;
112 }
113
114 - // Sum the balances of all accounts with the specified mint address
115 - double totalBalance = 0.0;
114 + // Sum raw amounts and ui amounts across all token accounts
115 + BigInt totalRaw = BigInt.zero;
116 + double totalUi = 0.0;
117
118 for (var tokenAccount in tokenAccounts) {
119 final tokenAmountResult = await _provider!.request(
120 SolanaRPCGetTokenAccountBalance(account: tokenAccount.pubkey),
121 );
122
122 - final balance = tokenAmountResult.uiAmountString;
123 + final raw = BigInt.tryParse(tokenAmountResult.amount) ?? BigInt.zero;
124 + totalRaw += raw;
125
124 - final balanceAsDouble = double.tryParse(balance ?? '0.0') ?? 0.0;
125 -
126 - totalBalance += balanceAsDouble;
126 + final ui = tokenAmountResult.uiAmount ??
127 + (double.tryParse(tokenAmountResult.uiAmountString ?? '0') ?? 0.0);
128 + totalUi += ui;
129 }
130
129 - return SolanaBalance(totalBalance, true);
131 + return SolanaBalance.forToken(totalRaw, totalUi);
132 } catch (_) {
133 if (throwOnError) {
134 rethrow;
cw_solana/lib/solana_wallet.dart
+3 -2
@@ -588,7 +588,8 @@ abstract class SolanaWalletBase
588 for (final entry in results) {
589 final token = entry.key;
590 final fetchedBalance = entry.value;
591 - final currentBalance = balance[token] ?? SolanaBalance(0.0, true);
591 + final currentBalance = balance[token] ??
592 + SolanaBalance.forToken(BigInt.zero, 0.0);
593 balance[token] = fetchedBalance ?? currentBalance;
594 }
595 }
@@ -636,7 +637,7 @@ abstract class SolanaWalletBase
637 if (token.enabled) {
638 final tokenBalance = await _client.getSplTokenBalance(token.mintAddress, solanaAddress) ??
639 balance[token] ??
639 - SolanaBalance(0.0, true);
640 + SolanaBalance.forToken(BigInt.zero, 0.0);
641
642 balance[token] = tokenBalance;
643 } else {