Skip to content

Commit 0bb19e5

Browse files
committed
fix(market-metrics): exception when opening coin right after login
1 parent 60c005d commit 0bb19e5

File tree

3 files changed

+80
-54
lines changed

3 files changed

+80
-54
lines changed

lib/bloc/cex_market_data/profit_loss/profit_loss_bloc.dart

+26-13
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@ class ProfitLossBloc extends Bloc<ProfitLossEvent, ProfitLossState> {
4343
ProfitLossPortfolioChartLoadRequested event,
4444
Emitter<ProfitLossState> emit,
4545
) async {
46-
List<Coin> coins = await _removeUnsupportedCons(event);
47-
// Charts for individual coins (coin details) are parsed here as well,
48-
// and should be hidden if not supported.
46+
try {
47+
List<Coin> coins = await _removeUnsupportedCons(event);
48+
// Charts for individual coins (coin details) are parsed here as well,
49+
// and should be hidden if not supported.
4950
if (coins.isEmpty && event.coins.length <= 1) {
5051
return emit(
5152
PortfolioProfitLossChartUnsupported(
@@ -58,13 +59,14 @@ class ProfitLossBloc extends Bloc<ProfitLossEvent, ProfitLossState> {
5859
.then(emit.call)
5960
.catchError((e, _) {
6061
logger.log('Failed to load portfolio profit/loss: $e', isError: true);
61-
if (state is! PortfolioProfitLossChartLoadSuccess) {
62-
emit(
63-
ProfitLossLoadFailure(
64-
error: TextError(error: 'Failed to load portfolio profit/loss: $e'),
65-
selectedPeriod: event.selectedPeriod,
66-
),
67-
);
62+
if (state is! PortfolioProfitLossChartLoadSuccess) {
63+
emit(
64+
ProfitLossLoadFailure(
65+
error:
66+
TextError(error: 'Failed to load portfolio profit/loss: $e'),
67+
selectedPeriod: event.selectedPeriod,
68+
),
69+
);
6870
}
6971
});
7072

@@ -76,9 +78,20 @@ class ProfitLossBloc extends Bloc<ProfitLossEvent, ProfitLossState> {
7678
.catchError((e, _) {
7779
// Ignore un-cached errors, as a transaction loading exception should not
7880
// make the graph disappear with a load failure emit, as the cached data
79-
// is already displayed. The periodic updates will still try to fetch the
80-
// data and update the graph.
81-
});
81+
// is already displayed. The periodic updates will still try to fetch the
82+
// data and update the graph.
83+
});
84+
}
85+
} catch (e) {
86+
logger
87+
.log('Failed to load portfolio profit/loss: $e', isError: true)
88+
.ignore();
89+
emit(
90+
ProfitLossLoadFailure(
91+
error: TextError(error: 'Failed to load portfolio profit/loss: $e'),
92+
selectedPeriod: event.selectedPeriod,
93+
),
94+
);
8295
}
8396

8497
await emit.forEach(

lib/bloc/coins_bloc/coins_bloc.dart

+33-29
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class CoinsBloc extends Bloc<CoinsEvent, CoinsState> {
2626
this._mm2Api,
2727
) : super(CoinsState.initial()) {
2828
on<CoinsStarted>(_onCoinsStarted, transformer: droppable());
29-
// TODO: move auth listener to ui layer: bloclistener fires auth events
29+
// TODO: move auth listener to ui layer: bloclistener should fire auth events
3030
on<CoinsBalanceMonitoringStarted>(_onCoinsBalanceMonitoringStarted);
3131
on<CoinsBalanceMonitoringStopped>(_onCoinsBalanceMonitoringStopped);
3232
on<CoinsBalancesRefreshed>(_onCoinsRefreshed, transformer: droppable());
@@ -81,7 +81,7 @@ class CoinsBloc extends Bloc<CoinsEvent, CoinsState> {
8181
if (coin == null) return;
8282

8383
// Get pubkeys from the SDK through the repo
84-
final asset = _kdfSdk.assets.assetsFromTicker(event.coinId).single;
84+
final asset = _kdfSdk.assets.available[coin.id]!;
8585
final pubkeys = await _kdfSdk.pubkeys.getPubkeys(asset);
8686

8787
// Update state with new pubkeys
@@ -323,13 +323,22 @@ class CoinsBloc extends Bloc<CoinsEvent, CoinsState> {
323323
CoinsSessionStarted event,
324324
Emitter<CoinsState> emit,
325325
) async {
326-
_coinsRepo.flushCache();
327-
_currentUserCache = event.signedInUser;
328-
await _activateLoginWalletCoins(emit);
329-
emit(state.copyWith(loginActivationFinished: true));
326+
try {
327+
_coinsRepo.flushCache();
328+
_currentUserCache = event.signedInUser;
329+
await _activateLoginWalletCoins(emit);
330+
emit(state.copyWith(loginActivationFinished: true));
330331

331-
add(CoinsBalancesRefreshed());
332-
add(CoinsBalanceMonitoringStarted());
332+
add(CoinsBalancesRefreshed());
333+
add(CoinsBalanceMonitoringStarted());
334+
} catch (e, s) {
335+
log(
336+
'Error on login: $e',
337+
isError: true,
338+
trace: s,
339+
path: 'coins_bloc => _onLogin',
340+
).ignore();
341+
}
333342
}
334343

335344
Future<void> _onLogout(
@@ -376,21 +385,20 @@ class CoinsBloc extends Bloc<CoinsEvent, CoinsState> {
376385
Iterable<String> coins,
377386
Emitter<CoinsState> emit,
378387
) async {
379-
// Start off by emitting the newly activated coins so that they all appear
380-
// in the list at once, rather than one at a time as they are activated
381-
_prePopulateListWithActivatingCoins(coins, emit);
382-
383388
try {
389+
// Start off by emitting the newly activated coins so that they all appear
390+
// in the list at once, rather than one at a time as they are activated
391+
emit(_prePopulateListWithActivatingCoins(coins));
392+
384393
await _kdfSdk.addActivatedCoins(coins);
385394
} catch (e, s) {
386395
log(
387-
'Failed to activate coins in SDK: $e',
396+
'Failed to add activated coins to SDK metadata field: $e',
388397
isError: true,
389398
path: 'coins_bloc => _activateCoins',
390399
trace: s,
391400
).ignore();
392-
// Update state to reflect failure
393-
return [];
401+
rethrow;
394402
}
395403

396404
final enabledAssets = await _kdfSdk.assets.getEnabledCoins();
@@ -414,10 +422,7 @@ class CoinsBloc extends Bloc<CoinsEvent, CoinsState> {
414422
return results;
415423
}
416424

417-
void _prePopulateListWithActivatingCoins(
418-
Iterable<String> coins,
419-
Emitter<CoinsState> emit,
420-
) {
425+
CoinsState _prePopulateListWithActivatingCoins(Iterable<String> coins) {
421426
final activatingCoins = Map<String, Coin>.fromIterable(
422427
coins
423428
.map(
@@ -433,11 +438,9 @@ class CoinsBloc extends Bloc<CoinsEvent, CoinsState> {
433438
.cast<Coin>(),
434439
key: (element) => (element as Coin).abbr,
435440
);
436-
emit(
437-
state.copyWith(
438-
walletCoins: {...state.walletCoins, ...activatingCoins},
439-
coins: {...state.coins, ...activatingCoins},
440-
),
441+
return state.copyWith(
442+
walletCoins: {...state.walletCoins, ...activatingCoins},
443+
coins: {...state.coins, ...activatingCoins},
441444
);
442445
}
443446

@@ -466,10 +469,10 @@ class CoinsBloc extends Bloc<CoinsEvent, CoinsState> {
466469
}
467470
} catch (e, s) {
468471
log(
469-
'Error activating coin ${coin!.id.toString()}',
472+
'Error activating coin ${coin!.id}',
470473
isError: true,
471474
trace: s,
472-
);
475+
).ignore();
473476
}
474477

475478
return coin;
@@ -478,7 +481,7 @@ class CoinsBloc extends Bloc<CoinsEvent, CoinsState> {
478481
Future<Coin> _activateTrezorCoin(Coin coin, String coinId) async {
479482
final asset = _kdfSdk.assets.available[coin.id];
480483
if (asset == null) {
481-
log('Failed to find asset for coin: ${coin.id}', isError: true);
484+
log('Failed to find asset for coin: ${coin.id}', isError: true).ignore();
482485
return coin.copyWith(state: CoinState.suspended);
483486
}
484487
final accounts = await _trezorBloc.activateCoin(asset);
@@ -525,8 +528,9 @@ class CoinsBloc extends Bloc<CoinsEvent, CoinsState> {
525528
.map((coin) => coin.abbr)
526529
.toList();
527530

528-
coinsToBeActivated.addAll(suspended);
529-
coinsToBeActivated.addAll(_getUnactivatedWalletCoins());
531+
coinsToBeActivated
532+
..addAll(suspended)
533+
..addAll(_getUnactivatedWalletCoins());
530534

531535
if (coinsToBeActivated.isEmpty) return;
532536
yield await _activateCoins(coinsToBeActivated, emit);

lib/bloc/coins_bloc/coins_repo.dart

+21-12
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:http/http.dart' as http;
77
import 'package:komodo_defi_rpc_methods/komodo_defi_rpc_methods.dart'
88
as kdf_rpc;
99
import 'package:komodo_defi_sdk/komodo_defi_sdk.dart';
10+
import 'package:komodo_defi_types/komodo_defi_type_utils.dart';
1011
import 'package:komodo_defi_types/komodo_defi_types.dart';
1112
import 'package:komodo_ui_kit/komodo_ui_kit.dart';
1213
import 'package:web_dex/bloc/coins_bloc/asset_coin_extension.dart';
@@ -94,9 +95,7 @@ class CoinsRepo {
9495
return _assetToCoinWithoutAddress(asset);
9596
}
9697

97-
@Deprecated('Use KomodoDefiSdk assets or getCoinFromId instead. '
98-
'This uses the deprecated assetsFromTicker method that uses a separate '
99-
'cache that does not update with custom token activation.')
98+
@Deprecated('Use KomodoDefiSdk assets or getCoinFromId instead.')
10099
Coin? getCoin(String coinId) {
101100
if (coinId.isEmpty) return null;
102101

@@ -128,16 +127,23 @@ class CoinsRepo {
128127
}
129128

130129
Future<Coin?> getEnabledCoin(String coinId) async {
131-
final enabledAssets = _kdfSdk.assets.assetsFromTicker(coinId);
132-
if (enabledAssets.length != 1) {
133-
return null;
134-
}
135130
final currentUser = await _kdfSdk.auth.currentUser;
136131
if (currentUser == null) {
137132
return null;
138133
}
139134

140-
final coin = _assetToCoinWithoutAddress(enabledAssets.single);
135+
final enabledAssets = await _kdfSdk.assets.getEnabledCoins();
136+
final enabledAsset = enabledAssets.firstWhereOrNull(
137+
(asset) => asset == coinId,
138+
);
139+
if (enabledAsset == null) {
140+
return null;
141+
}
142+
143+
final coin = getCoin(enabledAsset);
144+
if (coin == null) {
145+
return null;
146+
}
141147
final coinAddress = await getFirstPubkey(coin.abbr);
142148
return coin.copyWith(
143149
address: coinAddress,
@@ -229,7 +235,8 @@ class CoinsRepo {
229235
final isSignedIn = await _kdfSdk.auth.isSignedIn();
230236
if (!isSignedIn) {
231237
final coinIdList = assets.map((e) => e.id.id).join(', ');
232-
log('No wallet signed in. Skipping activation of [$coinIdList}]');
238+
log('No wallet signed in. Skipping activation of [$coinIdList}]')
239+
.ignore();
233240
return;
234241
}
235242

@@ -247,8 +254,9 @@ class CoinsRepo {
247254
await _broadcastAsset(coin.copyWith(state: CoinState.active));
248255
} catch (e, s) {
249256
log(
250-
'Error activating coin: ${asset.id.id} \n$e',
257+
'Error activating asset: ${asset.id.id} \n$e',
251258
isError: true,
259+
path: 'coins_repo => activateAssetsSync',
252260
trace: s,
253261
).ignore();
254262
await _broadcastAsset(
@@ -271,7 +279,8 @@ class CoinsRepo {
271279
final isSignedIn = await _kdfSdk.auth.isSignedIn();
272280
if (!isSignedIn) {
273281
final coinIdList = coins.map((e) => e.abbr).join(', ');
274-
log('No wallet signed in. Skipping activation of [$coinIdList}]');
282+
log('No wallet signed in. Skipping activation of [$coinIdList}]')
283+
.ignore();
275284
return;
276285
}
277286

@@ -478,7 +487,7 @@ class CoinsRepo {
478487
// Coins with the same coingeckoId supposedly have same usd price
479488
// (e.g. KMD == KMD-BEP20)
480489
final Iterable<Coin> samePriceCoins =
481-
(getKnownCoins()).where((coin) => coin.coingeckoId == coingeckoId);
490+
getKnownCoins().where((coin) => coin.coingeckoId == coingeckoId);
482491

483492
for (final Coin coin in samePriceCoins) {
484493
prices[coin.abbr] = CexPrice(

0 commit comments

Comments
 (0)