diff --git a/cw_bitcoin/lib/bitcoin_wallet.dart b/cw_bitcoin/lib/bitcoin_wallet.dart index 51f48571d..a0d88ce9a 100644 --- a/cw_bitcoin/lib/bitcoin_wallet.dart +++ b/cw_bitcoin/lib/bitcoin_wallet.dart @@ -345,12 +345,16 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { return balance; } + try { final lBalance = await lightningWallet!.getBalance(); this.balance[CryptoCurrency.btcln] = ElectrumBalance( confirmed: lBalance, unconfirmed: Money.zero(CryptoCurrency.btcln), frozen: Money.zero(CryptoCurrency.btcln)); + } catch (e) { + printV("Error fetching lightning balance: $e"); + } return ElectrumBalance( confirmed: balance.confirmed, diff --git a/lib/exchange/provider/near_Intents_exchange_provider.dart b/lib/exchange/provider/near_Intents_exchange_provider.dart index 2a6a86143..2ac942def 100644 --- a/lib/exchange/provider/near_Intents_exchange_provider.dart +++ b/lib/exchange/provider/near_Intents_exchange_provider.dart @@ -575,10 +575,17 @@ class NearIntentsExchangeProvider extends ExchangeProvider { final token = supported.firstWhereOrNull((t) => t.assetId == assetId); if (token == null) return null; - final title = token.symbol; + + final title = token.symbol.toUpperCase() + .replaceAll(RegExp(r'\s*\([^)]*\)'), ''); + final normalizedNetwork = _normalizeNearBlockchainToTag(token.blockchain); - final tag = - normalizedNetwork == title.toUpperCase() ? null : normalizedNetwork; + + final isNativeAsset = assetId.contains(':native:coin'); + + final tag = isNativeAsset || normalizedNetwork == title + ? null + : normalizedNetwork; return (title, tag); } diff --git a/lib/view_model/exchange/exchange_trade_view_model.dart b/lib/view_model/exchange/exchange_trade_view_model.dart index 2579b4644..154c1ab96 100644 --- a/lib/view_model/exchange/exchange_trade_view_model.dart +++ b/lib/view_model/exchange/exchange_trade_view_model.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:cake_wallet/core/amount_parsing_proxy.dart'; +import 'package:cake_wallet/core/execution_state.dart'; import 'package:cake_wallet/entities/calculate_fiat_amount.dart'; import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/exchange/exchange_provider_description.dart'; @@ -24,6 +25,7 @@ import 'package:cake_wallet/reactions/wallet_connect.dart'; import 'package:cake_wallet/src/screens/exchange_trade/exchange_trade_item.dart'; import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart'; import 'package:cake_wallet/store/dashboard/trades_store.dart'; +import 'package:cake_wallet/utils/exchange_provider_logger.dart'; import 'package:cake_wallet/utils/qr_util.dart'; import 'package:cake_wallet/utils/token_utilities.dart'; import 'package:cake_wallet/view_model/send/fees_view_model.dart'; @@ -48,7 +50,6 @@ abstract class ExchangeTradeViewModelBase with Store { required this.feesViewModel, required this.fiatConversionStore, }) : trade = tradesStore.trade!, - isSendable = _checkIfCanSend(tradesStore, wallet), isSwapsXYZCanSendFromExternal = _checkIfSwapsXYZCanSendFromExternal(tradesStore.trade!, wallet), items = ObservableList() { setUpOutput(); @@ -115,12 +116,10 @@ abstract class ExchangeTradeViewModelBase with Store { @observable Trade trade; - @observable - bool isSendable; - - bool isSwapsXYZCanSendFromExternal; + bool get isSendable => checkIfCanSend(trade, wallet) == null; + /// Providers that should hide the "send from external" button static const List _providersThatHideExternalSend = [ JupiterExchangeProvider, @@ -212,7 +211,13 @@ abstract class ExchangeTradeViewModelBase with Store { @action Future confirmSending() async { - if (!isSendable) return; + final canSendError = checkIfCanSend(trade, wallet); + + if (canSendError != null) { + _logCanSendError(trade, wallet, canSendError); + sendViewModel.state = FailureState(canSendError); + return; + } final selected = trade.from; if (selected == null) { @@ -348,48 +353,56 @@ abstract class ExchangeTradeViewModelBase with Store { ); } - static bool _checkIfCanSend(TradesStore tradesStore, WalletBase wallet) { - final trade = tradesStore.trade!; + String? checkIfCanSend(Trade? trade, WalletBase wallet) { + if (trade == null) return 'Trade is null'; + final tradeFrom = trade.from; + if (tradeFrom == null) return 'Trade from currency is null'; - bool _sameCurrency(CryptoCurrency? a, CryptoCurrency? b) => - a != null && b != null && a.titleAndTagEqual(b); + bool _sameCurrency(CryptoCurrency a, CryptoCurrency b) => a.titleAndTagEqual(b); - bool _isEthToken() => - wallet.currency == CryptoCurrency.eth && tradeFrom?.tag == CryptoCurrency.eth.title; + bool _isTokenBelongingToWallet(CryptoCurrency cur) { + final chainTag = cur.tag ?? cur.title; + return wallet.currency == cur && + (tradeFrom.tag?.toUpperCase() == chainTag.toUpperCase() || + tradeFrom.title.toUpperCase() == chainTag.toUpperCase()); + } - bool _isPolygonToken() => - wallet.currency == CryptoCurrency.maticpoly && - tradeFrom?.tag == CryptoCurrency.maticpoly.tag; - - bool _isBaseToken() => - wallet.currency == CryptoCurrency.baseEth && tradeFrom?.tag == CryptoCurrency.baseEth.tag; - - bool _isArbitrumToken() => - wallet.currency == CryptoCurrency.arbEth && - (tradeFrom?.tag == CryptoCurrency.arbEth.tag || - tradeFrom?.title == CryptoCurrency.arbEth.tag); // This is to handle the CryptoCurrency.arb that doesn't have a tag but fully belongs to the Arbitrum chain - - bool _isTronToken() => - wallet.currency == CryptoCurrency.trx && tradeFrom?.tag == CryptoCurrency.trx.title; - - bool _isSplToken() => - wallet.currency == CryptoCurrency.sol && tradeFrom?.tag == CryptoCurrency.sol.title; - - bool _isBscToken() => - wallet.currency == CryptoCurrency.bnb && tradeFrom?.tag == CryptoCurrency.bnb.tag; - - return _sameCurrency(tradeFrom, wallet.currency) || + final canSend = _sameCurrency(tradeFrom, wallet.currency) || (_sameCurrency(tradeFrom, CryptoCurrency.btcln) && wallet.currency == CryptoCurrency.btc) || - tradesStore.trade!.provider == ExchangeProviderDescription.xmrto || - _isEthToken() || - _isPolygonToken() || - _isSplToken() || - _isTronToken() || - _isBaseToken() || - _isArbitrumToken() || - _isBscToken(); + trade.provider == ExchangeProviderDescription.xmrto || + _isTokenBelongingToWallet(CryptoCurrency.eth) || + _isTokenBelongingToWallet(CryptoCurrency.maticpoly) || + _isTokenBelongingToWallet(CryptoCurrency.baseEth) || + _isTokenBelongingToWallet(CryptoCurrency.arbEth) || + _isTokenBelongingToWallet(CryptoCurrency.trx) || + _isTokenBelongingToWallet(CryptoCurrency.sol) || + _isTokenBelongingToWallet(CryptoCurrency.bnb); + + if (!canSend) { + return 'Wallet currency ${wallet.currency.title} does not match trade from currency ${tradeFrom.title} or is not a supported token for this wallet.'; + } + + return null; + } + + void _logCanSendError(Trade? trade, WalletBase wallet, String error) { + ExchangeProviderLogger.logError( + provider: trade?.provider, + function: '_checkIfCanSend', + error: error, + requestData: { + 'tradeId': trade?.id, + 'tradeFrom': trade?.from?.title, + 'tradeFromTag': trade?.from?.tag, + 'tradeTo': trade?.to?.title, + 'tradeToTag': trade?.to?.tag, + 'walletName': wallet.name, + 'walletCurrency': wallet.currency.title, + 'walletCurrencyTag': wallet.currency.tag, + }, + ); } static bool _checkIfSwapsXYZCanSendFromExternal(Trade trade, WalletBase wallet) {