-
Notifications
You must be signed in to change notification settings - Fork 240
chore(release): v0.9.1 release - Trezor login hot-fix
#2743
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughThis update addresses a critical bug with Trezor hardware wallet login by updating password handling and coin activation logic. Password utility functions are refactored to use centralized security utilities. Documentation is updated to reflect the new release, and the project version is incremented to 0.9.1. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant App
participant TrezorInitBloc
participant SecurityUtils
participant KdfSdk
User->>App: Initiate Trezor login
App->>TrezorInitBloc: _loginToTrezorWallet({walletName, password?})
alt password not provided
TrezorInitBloc->>SecurityUtils: generatePasswordSecure(16)
SecurityUtils-->>TrezorInitBloc: Generated password
end
TrezorInitBloc->>KdfSdk: addActivatedCoins(enabledByDefaultTrezorCoins)
TrezorInitBloc->>App: Complete login process
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
|
Visit the preview URL for this PR (updated for commit c0cd153): https://walletrc--pull-2743-merge-ncur58lv.web.app (expires Fri, 20 Jun 2025 11:49:07 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 Sign: f66a4ff03faa546f12f0ae5a841bd9eff2714dcc |
* fix pwd validation fail on hidden wallet * fix default pass & ensure auto active coins register * use secure random password * refactor: migrate password generation to SDK --------- Co-authored-by: CharlVS <[email protected]>
* fix(trezor): persist generated password and login in HD mode * chore(deps): update SDK to f63bebb * refactor(trezor): add error handling to password storage & retrieval
DeckerSU
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rebase the branch on the top of current dev. In current state it doesn't include build fixes.
DeckerSU
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
It looks like everything works as expected in most cases. I ran tests using both the web (PC) and desktop (linux) versions. For the web tests, I used a Trezor Safe 3 device with Google Chrome Version 137.0.7151.68 (Official Build) (64-bit).
Everything worked fine across various scenarios, except one: when the Trezor was set up with SLIP39 (20 words) and no PIN, I encountered the following error:
"Internal: bad magic in v1 read: 0x19f0 instead of 0x3f2323"
I tried disconnecting and reconnecting the Trezor, but the error persisted. Then, I re-initialized the Trezor with BIP39 (12 words) and no PIN—it worked fine. I also restored it again with SLIP39 (20 words) and no PIN, and that time it also worked as expected.
So, I approve the changes, but I strongly recommend running additional tests just to be sure that users won’t encounter the same issue under specific conditions.
One more thing: I noticed that if you choose Trezor, BTC using Native SegWit (bc1) addresses can't be added as a coin to the list. This is the default address format for Trezor, so it means users who hold their BTC in Native SegWit addresses may not be able to access their funds using Komodo Wallet.
smk762
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Confirmed I was able to access Trezor on both linux desktop and brave browser.
Non-blocking issue added at #2766
Confirm no segwit variants found (BTC, LTC, DGB) in activation list. Issue for this created at #2767
The bad magic error @DeckerSU reported has been converted to an issue at GLEECBTC/komodo-defi-framework#2488
Though some work remains to be done with Trezor, the reported login issue is resolved. Approved.
…d UX (#2771) - Restructure wallet page with tab-based navigation (Assets, Portfolio Growth, Profit & Loss) - Replace single scroll view with NestedScrollView for better tab content management - Move portfolio charts from overlay to dedicated tabs for clearer organization - Enhance mobile coin list items with dedicated balance/24h change layout - Add statistics carousel for mobile wallet overview replacing wrap layout - Integrate 24h price tracking across coin items and portfolio calculations - Update wallet overview with real-time balance and copy functionality - Improve responsive design with platform-specific padding and layouts - Refactor CoinListView into separate widget for cleaner code structure - Change "Currency" header to "Portfolio" and update action button text BREAKING CHANGE: PortfolioGrowthChartLoadSuccess state now requires totalBalance, totalChange24h, and percentageChange24h parameters
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🔭 Outside diff range comments (1)
lib/views/wallet/wallet_page/common/asset_list_item.dart (1)
31-43: 🛠️ Refactor suggestion
⚠️ Potential issue
priceChangePercentage24his never usedThe new value is accepted by
AssetListItembut not forwarded toAssetListItemMobile/AssetListItemDesktop.
Either pass it through or render it directly here; otherwise this field is dead code and the UI won’t show the 24 h change.- ? AssetListItemMobile( - assetId: assetId, - backgroundColor: backgroundColor, - onTap: onTap, - ) + ? AssetListItemMobile( + assetId: assetId, + backgroundColor: backgroundColor, + onTap: onTap, + priceChangePercentage24h: priceChangePercentage24h, + ) ... - : AssetListItemDesktop( - assetId: assetId, - backgroundColor: backgroundColor, - onTap: onTap, - ); + : AssetListItemDesktop( + assetId: assetId, + backgroundColor: backgroundColor, + onTap: onTap, + priceChangePercentage24h: priceChangePercentage24h, + );
♻️ Duplicate comments (1)
lib/bloc/cex_market_data/portfolio_growth/portfolio_growth_bloc.dart (1)
224-233: Same inconsistency as above inside the periodic update – totals are derived from the originalcoins, not the filteredsupportedCoinsactually displayed.
🧹 Nitpick comments (11)
lib/bloc/cex_market_data/price_chart/models/time_period.dart (1)
26-28: Prefer a getter forformattedto keep API symmetry and avoid redundant parenthesesIn the analogous
PriceChartPeriodenum,formattedis exposed as a getter. Using a method here introduces an unnecessary discrepancy and forces callers to add()when switching between the two types.- // TODO: Localize - String formatted() => name; + // TODO: Localize + String get formatted => name;No functional change, but it tightens consistency across the model layer and marginally improves call-site ergonomics.
lib/views/wallet/wallet_page/wallet_main/active_coins_list.dart (1)
59-69: Avoid firing Bloc events from the list builder
itemBuilderruns every build; emittingCoinsPubkeysRequestedhere can spam the bloc during fast scrolling or rebuilds.
Prefetch pubkeys before rendering, or cache the request status to ensure each coin triggers at most one fetch.lib/views/wallet/wallet_page/wallet_main/wallet_manage_section.dart (1)
96-106: Hard-coded text breaks i18n.The mobile header
'Portfolio'and button label'Add assets'bypass the existingeasy_localizationsetup.
Replace them with the correspondingLocaleKeysentries as done for the desktop flow to keep translations in sync.lib/bloc/cex_market_data/portfolio_growth/portfolio_growth_repository.dart (1)
545-553: Nit: method name leakage.
updatePrices()is a thin alias forfetchCurrentPrices()and adds no semantic value.
Consider removing it or turning it into a polling scheduler so the public API does more than forward the call.lib/views/wallet/wallet_page/common/expandable_coin_list_item.dart (2)
120-191: Multiple visible strings are not localised.
'Balance','24h %'and several others are hard-coded. This regresses localisation coverage introduced elsewhere.
Expose them viaLocaleKeysbefore release.
248-285: Untranslated “Swap” label.The chip caption
'Swap'should also come from the localisation bundle to avoid English-only UI.lib/views/wallet/wallet_page/wallet_main/wallet_overview.dart (1)
81-85: Currency formatting is fixed to USD.
NumberFormat.currency(symbol: '\$')ignores the user’s selected fiat.
Use the active fiat symbol (or locale) from settings to avoid confusing non-USD users.lib/bloc/cex_market_data/portfolio_growth/portfolio_growth_bloc.dart (2)
171-174: Duplicate cache refresh wastes bandwidth
updatePrices()is already called a few lines earlier inside the periodic loop, yet it’s invoked again here before every chart build. Remove one call to avoid doubling network traffic.
244-289: Edge-cases in helper math
coin.id.symbol.configSymbol.toUpperCase()risks key mismatches if the cached-price map uses raw symbols (e.g. “BTC”) whileconfigSymbolalready returns upper-case. Safer:final price = portfolioGrowthRepository.getCachedPrice(coin.id.symbol);
_calculateTotalBalanceforces a floor of0.01, which can fabricate money for dust portfolios. Prefer displaying<\$0.01in the UI instead of inflating the value.Percent change calculation divides by
totalBalance <= 0.01. Using the synthetic 0.01 from (2) can output misleading 100 % swings.lib/views/wallet/wallet_page/wallet_main/wallet_main.dart (2)
112-213: Hard-coded 340 px height breaks on tablets & desktops
The growth / P&L charts are wrapped in fixed-height containers. On tall screens they look cramped; on very small devices they may overflow. Let the chart decide its own height or useAspectRatio:- height: 340, + height: isMobile ? 280 : 420,or remove the explicit height altogether.
73-73: TabController always initialised with 3 tabs
For non-logged-in users the UI shows only one page; still creating a 3-lengthTabControlleris harmless but unnecessary. You can lazily instantiate it only whenAuthorizeMode.logIn.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (17)
lib/bloc/app_bloc_root.dart(1 hunks)lib/bloc/cex_market_data/portfolio_growth/portfolio_growth_bloc.dart(4 hunks)lib/bloc/cex_market_data/portfolio_growth/portfolio_growth_repository.dart(2 hunks)lib/bloc/cex_market_data/portfolio_growth/portfolio_growth_state.dart(1 hunks)lib/bloc/cex_market_data/price_chart/models/price_chart_interval.dart(1 hunks)lib/bloc/cex_market_data/price_chart/models/time_period.dart(1 hunks)lib/bloc/coins_bloc/coins_repo.dart(1 hunks)lib/model/cex_price.dart(1 hunks)lib/shared/widgets/coin_balance.dart(1 hunks)lib/views/wallet/wallet_page/common/asset_list_item.dart(1 hunks)lib/views/wallet/wallet_page/common/assets_list.dart(1 hunks)lib/views/wallet/wallet_page/common/expandable_coin_list_item.dart(5 hunks)lib/views/wallet/wallet_page/wallet_main/active_coins_list.dart(1 hunks)lib/views/wallet/wallet_page/wallet_main/wallet_main.dart(5 hunks)lib/views/wallet/wallet_page/wallet_main/wallet_manage_section.dart(3 hunks)lib/views/wallet/wallet_page/wallet_main/wallet_overview.dart(4 hunks)packages/komodo_ui_kit/lib/src/display/statistic_card.dart(1 hunks)
✅ Files skipped from review due to trivial changes (4)
- lib/bloc/coins_bloc/coins_repo.dart
- lib/shared/widgets/coin_balance.dart
- packages/komodo_ui_kit/lib/src/display/statistic_card.dart
- lib/bloc/cex_market_data/price_chart/models/price_chart_interval.dart
⏰ Context from checks skipped due to timeout of 90000ms (11)
- GitHub Check: Build Desktop (linux)
- GitHub Check: Build Desktop (windows)
- GitHub Check: Build Desktop (macos)
- GitHub Check: unit_tests
- GitHub Check: osv_scan
- GitHub Check: Build Mobile (iOS)
- GitHub Check: Test web-app-macos
- GitHub Check: Build Mobile (Android)
- GitHub Check: validate_code_guidelines
- GitHub Check: Test web-app-linux-profile
- GitHub Check: build_and_preview
🔇 Additional comments (6)
lib/bloc/app_bloc_root.dart (1)
195-199: Confirm symbol change intentSwitching the initial
PriceChartStartedsymbols to['BTC']shifts the default focus away from KMD.
Please verify this is a deliberate product decision and that BTC price data is always available at startup.lib/views/wallet/wallet_page/common/assets_list.dart (1)
48-52: Guard against missing map entries
priceChangePercentages[asset.id]can benull.
If downstream widgets assume a non-nulldouble, add a default (e.g.?? 0).lib/views/wallet/wallet_page/wallet_main/active_coins_list.dart (1)
59-63: Confirm Flutter version supportsSliverList.builder
SliverList.builderis only available from Flutter 3.10+.
If you target older SDKs, revert toSliverChildBuilderDelegateto keep compatibility.lib/model/cex_price.dart (2)
1-5: Good cleanupRe-using SDK definitions via typedefs removes duplicated models.
6-10: Edge-case for unknown provider
cexDataProvider()falls back tounknown, which relies on that enum member existing in the SDK. Confirm it’s still present after the SDK upgrade to avoid runtime errors.lib/bloc/cex_market_data/portfolio_growth/portfolio_growth_bloc.dart (1)
175-178: Totals may disagree with the plotted data
_calculateTotal*functions run on allcoins, while the chart just built might exclude unsupported / inactive coins. This can show a balance that does not match the chart line. Pass the exact coin list used to buildchartinstead of the originalcoinsargument.Also applies to: 183-186
| required this.totalBalance, | ||
| required this.totalChange24h, | ||
| required this.percentageChange24h, | ||
| }); | ||
|
|
||
| final ChartData portfolioGrowth; | ||
| final double percentageIncrease; | ||
| final double totalBalance; | ||
| final double totalChange24h; | ||
| final double percentageChange24h; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Avoid storing money in double.
double introduces rounding errors that quickly surface in financial UIs (e.g. $0.01 sometimes renders as 0.009999).
If practical, migrate these three monetary fields to a fixed-precision type (Decimal, BigInt cents, or a dedicated Money class) and format at the edge.
🤖 Prompt for AI Agents
In lib/bloc/cex_market_data/portfolio_growth/portfolio_growth_state.dart between
lines 22 and 32, the fields totalBalance, totalChange24h, and
percentageChange24h are currently typed as double, which can cause rounding
errors in financial calculations. To fix this, change these fields to use a
fixed-precision type such as Decimal, BigInt representing cents, or a dedicated
Money class. Update all related code to handle this new type and ensure
formatting to string for display happens only at the UI layer.
| Future<double> calculateTotalChange24h(List<Coin> coins) async { | ||
| // Fetch current prices including 24h change data | ||
| final prices = await _coinsRepository.fetchCurrentPrices() ?? {}; | ||
|
|
||
| // Calculate the 24h change by summing the change percentage of each coin | ||
| // multiplied by its USD balance and divided by 100 (to convert percentage to decimal) | ||
| double totalChange = 0.0; | ||
| for (final coin in coins) { | ||
| final price = prices[coin.id.symbol.configSymbol.toUpperCase()]; | ||
| final change24h = price?.change24h ?? 0.0; | ||
| final usdBalance = coin.lastKnownUsdBalance(_sdk) ?? 0.0; | ||
| totalChange += (change24h * usdBalance / 100); | ||
| } | ||
| return totalChange; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
calculateTotalChange24h triggers an extra network call per invocation.
Every call fetches fresh prices, even though updatePrices() intentionally pre-loads and caches them.
This defeats caching and can hammer the market-data service.
-final prices = await _coinsRepository.fetchCurrentPrices() ?? {};
+final prices = _coinsRepository.getCachedPrices() ??
+ await _coinsRepository.fetchCurrentPrices() ?? {};Alternatively pass the already-cached map from the caller.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Future<double> calculateTotalChange24h(List<Coin> coins) async { | |
| // Fetch current prices including 24h change data | |
| final prices = await _coinsRepository.fetchCurrentPrices() ?? {}; | |
| // Calculate the 24h change by summing the change percentage of each coin | |
| // multiplied by its USD balance and divided by 100 (to convert percentage to decimal) | |
| double totalChange = 0.0; | |
| for (final coin in coins) { | |
| final price = prices[coin.id.symbol.configSymbol.toUpperCase()]; | |
| final change24h = price?.change24h ?? 0.0; | |
| final usdBalance = coin.lastKnownUsdBalance(_sdk) ?? 0.0; | |
| totalChange += (change24h * usdBalance / 100); | |
| } | |
| return totalChange; | |
| Future<double> calculateTotalChange24h(List<Coin> coins) async { | |
| // Fetch current prices including 24h change data | |
| - final prices = await _coinsRepository.fetchCurrentPrices() ?? {}; | |
| + final prices = _coinsRepository.getCachedPrices() | |
| + ?? await _coinsRepository.fetchCurrentPrices() ?? {}; | |
| // Calculate the 24h change by summing the change percentage of each coin | |
| // multiplied by its USD balance and divided by 100 (to convert percentage to decimal) | |
| double totalChange = 0.0; | |
| for (final coin in coins) { | |
| final price = prices[coin.id.symbol.configSymbol.toUpperCase()]; | |
| final change24h = price?.change24h ?? 0.0; | |
| final usdBalance = coin.lastKnownUsdBalance(_sdk) ?? 0.0; | |
| totalChange += (change24h * usdBalance / 100); | |
| } | |
| return totalChange; | |
| } |
🤖 Prompt for AI Agents
In lib/bloc/cex_market_data/portfolio_growth/portfolio_growth_repository.dart
around lines 525 to 538, the calculateTotalChange24h method fetches current
prices on every call, causing unnecessary network requests and bypassing the
existing caching done by updatePrices(). To fix this, modify the method to
accept the cached prices map as a parameter from the caller instead of fetching
it internally, and use this passed-in map to calculate the total 24h change,
thereby avoiding redundant network calls and leveraging the cached data.
| Stream<Object?>.periodic(event.updateFrequency).asyncMap((_) async { | ||
| // Update prices before fetching chart data | ||
| await portfolioGrowthRepository.updatePrices(); | ||
| return _fetchPortfolioGrowthChart(event); | ||
| }), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Un-throttled price polling may flood the CEX API
updatePrices() is executed on every tick of Stream.periodic. If event.updateFrequency is small (e.g. a few seconds), the wallet will hammer the price endpoint continuously, even when the UI is backgrounded. Consider one of:
-Stream<Object?>.periodic(event.updateFrequency)…
+Stream<Object?>.periodic(event.updateFrequency.clamp(
+ const Duration(seconds: 30), // minimum polling interval
+ const Duration(minutes: 5), // upper bound
+))…or move price refreshing to a debounced/background service.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In lib/bloc/cex_market_data/portfolio_growth/portfolio_growth_bloc.dart around
lines 124 to 128, the current implementation calls updatePrices() on every tick
of Stream.periodic, which can flood the CEX API if the updateFrequency is small.
To fix this, implement a throttling or debouncing mechanism to limit how often
updatePrices() is called, or move the price refreshing logic to a background
service that respects app lifecycle states, ensuring it does not run
aggressively when the UI is backgrounded.
| class CoinListView extends StatelessWidget { | ||
| const CoinListView({ | ||
| super.key, | ||
| required this.mode, | ||
| required this.searchPhrase, | ||
| required this.withBalance, | ||
| required this.onActiveCoinItemTap, | ||
| required this.onAssetItemTap, | ||
| }); | ||
|
|
||
| final AuthorizeMode mode; | ||
| final String searchPhrase; | ||
| final bool withBalance; | ||
| final Function(Coin) onActiveCoinItemTap; | ||
| final Function(Coin) onAssetItemTap; | ||
|
|
||
| @override | ||
| Widget build(BuildContext context) { | ||
| switch (mode) { | ||
| case AuthorizeMode.logIn: | ||
| return ActiveCoinsList( | ||
| searchPhrase: searchPhrase, | ||
| withBalance: withBalance, | ||
| onCoinItemTap: onActiveCoinItemTap, | ||
| ); | ||
| case AuthorizeMode.hiddenLogin: | ||
| case AuthorizeMode.noLogin: | ||
| return AssetsList( | ||
| useGroupedView: true, | ||
| assets: context | ||
| .read<CoinsBloc>() | ||
| .state | ||
| .coins | ||
| .values | ||
| .map((coin) => coin.assetId) | ||
| .toList(), | ||
| withBalance: false, | ||
| searchPhrase: searchPhrase, | ||
| onAssetItemTap: (assetId) => onAssetItemTap( | ||
| context | ||
| .read<CoinsBloc>() | ||
| .state | ||
| .coins | ||
| .values | ||
| .firstWhere((coin) => coin.assetId == assetId), | ||
| ), | ||
| ); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
firstWhere can throw for unknown asset IDs
CoinListView converts an assetId back to a Coin with firstWhere, which throws if the coin set changes between build and tap. Use a null-safe lookup:
- .firstWhere((coin) => coin.assetId == assetId),
+ .firstWhereOrNull((coin) => coin.assetId == assetId) ??
+ Coin.unknown(assetId),(or guard against null).
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| class CoinListView extends StatelessWidget { | |
| const CoinListView({ | |
| super.key, | |
| required this.mode, | |
| required this.searchPhrase, | |
| required this.withBalance, | |
| required this.onActiveCoinItemTap, | |
| required this.onAssetItemTap, | |
| }); | |
| final AuthorizeMode mode; | |
| final String searchPhrase; | |
| final bool withBalance; | |
| final Function(Coin) onActiveCoinItemTap; | |
| final Function(Coin) onAssetItemTap; | |
| @override | |
| Widget build(BuildContext context) { | |
| switch (mode) { | |
| case AuthorizeMode.logIn: | |
| return ActiveCoinsList( | |
| searchPhrase: searchPhrase, | |
| withBalance: withBalance, | |
| onCoinItemTap: onActiveCoinItemTap, | |
| ); | |
| case AuthorizeMode.hiddenLogin: | |
| case AuthorizeMode.noLogin: | |
| return AssetsList( | |
| useGroupedView: true, | |
| assets: context | |
| .read<CoinsBloc>() | |
| .state | |
| .coins | |
| .values | |
| .map((coin) => coin.assetId) | |
| .toList(), | |
| withBalance: false, | |
| searchPhrase: searchPhrase, | |
| onAssetItemTap: (assetId) => onAssetItemTap( | |
| context | |
| .read<CoinsBloc>() | |
| .state | |
| .coins | |
| .values | |
| .firstWhere((coin) => coin.assetId == assetId), | |
| ), | |
| ); | |
| } | |
| } | |
| } | |
| class CoinListView extends StatelessWidget { | |
| const CoinListView({ | |
| super.key, | |
| required this.mode, | |
| required this.searchPhrase, | |
| required this.withBalance, | |
| required this.onActiveCoinItemTap, | |
| required this.onAssetItemTap, | |
| }); | |
| final AuthorizeMode mode; | |
| final String searchPhrase; | |
| final bool withBalance; | |
| final Function(Coin) onActiveCoinItemTap; | |
| final Function(Coin) onAssetItemTap; | |
| @override | |
| Widget build(BuildContext context) { | |
| switch (mode) { | |
| case AuthorizeMode.logIn: | |
| return ActiveCoinsList( | |
| searchPhrase: searchPhrase, | |
| withBalance: withBalance, | |
| onCoinItemTap: onActiveCoinItemTap, | |
| ); | |
| case AuthorizeMode.hiddenLogin: | |
| case AuthorizeMode.noLogin: | |
| return AssetsList( | |
| useGroupedView: true, | |
| assets: context | |
| .read<CoinsBloc>() | |
| .state | |
| .coins | |
| .values | |
| .map((coin) => coin.assetId) | |
| .toList(), | |
| withBalance: false, | |
| searchPhrase: searchPhrase, | |
| onAssetItemTap: (assetId) => onAssetItemTap( | |
| context | |
| .read<CoinsBloc>() | |
| .state | |
| .coins | |
| .values | |
| - .firstWhere((coin) => coin.assetId == assetId), | |
| + .firstWhereOrNull((coin) => coin.assetId == assetId) ?? | |
| + Coin.unknown(assetId), | |
| ), | |
| ); | |
| } | |
| } | |
| } |
🤖 Prompt for AI Agents
In lib/views/wallet/wallet_page/wallet_main/wallet_main.dart between lines 378
and 427, the use of firstWhere to find a Coin by assetId can throw an exception
if the assetId is not found due to changes in the coin set between build and
tap. To fix this, replace firstWhere with a null-safe lookup method such as
firstWhereOrNull or use a try-catch block to handle the case where no matching
Coin is found, ensuring the onAssetItemTap callback is only called with a valid
Coin or guarded against null values.
Komodo Wallet v0.9.1 Release Notes
This release includes critical bug fixes for Trezor hardware wallet functionality and introduces a comprehensive redesign of the wallet assets page with improved mobile experience and enhanced portfolio management features.
✨ New Features
🎨 Redesigned Assets Page
📊 Real-time Data Integration
🐛 Bug Fixes
🏗️ Technical Improvements
NestedScrollViewfor improved scroll behavior with tab navigationCoinListViewinto a separate widget for cleaner code architectureCexPriceto use SDK types for better compatibilityFull Changelog: 0.9.0...0.9.1