From 2764b46bfeec1078026c20979d09034be6acaca9 Mon Sep 17 00:00:00 2001 From: malik1004x Date: Mon, 22 Jun 2026 18:22:33 +0200 Subject: [PATCH 1/5] Fix desktop qr sizing (#3344) * fix qr sizing on desktop * fix cardsview sizing --- lib/new-ui/widgets/coins_page/cards/cards_view.dart | 7 +++---- lib/new-ui/widgets/receive_page/receive_qr_code.dart | 4 +++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/new-ui/widgets/coins_page/cards/cards_view.dart b/lib/new-ui/widgets/coins_page/cards/cards_view.dart index 2c36d635a..427660b90 100644 --- a/lib/new-ui/widgets/coins_page/cards/cards_view.dart +++ b/lib/new-ui/widgets/coins_page/cards/cards_view.dart @@ -10,6 +10,7 @@ import 'package:cake_wallet/new-ui/pages/send_page.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/utils/feature_flag.dart'; import 'package:cake_wallet/utils/payment_request.dart'; +import 'package:cake_wallet/utils/responsive_layout_util.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; import 'package:cake_wallet/view_model/monero_account_list/monero_account_list_view_model.dart'; import 'package:cw_core/card_design.dart'; @@ -72,8 +73,6 @@ class _CardsViewState extends State { final top = baseTop - (howFarBehind * overlapAmount); - final double cardWidth = MediaQuery.of(context).size.width * 0.878; - final double effectiveCardWidth = min(cardWidth, 768); final left = (parentWidth - effectiveCardWidth) / 2.0; @@ -228,9 +227,9 @@ class _CardsViewState extends State { } } + double get effectiveCardWidth => min(MediaQuery.of(context).size.width * 0.878, responsiveLayoutUtil.shouldRenderMobileUI ? 768 : 512); + double _getBoxHeight(int numCards, double overlapAmount) { - final double cardWidth = MediaQuery.of(context).size.width * 0.878; - final double effectiveCardWidth = min(cardWidth, 768); return /* height of initial card */ (2 / 3.2) * (effectiveCardWidth) + diff --git a/lib/new-ui/widgets/receive_page/receive_qr_code.dart b/lib/new-ui/widgets/receive_page/receive_qr_code.dart index e6f4ba5d1..6ff9eaf58 100644 --- a/lib/new-ui/widgets/receive_page/receive_qr_code.dart +++ b/lib/new-ui/widgets/receive_page/receive_qr_code.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/widgets/cake_image_widget.dart'; @@ -29,7 +31,7 @@ class ReceiveQrCode extends StatelessWidget { @override Widget build(BuildContext context) { final double targetY = largeQrMode ? largeQrModeBottomPadding+50 : 0; - final double resolvedSize = MediaQuery.of(context).size.width * 0.5; + final double resolvedSize = min(MediaQuery.of(context).size.width, MediaQuery.of(context).size.height) * 0.5; final double resolvedScale = largeQrMode ? 1.7 : 1; return Stack( From cda9d09ead46a40b434b0c0b88740fe9db945167 Mon Sep 17 00:00:00 2001 From: Omar Date: Tue, 23 Jun 2026 17:39:50 +0200 Subject: [PATCH 2/5] minor fixes [skip ci] --- lib/src/screens/backup/backup_page.dart | 8 ++++++-- lib/view_model/hardware_wallet/ledger_view_model.dart | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/src/screens/backup/backup_page.dart b/lib/src/screens/backup/backup_page.dart index 59abff990..34ec4a74d 100644 --- a/lib/src/screens/backup/backup_page.dart +++ b/lib/src/screens/backup/backup_page.dart @@ -154,8 +154,12 @@ class BackupPage extends BasePage { leftButtonText: S.of(context).share, actionRightButton: () async { await backupViewModelBase.saveToDownload(backup.name, backup.file); - Navigator.of(dialogContext).pop(); - await showBar(context, S.of(context).file_saved); + if (dialogContext.mounted && Navigator.canPop(dialogContext)) { + Navigator.of(dialogContext).pop(); + } + if (context.mounted && Navigator.canPop(context)) { + await showBar(context, S.of(context).file_saved); + } }, actionLeftButton: () async { Navigator.of(dialogContext).pop(); diff --git a/lib/view_model/hardware_wallet/ledger_view_model.dart b/lib/view_model/hardware_wallet/ledger_view_model.dart index c0746223a..5e77473dd 100644 --- a/lib/view_model/hardware_wallet/ledger_view_model.dart +++ b/lib/view_model/hardware_wallet/ledger_view_model.dart @@ -161,7 +161,7 @@ abstract class LedgerViewModelBase extends HardwareWalletViewModel with Store { allowChangeWallet: true, isReconnect: true, onConnectDevice: (context, ledgerVM) async { - if (context.mounted) { + if (context.mounted && Navigator.of(context).canPop()) { Navigator.of(context).pop(); } }, From 7a9a58554326bd3b4d53b5889d75084fa3e8bd00 Mon Sep 17 00:00:00 2001 From: Serhii <17529954+serhii-bor@users.noreply.github.com> Date: Thu, 25 Jun 2026 12:25:57 +0300 Subject: [PATCH 3/5] fix-monero-com-backup-restore-bug (#3339) * reject backups from other apps * make compatibility check optional --- lib/core/backup_service_v3.dart | 57 +++++++++++++++-- .../restore/restore_from_backup_page.dart | 62 ++++++++++++++----- .../restore_from_backup_view_model.dart | 9 ++- 3 files changed, 106 insertions(+), 22 deletions(-) diff --git a/lib/core/backup_service_v3.dart b/lib/core/backup_service_v3.dart index 9e9b5b667..7d746ff42 100644 --- a/lib/core/backup_service_v3.dart +++ b/lib/core/backup_service_v3.dart @@ -144,6 +144,21 @@ class BackupMetadata { } } +class IncompatibleBackupAppException implements Exception { + IncompatibleBackupAppException({ + required this.sourceAppName, + required this.currentAppName, + }); + + final String sourceAppName; + final String currentAppName; + + @override + String toString() { + return 'This backup was created in $sourceAppName and cannot be restored in $currentAppName.'; + } +} + class BackupServiceV3 extends $BackupService { BackupServiceV3(super.secureStorage, super.transactionDescriptionBox, super.keyService, super.sharedPreferences); @@ -197,7 +212,8 @@ class BackupServiceV3 extends $BackupService { } } - Future importBackupFile(File file, String password, {String nonce = secrets.backupSalt}) { + Future importBackupFile(File file, String password, + {String nonce = secrets.backupSalt, bool checkBackupApp = true}) { final version = getVersionFile(file); switch (version) { case BackupVersion.unknown: @@ -210,11 +226,12 @@ class BackupServiceV3 extends $BackupService { case BackupVersion.v2: return super.importBackupV2(file.readAsBytesSync(), password); case BackupVersion.v3: - return importBackupFileV3(file, password, nonce: nonce); + return importBackupFileV3(file, password, nonce: nonce, checkBackupApp: checkBackupApp); } } - Future importBackupFileV3(File file, String password, {String nonce = secrets.backupSalt}) async{ + Future importBackupFileV3(File file, String password, + {String nonce = secrets.backupSalt,bool checkBackupApp = true}) async{ // Overall design of v3 backup is the following: // 1. backup.zip - plaintext zip file that user can open with any archive manager // 2. backup.zip/README.txt - text file to let user know what is inside of this file @@ -223,6 +240,11 @@ class BackupServiceV3 extends $BackupService { final inputStream = InputFileStream(file.path); final archive = ZipDecoder().decodeStream(inputStream); + + if (checkBackupApp) { + await _throwIfBackupWasCreatedInAnotherApp(archive); + } + final metadataFile = archive.findFile('metadata.json'); if (metadataFile == null) { throw Exception('Invalid v3 backup: missing metadata.json'); @@ -425,7 +447,7 @@ class BackupServiceV3 extends $BackupService { metadata.sha512sum = (await sha512.bind(dataBinUnencrypted.openRead()).first).toString(); final raf = await dataBinUnencrypted.open(); - + while (true) { printV("Reading chunk ${chunkIndex++}"); @@ -491,6 +513,33 @@ This backup was created on ${DateTime.now().toIso8601String()} return file; } + Future _throwIfBackupWasCreatedInAnotherApp(Archive archive) async { + final readmeFile = archive.findFile('README.txt'); + if (readmeFile == null) return; + + final readmeBytes = readmeFile.rawContent?.readBytes(); + if (readmeBytes == null) return; + + final readmeString = utf8.decode(readmeBytes, allowMalformed: true); + final sourceAppName = _extractBackupAppName(readmeString); + if (sourceAppName == null) return; + + + final currentAppName = (await PackageInfo.fromPlatform()).appName; + if (sourceAppName == currentAppName) return; + + + throw IncompatibleBackupAppException( + sourceAppName: sourceAppName, + currentAppName: currentAppName, + ); + } + + String? _extractBackupAppName(String readme) { + final match = RegExp(r'^This is a (.+) backup\.', multiLine: true).firstMatch(readme); + return match?.group(1)?.trim(); + } + static const chunkSize = 24 * 1024 * 1024; // 24MiB File setVersionFile(File file, BackupVersion version) { diff --git a/lib/src/screens/restore/restore_from_backup_page.dart b/lib/src/screens/restore/restore_from_backup_page.dart index 0f5bdd324..621a880ba 100644 --- a/lib/src/screens/restore/restore_from_backup_page.dart +++ b/lib/src/screens/restore/restore_from_backup_page.dart @@ -1,6 +1,8 @@ +import 'package:cake_wallet/core/backup_service_v3.dart'; import 'package:cake_wallet/core/execution_state.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; +import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; @@ -18,6 +20,7 @@ class RestoreFromBackupPage extends BasePage { final RestoreFromBackupViewModel restoreFromBackupViewModel; final TextEditingController textEditingController; + bool _isStateReactionSet = false; @override String get title => S.current.restore_title_from_backup; @@ -32,22 +35,26 @@ class RestoreFromBackupPage extends BasePage { @override Widget body(BuildContext context) { - reaction((_) => restoreFromBackupViewModel.state, (ExecutionState state) { - if (state is FailureState) { - WidgetsBinding.instance.addPostFrameCallback((_) { - showPopUp( - context: context, - builder: (BuildContext context) { - return AlertWithOneAction( - alertTitle: S.of(context).error, - alertContent: state.error, - buttonText: S.of(context).ok, - buttonAction: () => Navigator.of(context).pop(), - ); - }); - }); - } - }); + if (!_isStateReactionSet) { + _isStateReactionSet = true; + + reaction((_) => restoreFromBackupViewModel.state, (ExecutionState state) { + if (state is FailureState) { + WidgetsBinding.instance.addPostFrameCallback((_) { + showPopUp( + context: context, + builder: (BuildContext context) { + return AlertWithOneAction( + alertTitle: S.of(context).error, + alertContent: state.error, + buttonText: S.of(context).ok, + buttonAction: () => Navigator.of(context).pop(), + ); + }); + }); + } + }); + } return Center( child: ConstrainedBox( @@ -175,6 +182,29 @@ class RestoreFromBackupPage extends BasePage { } try { await restoreFromBackupViewModel.import(textEditingController.text); + } on IncompatibleBackupAppException catch (e) { + final isConfirmed = await showPopUp( + context: context, + builder: (_) { + return AlertWithTwoActions( + alertTitle: S.current.warning, + alertContent: + 'This backup was created in ${e.sourceAppName}, but you are restoring it in ${e.currentAppName}. ' + 'Please make sure this is the correct backup file before continuing.', + leftButtonText: S.of(context).cancel, + rightButtonText: S.of(context).ok, + actionLeftButton: () => Navigator.of(context).pop(false), + actionRightButton: () => Navigator.of(context).pop(true), + ); + }, + ); + + if (isConfirmed ?? false) { + await restoreFromBackupViewModel.import( + textEditingController.text, + checkBackupApp: false, + ); + } } catch (e) { await showPopUp( context: context, diff --git a/lib/view_model/restore_from_backup_view_model.dart b/lib/view_model/restore_from_backup_view_model.dart index 6a54cf4cc..40e2891f7 100644 --- a/lib/view_model/restore_from_backup_view_model.dart +++ b/lib/view_model/restore_from_backup_view_model.dart @@ -32,7 +32,7 @@ abstract class RestoreFromBackupViewModelBase with Store { void reset() => filePath = ''; @action - Future import(String password) async { + Future import(String password,{bool checkBackupApp = true}) async { try { state = IsExecutingState(); @@ -44,7 +44,9 @@ abstract class RestoreFromBackupViewModelBase with Store { final file = File(filePath); try { - await backupService.importBackupFile(file, password); + await backupService.importBackupFile(file, password, checkBackupApp: checkBackupApp); + } on IncompatibleBackupAppException { + rethrow; } catch (e, s) { if (e.toString().contains("unknown_backup_version")) { state = FailureState('This is not a valid backup file, please make sure you have selected the correct one'); @@ -74,6 +76,9 @@ abstract class RestoreFromBackupViewModelBase with Store { }); state = ExecutedSuccessfullyState(); + } on IncompatibleBackupAppException { + state = InitialExecutionState(); + rethrow; } catch (e, s) { var msg = e.toString().toLowerCase(); From d3a1464775911dcffa6dc912d04fad8e7c1d168b Mon Sep 17 00:00:00 2001 From: malik1004x Date: Thu, 25 Jun 2026 11:29:42 +0200 Subject: [PATCH 4/5] improve address rotation button ui + fix bug when autogenerate is disabled (#3334) * improve address rotation button ui + fix bug when autogenerate is disabled * remove dumbass debug print * add button show condition --- lib/new-ui/pages/receive_page.dart | 50 +++++++++++-------- .../wallet_address_list_view_model.dart | 13 ++++- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/lib/new-ui/pages/receive_page.dart b/lib/new-ui/pages/receive_page.dart index 9ad2d7d2f..84d1e935a 100644 --- a/lib/new-ui/pages/receive_page.dart +++ b/lib/new-ui/pages/receive_page.dart @@ -1,6 +1,7 @@ import 'package:cake_wallet/core/utilities.dart'; import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart'; import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/new-ui/widgets/modern_button.dart'; import 'package:cake_wallet/new-ui/widgets/receive_page/payjoin_copy_modal.dart'; import 'package:cake_wallet/new-ui/widgets/receive_page/receive_address_type.dart'; import 'package:cake_wallet/new-ui/widgets/receive_page/receive_address_widget.dart'; @@ -22,6 +23,7 @@ import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/payment_uris.dart'; import 'package:cw_core/receive_page_option.dart'; import 'package:cw_core/utils/print_verbose.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:mobx/mobx.dart'; import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; @@ -194,29 +196,37 @@ class _NewReceivePageState extends State { ModalTopBar( title: _largeQrMode ? "" : S.of(context).receive, leadingIcon: Icon(Icons.close), - trailingIcon: _largeQrMode - ? Icon(Icons.share) - : widget.addressListViewModel.hasAddressRotation - /* TODO rotating is broken on mweb, disabling for now, fix after mvp*/ - && - !(widget.receiveOptionViewModel.selectedReceiveOption.description ?? "") - .toLowerCase() - .contains("mweb") - ? Icon(Icons.refresh) - : null, onLeadingPressed: () { Navigator.of(context, rootNavigator: true).pop(); }, - onTrailingPressed: () { - if (_largeQrMode) { - ShareUtil.share( - text: widget.addressListViewModel.uri.toString(), - context: context, - ); - } else if (widget.addressListViewModel.hasAddressRotation) { - widget.addressListViewModel.rotateAddress(); - } - }, + trailingWidget: Observer( + builder: (_) => AnimatedSwitcher( + duration: Duration(milliseconds: 300), + child: _largeQrMode || widget.addressListViewModel.hasAddressRotation + /* TODO rotating is broken on mweb, disabling for now, fix after mvp*/ + && + !(widget.receiveOptionViewModel.selectedReceiveOption.description ?? "") + .toLowerCase() + .contains("mweb") ? ModernButton( + key: ValueKey(_largeQrMode), + size: 36, + icon: _largeQrMode ? Icon(Icons.share) : widget.addressListViewModel.isRotatingAddress + ? CupertinoActivityIndicator() + : Icon(Icons.refresh), + onPressed: () { + if(_largeQrMode) { + ShareUtil.share( + text: widget.addressListViewModel.uri.toString(), + context: context, + ); + } else { + if(widget.addressListViewModel.hasAddressRotation) { + widget.addressListViewModel.rotateAddress(); + } + } + }):SizedBox.shrink(), + ), + ), ), Expanded( child: Column( diff --git a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart index f097e5d12..b69558bff 100644 --- a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart +++ b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart @@ -614,11 +614,20 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo void setAddress(WalletAddressListItem address) => wallet.walletAddresses.address = address.address; + @observable + bool isRotatingAddress = false; + @action Future rotateAddress() async { - await createNewAddress(wallet, ""); - if (isElectrumWallet) { + if(isRotatingAddress) { + return; + } + try { + isRotatingAddress = true; + await createNewAddress(wallet, ""); wallet.walletAddresses.address = addressList.whereType().last.address; + } finally { + isRotatingAddress = false; } } From eaa8338a52f693e438dc46a7541c2b205c634c28 Mon Sep 17 00:00:00 2001 From: malik1004x Date: Thu, 25 Jun 2026 12:05:05 +0200 Subject: [PATCH 5/5] prevent trade.from saving as null + fallback when it does (#3346) --- .../near_Intents_exchange_provider.dart | 4 +-- .../assets_history/history_section.dart | 3 -- .../assets_history/history_trade_tile.dart | 29 ++++++++++++------- lib/src/screens/dev/moneroc_cache_debug.dart | 2 ++ .../exchange/exchange_view_model.dart | 6 ++++ 5 files changed, 28 insertions(+), 16 deletions(-) diff --git a/lib/exchange/provider/near_Intents_exchange_provider.dart b/lib/exchange/provider/near_Intents_exchange_provider.dart index 480fc6abe..2a6a86143 100644 --- a/lib/exchange/provider/near_Intents_exchange_provider.dart +++ b/lib/exchange/provider/near_Intents_exchange_provider.dart @@ -280,8 +280,8 @@ class NearIntentsExchangeProvider extends ExchangeProvider { final trade = Trade( id: depositAddress, // Using deposit address as trade ID - from: from, - to: to, + from: request.fromCurrency, + to: request.toCurrency, provider: description, providerName: title, state: TradeState.created, diff --git a/lib/new-ui/widgets/coins_page/assets_history/history_section.dart b/lib/new-ui/widgets/coins_page/assets_history/history_section.dart index 32d99020b..8861523f3 100644 --- a/lib/new-ui/widgets/coins_page/assets_history/history_section.dart +++ b/lib/new-ui/widgets/coins_page/assets_history/history_section.dart @@ -101,9 +101,6 @@ class HistorySection extends StatelessWidget { final trade = item.trade; final tradeFrom = trade.from; final tradeTo = trade.to; - if (tradeFrom == null || tradeTo == null) { - return const SizedBox.shrink(); - } return GestureDetector( onTap: () => Navigator.of(context) diff --git a/lib/new-ui/widgets/coins_page/assets_history/history_trade_tile.dart b/lib/new-ui/widgets/coins_page/assets_history/history_trade_tile.dart index 3e859803d..f762a3230 100644 --- a/lib/new-ui/widgets/coins_page/assets_history/history_trade_tile.dart +++ b/lib/new-ui/widgets/coins_page/assets_history/history_trade_tile.dart @@ -15,13 +15,13 @@ class HistoryTradeTile extends StatelessWidget { required this.roundedTop, required this.roundedBottom, required this.bottomSeparator, - required this.from, - required this.to, + this.from, + this.to, required this.swapState, required this.provider}); - final CryptoCurrency from; - final CryptoCurrency to; + final CryptoCurrency? from; + final CryptoCurrency? to; final ExchangeProviderDescription provider; final String date; final String amount; @@ -32,6 +32,11 @@ class HistoryTradeTile extends StatelessWidget { final TradeState swapState; Widget _getLeadingStack(BuildContext context) { + if (from == null || to == null) { + return SizedBox(width: 50, height: 50); + } + + double currencyIconSize = 22.0; return SizedBox( @@ -40,7 +45,7 @@ class HistoryTradeTile extends StatelessWidget { child: Stack( children: [ CakeImageWidget( - imageUrl: _getIconPath(from), width: currencyIconSize, height: currencyIconSize), + imageUrl: _getIconPath(from!), width: currencyIconSize, height: currencyIconSize), Positioned( top: currencyIconSize / 2, left: currencyIconSize / 2, @@ -50,7 +55,7 @@ class HistoryTradeTile extends StatelessWidget { Border.all(width: 2, color: Theme.of(context).colorScheme.surfaceContainer), shape: BoxShape.circle), child: CakeImageWidget( - imageUrl: _getIconPath(to), + imageUrl: _getIconPath(to!), width: currencyIconSize, height: currencyIconSize, ), @@ -85,8 +90,8 @@ class HistoryTradeTile extends StatelessWidget { style: TextStyle( color: Theme.of(context).colorScheme.onSurfaceVariant, fontWeight: FontWeight.w500)), - Text(from.title, style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant)), - if (fromChainIcon.isNotEmpty) + if(from?.title != null) Text(from!.title, style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant)), + if (fromChainIcon?.isNotEmpty ?? false) CakeImageWidget( imageUrl: fromChainIcon, width: 12, @@ -106,10 +111,11 @@ class HistoryTradeTile extends StatelessWidget { receiveAmount.withMaxDecimals(8), style: TextStyle(fontWeight: FontWeight.w500), ), + if(to!=null) Text( - to.title, + to!.title, ), - if (toChainIcon.isNotEmpty) CakeImageWidget(imageUrl: toChainIcon, width: 12, height: 12) + if (toChainIcon?.isNotEmpty ?? false) CakeImageWidget(imageUrl: toChainIcon, width: 12, height: 12) ], ), leadingIcon: _getLeadingStack(context), @@ -137,7 +143,8 @@ class HistoryTradeTile extends StatelessWidget { return ""; } - String _getChainIcon(CryptoCurrency currency) { + String? _getChainIcon(CryptoCurrency? currency) { + if(currency == null) return null; try { if (currency.title.isNotEmpty) { final parsedCurrency = CryptoCurrency.safeParseCurrencyFromString(currency.title, tag: currency.tag); diff --git a/lib/src/screens/dev/moneroc_cache_debug.dart b/lib/src/screens/dev/moneroc_cache_debug.dart index 6c0b20827..0e6b5c618 100644 --- a/lib/src/screens/dev/moneroc_cache_debug.dart +++ b/lib/src/screens/dev/moneroc_cache_debug.dart @@ -9,6 +9,7 @@ import 'package:cw_core/root_dir.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; import 'package:path/path.dart' as path; class DevMoneroWalletCacheDebugPage extends StatelessWidget { @@ -263,6 +264,7 @@ class _JsonExplorerState extends State { ), ) : ListView.builder( + controller: ModalScrollController.of(context), itemCount: _filteredItems.length, itemBuilder: (context, index) { final item = _filteredItems[index]; diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index 5fb896f53..792b23f12 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -1242,6 +1242,12 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with trade.walletId = wallet.id; trade.chainId = wallet.chainId; trade.fromWalletAddress = wallet.walletAddresses.address; + if(trade.from == null) { + trade.from = depositCurrency; + } + if(trade.to == null) { + trade.to = receiveCurrency; + } final canCreateTrade = await isCanCreateTrade(trade); if (!canCreateTrade.result) {