6.1.0 fixes (#3190)

* - Fix swap state not maintained (fixed rate can be on or off at the same time) - Fix Pay Anything putting contract address - Pick the token of the URI * fix incorrect function calls [skip ci]

Omar Hatem committed Apr 18, 2026 at 00:05 UTC 314eb36dd5dd8363a4af87de3bc70c32f4f43e8c
8 files changed +49 -14
cw_evm/lib/clients/evm_chain_client.dart
+3
@@ -535,6 +535,9 @@ class EVMChainClient {
535 } on RangeError catch (_) {
536 throw Exception('Invalid token contract for this network.');
537 } catch (e) {
538 + if (e.toString().contains("hostUnreachable")) {
539 + return EVMChainERC20Balance(BigInt.zero);
540 + }
541 throw Exception('Could not fetch balances: ${e.toString()}');
542 }
543 }
lib/exchange/provider/swaptrade_exchange_provider.dart
+3
@@ -94,6 +94,9 @@ class SwapTradeExchangeProvider extends ExchangeProvider {
94 }) async {
95 try {
96 if (amount == 0) return 0.0;
97 + if (isFixedRateMode && !supportsFixedRate) {
98 + return 0.0;
99 + }
100 if(from == CryptoCurrency.btcln || to == CryptoCurrency.btcln) return 0;
101
102 final params = <String, dynamic>{};
lib/new-ui/pages/swap_page.dart
+2 -1
@@ -378,11 +378,12 @@ class _NewSwapPageState extends State<NewSwapPage> {
378
379 @override
380 void dispose() {
381 - super.dispose();
381 _depositAmountFocus.dispose();
382 _depositAddressFocus.dispose();
383 _receiveAmountFocus.dispose();
384 _receiveAddressFocus.dispose();
385 + widget.exchangeViewModel.dispose();
386 + super.dispose();
387 }
388
389 void _onCurrencyChange(CryptoCurrency currency, ExchangeViewModel exchangeViewModel,
lib/new-ui/widgets/send_page/send_address_input.dart
+5 -1
@@ -169,7 +169,11 @@ class _NewSendAddressInputState extends State<NewSendAddressInput> {
169
170 try {
171 final uri = Uri.parse(code);
172 - widget.addressController.text = uri.path;
172 + // probably should remove this and let the `onURIScanned` handle it, but for now,
173 + // will fix that it takes the token contract address
174 + if (!uri.path.contains("/transfer")) {
175 + widget.addressController.text = uri.path;
176 + }
177 widget.onURIScanned?.call(uri);
178 } catch (_) {
179 widget.addressController.text = code;
lib/src/screens/settings/connection_sync_page.dart
+2 -2
@@ -100,7 +100,7 @@ class ConnectionSyncPage extends BasePage {
100 label: S.of(context).arbiscan_history,
101 value: _connectionSyncViewModel.useArbiScan,
102 onChanged: (val) {
103 - _connectionSyncViewModel.setUsePolygonScan(val);
103 + _connectionSyncViewModel.setUseArbiScan(val);
104 }),
105 if (_connectionSyncViewModel.canUseBscScan)
106 ListItemToggle(
@@ -116,7 +116,7 @@ class ConnectionSyncPage extends BasePage {
116 label: S.of(context).trongrid_history,
117 value: _connectionSyncViewModel.useTronGrid,
118 onChanged: (val) {
119 - _connectionSyncViewModel.setUsePolygonScan(val);
119 + _connectionSyncViewModel.setUseTronGrid(val);
120 }),
121 if (_connectionSyncViewModel.canUseMempoolFeeAPI)
122 ListItemToggle(
lib/src/widgets/bottom_sheet/token_selection_bottom_sheet.dart
+10 -2
@@ -15,6 +15,9 @@ import 'package:cake_wallet/wallet_types.g.dart';
15 import 'package:cw_core/crypto_currency.dart';
16 import 'package:cw_core/currency.dart';
17 import 'package:cw_core/currency_for_wallet_type.dart';
18 +import 'package:cw_core/erc20_token.dart';
19 +import 'package:cw_core/spl_token.dart';
20 +import 'package:cw_core/tron_token.dart';
21 import 'package:cw_core/utils/print_verbose.dart';
22 import 'package:cw_core/wallet_type.dart';
23 import 'package:flutter/material.dart';
@@ -78,7 +81,8 @@ class _TokenSelectionContentState extends State<_TokenSelectionContent> {
81 _autoSelectToken();
82 }
83
81 - bool get _isNetworkSelectable => widget.fixedNetwork == null || isEVMCompatibleChain(widget.fixedNetwork!);
84 + bool get _isNetworkSelectable =>
85 + widget.fixedNetwork == null || isEVMCompatibleChain(widget.fixedNetwork!);
86
87 Future<void> _autoSelectToken() async {
88 if (selectedNetwork == null) return;
@@ -102,7 +106,11 @@ class _TokenSelectionContentState extends State<_TokenSelectionContent> {
106 }
107
108 setState(() {
105 - selectedToken = tokens.first;
109 + selectedToken = tokens.firstWhere((e) {
110 + return (e is Erc20Token && e.contractAddress == widget.paymentRequest.contractAddress) ||
111 + (e is SPLToken && e.mintAddress == widget.paymentRequest.contractAddress) ||
112 + (e is TronToken && e.contractAddress == widget.paymentRequest.contractAddress);
113 + }, orElse: () => tokens.first);
114 isLoadingTokens = false;
115 });
116 } catch (e) {
lib/utils/exception_handler.dart
+1
@@ -304,6 +304,7 @@ class ExceptionHandler {
304 "Image upload failed due to loss of GPU access",
305 "transport error",
306 "SdkError.sparkError(field0: Operator RPC error: Connection error: status: Unavailable, message: \"dns error\", details: []",
307 + "the timeout of the request was reached",
308
309 "support for coin removed, your seedphrase:"
310 ];
lib/view_model/exchange/exchange_view_model.dart
+23 -8
@@ -82,6 +82,16 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
82 // depositCurrency = wallet.currency;
83 }
84
85 + final List<ReactionDisposer> _disposers = [];
86 +
87 + void dispose() {
88 + bestRateSync.cancel();
89 + for (final disposer in _disposers) {
90 + disposer();
91 + }
92 + _disposers.clear();
93 + }
94 +
95 ExchangeViewModelBase(
96 this._appStore,
97 this.trades,
@@ -166,11 +176,11 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
176 depositAddress =
177 useSameWalletAddress(depositCurrency) ? wallet.walletAddresses.addressForExchange : '';
178
169 - reaction((_) => receiveAddress, (_) {
179 + _disposers.add(reaction((_) => receiveAddress, (_) {
180 if(!(tradeState is TradeIsCreatedSuccessfully)) {
181 receiveAddressDisplayName = null;
182 }
173 - });
183 + }));
184
185 provider = providerList.firstOrNull;
186 final initialProvider = provider;
@@ -184,9 +194,9 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
194
195 // providerDisplay is read by ui to display auto-selected provider.
196 // it's on a delay so it doesn't flicker.
187 - reaction((_)=>bestRateProvider,(val) {
197 + _disposers.add(reaction((_) => bestRateProvider, (val) {
198 providerDisplay = val;
189 - },delay: 300);
199 + }, delay: 300));
200
201 receiveCurrencies = CryptoCurrency.all
202 .where((cryptoCurrency) => !excludeReceiveCurrencies.contains(cryptoCurrency))
@@ -202,19 +212,19 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
212 _injectUserTronTokensIntoCurrencyLists();
213 _defineIsReceiveAmountEditable();
214 loadLimits();
205 - reaction((_) => isFixedRateMode, (Object _) {
215 + _disposers.add(reaction((_) => isFixedRateMode, (Object _) {
216 bestRateProvider = null;
217 bestRate = 0.0;
218 loadLimits();
209 - });
219 + }));
220
211 - reaction((_) => forceDecentralizedExchanges, (val) {
221 + _disposers.add(reaction((_) => forceDecentralizedExchanges, (val) {
222 if (val && (bestRateProvider?.description.isCentralized ?? false)) {
223 bestRateProvider = null;
224 bestRate = 0.0;
225 loadLimits();
226 }
217 - });
227 + }));
228
229 if (isElectrumWallet) {
230 bitcoin!.updateFeeRates(wallet);
@@ -1071,6 +1081,11 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
1081
1082 printV('createTrade: trying provider=${provider.title}');
1083
1084 + // should not happen but just as an extra check
1085 + if (isFixedRateMode && provider.supportsFixedRate == false) {
1086 + continue;
1087 + }
1088 +
1089 // Skip Swaps.xyz when sending from external
1090 if (isSendFromExternal &&
1091 provider.description == ExchangeProviderDescription.swapsXyz) {