diff --git a/lib/new-ui/pages/swap_page.dart b/lib/new-ui/pages/swap_page.dart index a0fdd685b..0c85bdc76 100644 --- a/lib/new-ui/pages/swap_page.dart +++ b/lib/new-ui/pages/swap_page.dart @@ -401,8 +401,6 @@ class _NewSwapPageState extends State { address: isCurrentTypeWallet ? exchangeViewModel.wallet.walletAddresses.addressForExchange : ''); - - key.currentState!.changeAmount(amount: ''); } void _onWalletNameChange(ExchangeViewModel exchangeViewModel, CryptoCurrency currency, diff --git a/lib/src/screens/exchange/exchange_page.dart b/lib/src/screens/exchange/exchange_page.dart index dee12e1b5..d60eb08ca 100644 --- a/lib/src/screens/exchange/exchange_page.dart +++ b/lib/src/screens/exchange/exchange_page.dart @@ -636,8 +636,6 @@ class ExchangePage extends BasePage { key.currentState!.changeAddress( address: isCurrentTypeWallet ? exchangeViewModel.wallet.walletAddresses.addressForExchange : ''); - - key.currentState!.changeAmount(amount: ''); } void _onWalletNameChange(ExchangeViewModel exchangeViewModel, CryptoCurrency currency, diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index dd34f51b9..6ae085510 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -48,6 +48,7 @@ import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart'; import 'package:cake_wallet/store/dashboard/trades_store.dart'; import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/templates/exchange_template_store.dart'; +import 'package:cake_wallet/evm/evm.dart'; import 'package:cake_wallet/reactions/wallet_connect.dart'; import 'package:cake_wallet/utils/feature_flag.dart'; import 'package:cake_wallet/utils/token_utilities.dart'; @@ -250,6 +251,20 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with } return true; }); + } else if (isEVMCompatibleChain(wallet.type)) { + final currency = depositCurrency; + final balanceCurrency = wallet.balance.keys.firstWhereOrNull( + (c) => + c.title == depositCurrency.title && + (c.tag == depositCurrency.tag || c.tag == depositCurrency.title), + ); + final balanceForCurrency = + balanceCurrency != null ? wallet.balance[balanceCurrency] : null; + if (depositCurrency == currency && balanceForCurrency != null) { + depositAvailableAmount = _appStore.amountParsingProxy + .getDisplayCryptoStringFromBigInt( + balanceForCurrency.fullAvailableBalance, balanceCurrency!); + } } else { final currency = depositCurrency; final amount = _appStore.amountParsingProxy.getDisplayCryptoString( @@ -478,9 +493,20 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with @computed String? get balanceDisplay { - final bal = wallet.balance[depositCurrency]?.fullAvailableBalance; - if(bal == null) return null; - return amountParsingProxy.getDisplayCryptoStringFromBigInt(bal, depositCurrency); + CryptoCurrency? balanceCurrency; + if (isEVMCompatibleChain(wallet.type)) { + balanceCurrency = wallet.balance.keys.firstWhereOrNull( + (c) => + c.title == depositCurrency.title && + (c.tag == depositCurrency.tag || c.tag == depositCurrency.title), + ); + } else { + balanceCurrency = depositCurrency; + } + final bal = balanceCurrency != null ? wallet.balance[balanceCurrency]?.fullAvailableBalance : null; + if (bal == null) return null; + return amountParsingProxy.getDisplayCryptoStringFromBigInt( + bal, balanceCurrency ?? depositCurrency); } //* Still open to further optimize these checks @@ -515,15 +541,23 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with return priority; } - bool get hasAllAmount => - [ - WalletType.monero, - WalletType.bitcoin, - WalletType.litecoin, - WalletType.bitcoinCash, - WalletType.dogecoin, - ].contains(wallet.type) && - (depositCurrency == wallet.currency); + bool get hasAllAmount { + if ([ + WalletType.monero, + WalletType.bitcoin, + WalletType.litecoin, + WalletType.bitcoinCash, + WalletType.dogecoin, + ].contains(wallet.type)) return (depositCurrency == wallet.currency); + + if (!isEVMCompatibleChain(wallet.type)) return false; + + if (depositCurrency == wallet.currency) return true; + + return wallet.balance.keys.any((c) => + c.title == depositCurrency.title && + (c.tag == depositCurrency.tag || c.tag == depositCurrency.title)); + } bool get isMoneroWallet => wallet.type == WalletType.monero; @@ -706,26 +740,38 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with @action void changeDepositCurrency({required CryptoCurrency currency}) { + final previousCurrency = depositCurrency; + final wasSendAllEnabled = isSendAllEnabled; + depositCurrency = currency; isFixedRateMode = false; - _onPairChange(); isDepositAddressEnabled = !useSameWalletAddress(depositCurrency); + + if (previousCurrency != currency) { + _onPairChange(clearBoth: wasSendAllEnabled); + } fetchFiatPrice(currency); updateDepositAvailableAmount(); } @action void changeReceiveCurrency({required CryptoCurrency currency}) { + final previousCurrency = receiveCurrency; + if (!(currency.tag == receiveCurrency.tag || currency.tag == receiveCurrency.title || currency.title == receiveCurrency.tag || currency == receiveCurrency)) { receiveAddress = ""; } + receiveCurrency = currency; isFixedRateMode = false; - _onPairChange(); isDepositAddressEnabled = !useSameWalletAddress(depositCurrency); + + if (previousCurrency != currency) { + _onPairChange(); + } fetchFiatPrice(currency); } @@ -836,6 +882,11 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with isReceiveAmount: isFixedRateMode); } + bool _excludeProviderForSwapAll(ExchangeProvider provider) => + isSendAllEnabled && + (provider.description == ExchangeProviderDescription.swapsXyz || + provider.description == ExchangeProviderDescription.nearIntents); + Future calculateBestRate() async { if (depositCurrency == receiveCurrency) { bestRate = 0.0; @@ -846,6 +897,8 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with initialAmountByAssets(isFixedRateMode ? receiveCurrency : depositCurrency); final validProvidersForAmount = _tradeAvailableProviders.where((provider) { + if (_excludeProviderForSwapAll(provider)) return false; + final limits = _providerLimits[provider]; if (limits == null) return false; @@ -962,7 +1015,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with if (lowestMin != double.maxFinite) { limits = Limits(min: lowestMin, max: highestMax); - limitsState = LimitsLoadedSuccessfully(limits: limits); } else { limitsState = LimitsLoadedFailure(error: 'Limits loading failed'); @@ -1081,6 +1133,10 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with printV('createTrade: trying provider=${provider.title}'); + if (_excludeProviderForSwapAll(provider)) { + printV('Skipping Swaps.xyz or Near Intents for swap all'); + continue; + } // should not happen but just as an extra check if (isFixedRateMode && provider.supportsFixedRate == false) { continue; @@ -1254,6 +1310,56 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with final amount = await unspentCoinsListViewModel.getSendingBalance(UnspentCoinType.any); changeDepositAmount(amount: wallet.currency.formatAmount(BigInt.from(amount)), isCanonical: true); + } else if (isEVMCompatibleChain(wallet.type)) { + final balanceCurrency = wallet.balance.keys.firstWhereOrNull( + (currency) => + currency.title == depositCurrency.title && + (currency.tag == depositCurrency.tag || currency.tag == depositCurrency.title), + ); + + final balanceForCurrency = balanceCurrency != null ? wallet.balance[balanceCurrency] : null; + if (balanceForCurrency == null) { + changeDepositAmount(amount: wallet.currency.formatAmount(BigInt.zero), isCanonical: true); + return; + } + + final balanceAmount = _appStore.amountParsingProxy.getDisplayCryptoStringFromBigInt(balanceForCurrency.fullAvailableBalance, balanceCurrency!); + final balanceDouble = double.tryParse(balanceAmount.replaceAll(',', '.')) ?? 0.0; + if (balanceDouble <= 0) { + changeDepositAmount(amount: wallet.currency.formatAmount(BigInt.zero), isCanonical: true); + return; + } + + final isNative = depositCurrency == wallet.currency; + + if (!isNative) { + changeDepositAmount(amount: balanceAmount, isCanonical: true); + return; + } + + try { + final priority = _settingsStore.getPriority(wallet.type, chainId: wallet.chainId); + await wallet.updateEstimatedFeesParams(priority); + + String? feeString; + if (isEVMCompatibleChain(wallet.type)) { + feeString = evm!.getEVMNativeEstimatedFee(wallet); + } + + if (feeString == null || feeString.isEmpty) { + changeDepositAmount(amount: balanceAmount, isCanonical: true); + return; + } + + final balanceWei = balanceForCurrency.fullAvailableBalance; + final feeWei = BigInt.parse(feeString); + final amountAfterFeeWei = balanceWei > feeWei ? balanceWei - feeWei : BigInt.zero; + changeDepositAmount( + amount: wallet.currency.formatAmount(amountAfterFeeWei), isCanonical: true); + } catch (e) { + printV('Error calculating send all for EVM: $e'); + changeDepositAmount(amount: balanceAmount, isCanonical: true); + } } } @@ -1293,13 +1399,26 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with void removeTemplate({required ExchangeTemplate template}) => _exchangeTemplateStore.remove(template: template); - void _onPairChange() { - _depositAmount = ''; - _receiveAmount = ''; + void _onPairChange({bool clearBoth = false}) { + if (clearBoth) { + _depositAmount = ''; + _receiveAmount = ''; + if (!hasAllAmount) isSendAllEnabled = false; + } else { + if (isFixedRateMode) { + _depositAmount = ''; + } else { + _receiveAmount = ''; + } + } bestRate = 0.0; bestRateProvider = null; _sortedAvailableProviders.clear(); - loadLimits(); + loadLimits().then((_) { + if (clearBoth && hasAllAmount) { + calculateDepositAllAmount(); + } + }); _setAvailableProviders(); }