diff --git a/lib/exchange/provider/trocador_exchange_provider.dart b/lib/exchange/provider/trocador_exchange_provider.dart index d8f5f07d3..fc80d79de 100644 --- a/lib/exchange/provider/trocador_exchange_provider.dart +++ b/lib/exchange/provider/trocador_exchange_provider.dart @@ -8,12 +8,14 @@ import 'package:cake_wallet/exchange/trade.dart'; import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/trade_state.dart'; import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart'; +import 'package:cake_wallet/lightning/lightning.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:http/http.dart'; class TrocadorExchangeProvider extends ExchangeProvider { TrocadorExchangeProvider({this.useTorOnly = false, this.providerStates = const {}}) - : _lastUsedRateId = '', _provider = [], + : _lastUsedRateId = '', + _provider = [], super(pairList: supportedPairs(_notSupported)); bool useTorOnly; @@ -24,7 +26,7 @@ class TrocadorExchangeProvider extends ExchangeProvider { 'StealthEx', 'Simpleswap', 'Swapuz' - 'ChangeNow', + 'ChangeNow', 'Changehero', 'FixedFloat', 'LetsExchange', @@ -95,6 +97,14 @@ class TrocadorExchangeProvider extends ExchangeProvider { final coinJson = responseJSON.first as Map; + // trocador treats btcln as just bitcoin amounts: + if (from == CryptoCurrency.btcln) { + return Limits( + min: lightning!.bitcoinDoubleToLightningDouble(amount: (coinJson['minimum'] as double)), + max: lightning!.bitcoinDoubleToLightningDouble(amount: (coinJson['maximum'] as double)), + ); + } + return Limits( min: coinJson['minimum'] as double, max: coinJson['maximum'] as double, @@ -111,14 +121,20 @@ class TrocadorExchangeProvider extends ExchangeProvider { try { if (amount == 0) return 0.0; + double amt = amount; + + if (from == CryptoCurrency.btcln) { + amt = lightning!.lightningDoubleToBitcoinDouble(amount: amount); + } + final params = { 'api_key': apiKey, 'ticker_from': _normalizeCurrency(from), 'ticker_to': _normalizeCurrency(to), 'network_from': _networkFor(from), 'network_to': _networkFor(to), - if (!isFixedRateMode) 'amount_from': amount.toString(), - if (isFixedRateMode) 'amount_to': amount.toString(), + if (!isFixedRateMode) 'amount_from': amt.toString(), + if (isFixedRateMode) 'amount_to': amt.toString(), 'payment': isFixedRateMode ? 'True' : 'False', 'min_kycrating': 'C', 'markup': markup, @@ -145,6 +161,14 @@ class TrocadorExchangeProvider extends ExchangeProvider { @override Future createTrade({required TradeRequest request, required bool isFixedRateMode}) async { + double fromAmt = double.parse(request.fromAmount); + double toAmt = double.parse(request.toAmount); + if (request.fromCurrency == CryptoCurrency.btcln) { + fromAmt = lightning!.lightningDoubleToBitcoinDouble(amount: fromAmt); + } + if (request.toCurrency == CryptoCurrency.btcln) { + toAmt = lightning!.lightningDoubleToBitcoinDouble(amount: toAmt); + } final params = { 'api_key': apiKey, @@ -155,24 +179,28 @@ class TrocadorExchangeProvider extends ExchangeProvider { 'payment': isFixedRateMode ? 'True' : 'False', 'min_kycrating': 'C', 'markup': markup, - if (!isFixedRateMode) 'amount_from': request.fromAmount, - if (isFixedRateMode) 'amount_to': request.toAmount, + if (!isFixedRateMode) 'amount_from': fromAmt.toString(), + if (isFixedRateMode) 'amount_to': toAmt.toString(), 'address': request.toAddress, 'refund': request.refundAddress }; + double amt = double.tryParse(request.toAmount) ?? 0; + if (request.fromCurrency == CryptoCurrency.btcln) { + amt = lightning!.lightningDoubleToBitcoinDouble(amount: amt); + } + if (isFixedRateMode) { await fetchRate( from: request.fromCurrency, to: request.toCurrency, - amount: double.tryParse(request.toAmount) ?? 0, + amount: amt, isFixedRateMode: true, isReceiveAmount: true, ); params['id'] = _lastUsedRateId; } - String firstAvailableProvider = ''; for (var provider in _provider) { @@ -212,20 +240,29 @@ class TrocadorExchangeProvider extends ExchangeProvider { final providerId = responseJSON['id_provider'] as String; final providerName = responseJSON['provider'] as String; + String? responseAmount = responseJSON['amount_from']?.toString(); + if (request.fromCurrency == CryptoCurrency.btcln && responseAmount != null) { + responseAmount = lightning! + .bitcoinDoubleToLightningDouble(amount: double.parse(responseAmount)) + .toString(); + } + responseAmount ??= fromAmt.toString(); + return Trade( - id: id, - from: request.fromCurrency, - to: request.toCurrency, - provider: description, - inputAddress: inputAddress, - refundAddress: refundAddress, - state: TradeState.deserialize(raw: status), - password: password, - providerId: providerId, - providerName: providerName, - createdAt: DateTime.tryParse(date)?.toLocal(), - amount: responseJSON['amount_from']?.toString() ?? request.fromAmount, - payoutAddress: payoutAddress); + id: id, + from: request.fromCurrency, + to: request.toCurrency, + provider: description, + inputAddress: inputAddress, + refundAddress: refundAddress, + state: TradeState.deserialize(raw: status), + password: password, + providerId: providerId, + providerName: providerName, + createdAt: DateTime.tryParse(date)?.toLocal(), + amount: responseAmount, + payoutAddress: payoutAddress, + ); } @override diff --git a/lib/lightning/cw_lightning.dart b/lib/lightning/cw_lightning.dart index 5cb5e71f6..491f54395 100644 --- a/lib/lightning/cw_lightning.dart +++ b/lib/lightning/cw_lightning.dart @@ -72,6 +72,7 @@ class CWLightning extends Lightning { @override ReceivePageOption getOptionOnchain() => LightningReceivePageOption.lightningOnchain; + @override String satsToLightningString(int sats) { const bitcoinAmountLength = 8; const bitcoinAmountDivider = 100000000; @@ -84,16 +85,28 @@ class CWLightning extends Lightning { return formattedAmount.substring(0, formattedAmount.length - 2); } + @override String bitcoinAmountToLightningString({required int amount}) { final bitcoinAmountFormat = NumberFormat() ..maximumFractionDigits = bitcoinAmountLength ..minimumFractionDigits = 1; - String formattedAmount = bitcoinAmountFormat - .format(cryptoAmountToDouble(amount: amount, divider: 1)); + String formattedAmount = + bitcoinAmountFormat.format(cryptoAmountToDouble(amount: amount, divider: 1)); return formattedAmount.substring(0, formattedAmount.length - 2); } + @override int bitcoinAmountToLightningAmount({required int amount}) { return amount * 100000000; } + + @override + double bitcoinDoubleToLightningDouble({required double amount}) { + return amount * 100000000; + } + + @override + double lightningDoubleToBitcoinDouble({required double amount}) { + return amount / 100000000; + } } diff --git a/lib/src/screens/send/lightning_send_page.dart b/lib/src/screens/send/lightning_send_page.dart index ad1d9da58..7485f9991 100644 --- a/lib/src/screens/send/lightning_send_page.dart +++ b/lib/src/screens/send/lightning_send_page.dart @@ -171,6 +171,7 @@ class LightningSendPage extends BasePage { onPushPasteButton: (context) async { output.resetParsedAddress(); await output.fetchParsedAddress(context); + await send(context); }, onPushAddressBookButton: (context) async { output.resetParsedAddress(); @@ -188,28 +189,11 @@ class LightningSendPage extends BasePage { bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24), bottomSection: Column( children: [ - LoadingPrimaryButton( + PrimaryButton( text: S.of(context).send, color: Theme.of(context).primaryColor, textColor: Colors.white, - isLoading: lightningViewModel.loading, - onPressed: () async { - try { - lightningViewModel.setLoading(true); - await processInput(context); - lightningViewModel.setLoading(false); - } catch (e) { - showPopUp( - context: context, - builder: (BuildContext context) { - return AlertWithOneAction( - alertTitle: S.of(context).error, - alertContent: e.toString(), - buttonText: S.of(context).ok, - buttonAction: () => Navigator.of(context).pop()); - }); - } - }, + onPressed: () => send(context), ), ], ), @@ -219,6 +203,22 @@ class LightningSendPage extends BasePage { ); } + Future send(BuildContext context) async { + try { + await processInput(context); + } catch (e) { + showPopUp( + context: context, + builder: (BuildContext context) { + return AlertWithOneAction( + alertTitle: S.of(context).error, + alertContent: e.toString(), + buttonText: S.of(context).ok, + buttonAction: () => Navigator.of(context).pop()); + }); + } + } + Future _onNavigateBack(BuildContext context) async { onClose(context); return false; diff --git a/tool/configure.dart b/tool/configure.dart index cd86ae388..f36f07c53 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -775,6 +775,8 @@ abstract class Lightning { ReceivePageOption getOptionOnchain(); String bitcoinAmountToLightningString({required int amount}); int bitcoinAmountToLightningAmount({required int amount}); + double bitcoinDoubleToLightningDouble({required double amount}); + double lightningDoubleToBitcoinDouble({required double amount}); } """;