From 8e87464caa98c01b68d091137d192745869ae4fd Mon Sep 17 00:00:00 2001 From: CharlVS <77973576+CharlVS@users.noreply.github.com> Date: Mon, 16 Mar 2026 20:00:29 +0100 Subject: [PATCH 1/4] fix(sia): finalize app release integration --- lib/bloc/coins_bloc/coins_repo.dart | 23 ++++++ .../coins_manager/coins_manager_bloc.dart | 76 ++++++++++++++----- .../withdraw_form/withdraw_form_bloc.dart | 27 +++++++ pubspec.lock | 16 ++-- sdk | 2 +- 5 files changed, 114 insertions(+), 30 deletions(-) diff --git a/lib/bloc/coins_bloc/coins_repo.dart b/lib/bloc/coins_bloc/coins_repo.dart index e4a6d7242a..9822d0937a 100644 --- a/lib/bloc/coins_bloc/coins_repo.dart +++ b/lib/bloc/coins_bloc/coins_repo.dart @@ -26,6 +26,7 @@ import 'package:web_dex/mm2/mm2_api/rpc/withdraw/withdraw_request.dart'; import 'package:web_dex/model/cex_price.dart'; import 'package:web_dex/model/coin.dart'; import 'package:web_dex/model/kdf_auth_metadata_extension.dart'; +import 'package:web_dex/model/wallet.dart'; import 'package:web_dex/model/text_error.dart'; import 'package:web_dex/model/withdraw_details/withdraw_details.dart'; import 'package:web_dex/services/arrr_activation/arrr_activation_service.dart'; @@ -66,6 +67,8 @@ class CoinsRepo { final ArrrActivationService _arrrActivationService; final _log = Logger('CoinsRepo'); + static const _unsupportedTrezorSiaMessage = + 'SIA is not supported for Trezor wallets in this release.'; /// { acc: { abbr: address }}, used in Fiat Page final Map> _addressCache = {}; @@ -382,6 +385,26 @@ class CoinsRepo { return; } + final walletType = (await _kdfSdk.currentWallet())?.config.type; + if (walletType == WalletType.trezor) { + final unsupportedAssetIds = assets + .where((asset) => asset.id.subClass == CoinSubClass.sia) + .map((asset) => asset.id.id) + .toList(); + if (unsupportedAssetIds.isNotEmpty) { + _log.warning( + 'Skipping unsupported Trezor SIA activation for ' + '${unsupportedAssetIds.join(', ')}: $_unsupportedTrezorSiaMessage', + ); + } + assets = assets + .where((asset) => asset.id.subClass != CoinSubClass.sia) + .toList(); + if (assets.isEmpty) { + return; + } + } + // Debug logging for activation if (kDebugElectrumLogs) { final coinIdList = assets.map((e) => e.id.id).join(', '); diff --git a/lib/bloc/coins_manager/coins_manager_bloc.dart b/lib/bloc/coins_manager/coins_manager_bloc.dart index 2b0da74164..b64f28739f 100644 --- a/lib/bloc/coins_manager/coins_manager_bloc.dart +++ b/lib/bloc/coins_manager/coins_manager_bloc.dart @@ -15,6 +15,7 @@ import 'package:web_dex/bloc/settings/settings_repository.dart'; import 'package:web_dex/blocs/trading_entities_bloc.dart'; import 'package:web_dex/model/coin.dart'; import 'package:web_dex/model/coin_utils.dart'; +import 'package:web_dex/model/wallet.dart'; import 'package:web_dex/shared/utils/extensions/kdf_user_extensions.dart'; import 'package:web_dex/router/state/wallet_state.dart'; import 'package:web_dex/views/wallet/coins_manager/coins_manager_helpers.dart'; @@ -68,13 +69,17 @@ class CoinsManagerBloc extends Bloc { ) async { final List filters = []; - final mergedCoinsList = _mergeCoinLists( + final originalCoins = await _filterUnsupportedHardwareCoins( await _getOriginalCoinList( _coinsRepo, event.action, cachedKnownCoinsMap: _cachedKnownCoinsMap, cachedWalletCoins: _cachedWalletCoins, ), + event.action, + ); + final mergedCoinsList = _mergeCoinLists( + originalCoins, state.coins, ).toList(); @@ -86,8 +91,15 @@ class CoinsManagerBloc extends Bloc { state.selectedCoins, event.action, ); + final visibleSelectedCoins = await _filterUnsupportedHardwareCoins( + selectedCoins, + event.action, + ); - final uniqueCombinedList = {...mergedCoinsList, ...selectedCoins}; + final uniqueCombinedList = { + ...mergedCoinsList, + ...visibleSelectedCoins, + }; final testFilteredCoins = await _filterTestCoinsIfNeeded( uniqueCombinedList.toList(), @@ -111,7 +123,7 @@ class CoinsManagerBloc extends Bloc { state.copyWith( coins: sortedCoins.unique((coin) => coin.id), action: event.action, - selectedCoins: selectedCoins, + selectedCoins: visibleSelectedCoins, ), ); } @@ -147,11 +159,14 @@ class CoinsManagerBloc extends Bloc { _cachedTestCoinsEnabled = (await _settingsRepository.loadSettings()).testCoinsEnabled; - final List coins = await _getOriginalCoinList( - _coinsRepo, + final List coins = await _filterUnsupportedHardwareCoins( + await _getOriginalCoinList( + _coinsRepo, + event.action, + cachedKnownCoinsMap: _cachedKnownCoinsMap, + cachedWalletCoins: _cachedWalletCoins, + ), event.action, - cachedKnownCoinsMap: _cachedKnownCoinsMap, - cachedWalletCoins: _cachedWalletCoins, ); // Add wallet coins to selected coins if in add mode so that they @@ -164,9 +179,13 @@ class CoinsManagerBloc extends Bloc { : [], event.action, ); + final visibleSelectedCoins = await _filterUnsupportedHardwareCoins( + selectedCoins, + event.action, + ); final filteredCoins = await _filterTestCoinsIfNeeded( - {...coins, ...selectedCoins}.toList(), + {...coins, ...visibleSelectedCoins}.toList(), ); final sortedCoins = _sortCoins(filteredCoins, event.action, state.sortData); @@ -174,7 +193,7 @@ class CoinsManagerBloc extends Bloc { state.copyWith( coins: sortedCoins.unique((coin) => coin.id), action: event.action, - selectedCoins: selectedCoins, + selectedCoins: visibleSelectedCoins, ), ); } @@ -185,9 +204,7 @@ class CoinsManagerBloc extends Bloc { ) { final List newTypes = state.selectedCoinTypes.contains(event.type) - ? state.selectedCoinTypes - .where((type) => type != event.type) - .toList() + ? state.selectedCoinTypes.where((type) => type != event.type).toList() : [...state.selectedCoinTypes, event.type]; emit(state.copyWith(selectedCoinTypes: newTypes)); @@ -249,10 +266,12 @@ class CoinsManagerBloc extends Bloc { } on ZhtlcActivationCancelled { // Revert optimistic selection and show a friendly message selectedCoins.remove(coin); - emit(state.copyWith( - selectedCoins: selectedCoins.toList(), - errorMessage: 'Activation canceled.', - )); + emit( + state.copyWith( + selectedCoins: selectedCoins.toList(), + errorMessage: 'Activation canceled.', + ), + ); return; } } else { @@ -358,12 +377,26 @@ class CoinsManagerBloc extends Bloc { List _filterByType(List coins) { return coins - .where( - (coin) => state.selectedCoinTypes.contains(coin.id.subClass), - ) + .where((coin) => state.selectedCoinTypes.contains(coin.id.subClass)) .toList(); } + Future> _filterUnsupportedHardwareCoins( + List coins, + CoinsManagerAction action, + ) async { + if (action != CoinsManagerAction.add) { + return coins; + } + + final currentWalletType = (await _sdk.auth.currentUser)?.wallet.config.type; + if (currentWalletType != WalletType.trezor) { + return coins; + } + + return coins.where((coin) => coin.id.subClass != CoinSubClass.sia).toList(); + } + /// Merges wallet coins into selected coins list when in add mode Future> _mergeWalletCoinsIfNeeded( List selectedCoins, @@ -383,8 +416,9 @@ class CoinsManagerBloc extends Bloc { // This ensures toggles remain OFF if auto-activation was bypassed. if (walletCoin.id.subClass == CoinSubClass.zhtlc) { try { - final saved = - await _sdk.activationConfigService.getSavedZhtlc(walletCoin.id); + final saved = await _sdk.activationConfigService.getSavedZhtlc( + walletCoin.id, + ); if (saved == null) { continue; } diff --git a/lib/bloc/withdraw_form/withdraw_form_bloc.dart b/lib/bloc/withdraw_form/withdraw_form_bloc.dart index 7ea4140b17..c3ee980392 100644 --- a/lib/bloc/withdraw_form/withdraw_form_bloc.dart +++ b/lib/bloc/withdraw_form/withdraw_form_bloc.dart @@ -24,6 +24,8 @@ import 'package:decimal/decimal.dart'; class WithdrawFormBloc extends Bloc { static final Logger _logger = Logger('WithdrawFormBloc'); + static const _unsupportedSiaHardwareWalletMessage = + 'SIA is not supported for hardware wallets in this release.'; final KomodoDefiSdk _sdk; final WalletType? _walletType; @@ -586,6 +588,17 @@ class WithdrawFormBloc extends Bloc { Emitter emit, ) async { if (state.hasValidationErrors) return; + if (_isUnsupportedSiaHardwareWalletFlow) { + emit( + state.copyWith( + previewError: () => + TextError(error: _unsupportedSiaHardwareWalletMessage), + isSending: false, + isAwaitingTrezorConfirmation: false, + ), + ); + return; + } try { emit( @@ -647,6 +660,17 @@ class WithdrawFormBloc extends Bloc { Emitter emit, ) async { if (state.hasValidationErrors) return; + if (_isUnsupportedSiaHardwareWalletFlow) { + emit( + state.copyWith( + transactionError: () => + TextError(error: _unsupportedSiaHardwareWalletMessage), + isSending: false, + isAwaitingTrezorConfirmation: false, + ), + ); + return; + } try { emit( @@ -733,6 +757,9 @@ class WithdrawFormBloc extends Bloc { } } + bool get _isUnsupportedSiaHardwareWalletFlow => + _walletType == WalletType.trezor && state.asset.protocol is SiaProtocol; + void _onCancelled( WithdrawFormCancelled event, Emitter emit, diff --git a/pubspec.lock b/pubspec.lock index f620954de5..46d83d1618 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -844,10 +844,10 @@ packages: dependency: transitive description: name: matcher - sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6" + sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 url: "https://pub.dev" source: hosted - version: "0.12.18" + version: "0.12.19" material_color_utilities: dependency: transitive description: @@ -1297,26 +1297,26 @@ packages: dependency: "direct dev" description: name: test - sha256: "54c516bbb7cee2754d327ad4fca637f78abfc3cbcc5ace83b3eda117e42cd71a" + sha256: "280d6d890011ca966ad08df7e8a4ddfab0fb3aa49f96ed6de56e3521347a9ae7" url: "https://pub.dev" source: hosted - version: "1.29.0" + version: "1.30.0" test_api: dependency: transitive description: name: test_api - sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" + sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" url: "https://pub.dev" source: hosted - version: "0.7.9" + version: "0.7.10" test_core: dependency: transitive description: name: test_core - sha256: "394f07d21f0f2255ec9e3989f21e54d3c7dc0e6e9dbce160e5a9c1a6be0e2943" + sha256: "0381bd1585d1a924763c308100f2138205252fb90c9d4eeaf28489ee65ccde51" url: "https://pub.dev" source: hosted - version: "0.6.15" + version: "0.6.16" typed_data: dependency: transitive description: diff --git a/sdk b/sdk index 54e1420f8f..5902fcf883 160000 --- a/sdk +++ b/sdk @@ -1 +1 @@ -Subproject commit 54e1420f8f657414168555a849d9041ca3eea5b9 +Subproject commit 5902fcf8830c72572bd1cd9140c3b922f13b3d6f From e1dcd7db4ede0cf0e3833f924d2fbaa1dd9f41c6 Mon Sep 17 00:00:00 2001 From: CharlVS <77973576+CharlVS@users.noreply.github.com> Date: Wed, 18 Mar 2026 19:51:59 +0100 Subject: [PATCH 2/4] chore(sdk): repoint app SIA branch to sdk/test-sia Point the app's SIA integration branch at the current sdk/test-sia tip so the submodule references a GitHub-visible commit and the dev PR can be reviewed alongside the SDK PR. --- sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk b/sdk index 5902fcf883..67ce7e0321 160000 --- a/sdk +++ b/sdk @@ -1 +1 @@ -Subproject commit 5902fcf8830c72572bd1cd9140c3b922f13b3d6f +Subproject commit 67ce7e0321816c7885fb3285d9e83d2e79182de1 From 94b36cf258db2b4c2c31e36b287c1d686f66205c Mon Sep 17 00:00:00 2001 From: CharlVS <77973576+CharlVS@users.noreply.github.com> Date: Wed, 18 Mar 2026 20:25:50 +0100 Subject: [PATCH 3/4] fix(sia): broadcast suspended state for filtered Trezor SIA assets When a Trezor wallet has SIA in its activated coins from an older build, the early return in activateAssetsSync would leave those coins stuck in the "activating" state because no update was ever broadcast via enabledAssetsChanges. Now we broadcast CoinState.suspended for each filtered SIA asset before discarding them, so CoinsBloc correctly removes them from walletCoins. --- lib/bloc/coins_bloc/coins_repo.dart | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/bloc/coins_bloc/coins_repo.dart b/lib/bloc/coins_bloc/coins_repo.dart index 9822d0937a..650c18a82c 100644 --- a/lib/bloc/coins_bloc/coins_repo.dart +++ b/lib/bloc/coins_bloc/coins_repo.dart @@ -387,15 +387,20 @@ class CoinsRepo { final walletType = (await _kdfSdk.currentWallet())?.config.type; if (walletType == WalletType.trezor) { - final unsupportedAssetIds = assets - .where((asset) => asset.id.subClass == CoinSubClass.sia) - .map((asset) => asset.id.id) - .toList(); - if (unsupportedAssetIds.isNotEmpty) { + final unsupportedSiaAssets = + assets.where((asset) => asset.id.subClass == CoinSubClass.sia); + if (unsupportedSiaAssets.isNotEmpty) { _log.warning( 'Skipping unsupported Trezor SIA activation for ' - '${unsupportedAssetIds.join(', ')}: $_unsupportedTrezorSiaMessage', + '${unsupportedSiaAssets.map((a) => a.id.id).join(', ')}: ' + '$_unsupportedTrezorSiaMessage', ); + for (final siaAsset in unsupportedSiaAssets) { + _broadcastAsset( + _assetToCoinWithoutAddress(siaAsset) + .copyWith(state: CoinState.suspended), + ); + } } assets = assets .where((asset) => asset.id.subClass != CoinSubClass.sia) From 36eaecf291c8cc9cd8bc2af3ca1367d0c910cb24 Mon Sep 17 00:00:00 2001 From: CharlVS <77973576+CharlVS@users.noreply.github.com> Date: Wed, 18 Mar 2026 21:55:16 +0100 Subject: [PATCH 4/4] chore(sdk): update submodule to include withdrawal fix (#322) --- sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk b/sdk index 7a3f409ac3..482ca5feb5 160000 --- a/sdk +++ b/sdk @@ -1 +1 @@ -Subproject commit 7a3f409ac3a31da934edec4d77d79a5bf21fe0a3 +Subproject commit 482ca5feb53960ded40788873f41d291bb317906