What changed, and why it matters
This commit fixes a bug in how the Stack Wallet app fetches cryptocurrency prices from CoinGecko. Previously, the app tried to match coins by their display name (e.g., 'Bitcoin'), which caused 'Bitcoin Frost' to be missed because its name differs. The change now matches coins by their unique CoinGecko ID instead, so both regular Bitcoin and Bitcoin Frost get correct price data. There is no security vulnerability here—it's a functional bug fix for price display accuracy.
No security action required. Treat as a routine functional fix. If reviewing, verify that _coinToIdMap contains correct CoinGecko IDs for all supported mainnet coins and that duplicate runtimeType entries are handled appropriately.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch changes PriceAPI’s CoinGecko response parsing in lib/services/price.dart. It replaces a name-based lookup (AppConfig.getCryptoCurrencyByPrettyName) with a runtimeType/ID-based filter against _coinToIdMap and CryptoCurrencyNetwork.main. This resolves a collision/omission where BitcoinFrost (a separate CryptoCurrency subtype) was not being matched and priced. A test expectation for BitcoinFrost pricing was added in test/price_test.dart.
Changed components
lib/services/price.darttest/price_test.dartInspect captured patch +16 / −10
diff --git a/lib/services/price.dart b/lib/services/price.dart
index 7af1ec2..23f1cf2 100644
--- a/lib/services/price.dart
+++ b/lib/services/price.dart
@@ -159,16 +159,14 @@ class PriceAPI {
for (final map in coinGeckoData) {
final String coinName = map["name"] as String;
- late CryptoCurrency coin;
- try {
- coin = AppConfig.getCryptoCurrencyByPrettyName(
- coinName == "Factor" ? "Fact0rn" : coinName,
- );
- } catch (e, s) {
+ final coins = AppConfig.coins.where(
+ (coin) =>
+ coin.network == CryptoCurrencyNetwork.main &&
+ _coinToIdMap[coin.runtimeType] == map["id"],
+ );
+ if (coins.isEmpty) {
Logging.instance.e(
"Failed to find matching app coin for $coinName. Moving on",
- error: e,
- stackTrace: s,
);
continue;
}
@@ -179,9 +177,13 @@ class PriceAPI {
? double.parse(map["price_change_percentage_24h"].toString())
: 0.0;
- result[coin] = (value: price, change24h: change24h);
+ for (final coin in coins) {
+ result[coin] = (value: price, change24h: change24h);
+ }
} catch (_) {
- result.remove(coin);
+ for (final coin in coins) {
+ result.remove(coin);
+ }
}
}
diff --git a/test/price_test.dart b/test/price_test.dart
index 468295b..d28988f 100644
--- a/test/price_test.dart
+++ b/test/price_test.dart
@@ -31,6 +31,10 @@ void main() {
prices,
contains("Instance of 'Bitcoin': (change24h: 0.0, value: 1)"),
);
+ expect(
+ prices,
+ contains("Instance of 'BitcoinFrost': (change24h: 0.0, value: 1)"),
+ );
expect(
prices,
contains(
Why this scored 17/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.