From 89c1c352c5f5012913c87d3bf84a8ef94a21cc3f Mon Sep 17 00:00:00 2001 From: Philipp Hoenisch Date: Fri, 26 Jan 2024 09:28:18 +0100 Subject: [PATCH] chore: remove parsing lightning invocies --- CHANGELOG.md | 1 + mobile/lib/common/routes.dart | 9 - mobile/lib/features/wallet/balance_row.dart | 11 - .../features/wallet/domain/wallet_type.dart | 2 +- .../lib/features/wallet/scanner_screen.dart | 41 +- .../wallet/send/send_lightning_screen.dart | 481 ------------------ 6 files changed, 32 insertions(+), 513 deletions(-) delete mode 100644 mobile/lib/features/wallet/send/send_lightning_screen.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index d4023eaf4..ec4be9542 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] - Chore: Enforce minimum quantity to 500 on dlc channel open +- Chore(app): Remove paying lightning invoices ## [1.8.0] - 2024-01-23 diff --git a/mobile/lib/common/routes.dart b/mobile/lib/common/routes.dart index ead85505a..42403b279 100644 --- a/mobile/lib/common/routes.dart +++ b/mobile/lib/common/routes.dart @@ -4,7 +4,6 @@ import 'package:get_10101/common/settings/channel_screen.dart'; import 'package:get_10101/common/settings/delete_network_graph.dart'; import 'package:get_10101/common/status_screen.dart'; import 'package:get_10101/features/wallet/domain/destination.dart'; -import 'package:get_10101/features/wallet/send/send_lightning_screen.dart'; import 'package:get_10101/features/wallet/send/send_onchain_screen.dart'; import 'package:get_10101/features/welcome/loading_screen.dart'; import 'package:get_10101/common/scaffold_with_nav_bar.dart'; @@ -165,14 +164,6 @@ GoRouter createRoutes() { return SendOnChainScreen(destination: state.extra as OnChainAddress); }, ), - GoRoute( - path: SendLightningScreen.subRouteName, - // Use root navigator so the screen overlays the application shell - parentNavigatorKey: rootNavigatorKey, - builder: (BuildContext context, GoRouterState state) { - return SendLightningScreen(destination: state.extra as LightningInvoice); - }, - ), GoRoute( path: OnboardingScreen.subRouteName, parentNavigatorKey: rootNavigatorKey, diff --git a/mobile/lib/features/wallet/balance_row.dart b/mobile/lib/features/wallet/balance_row.dart index e5b5446d7..70f3f3350 100644 --- a/mobile/lib/features/wallet/balance_row.dart +++ b/mobile/lib/features/wallet/balance_row.dart @@ -46,17 +46,6 @@ class _BalanceRowState extends State with SingleTickerProviderStateM style: TextStyle(fontSize: 14, color: Colors.white, fontWeight: FontWeight.normal)) ]), - WalletType.stable => Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text(formatter.format(positionChangeNotifier.getStableUSDAmountInFiat()), - style: const TextStyle( - fontSize: 30, color: Colors.white, fontWeight: FontWeight.bold)), - const Text(" \$", - style: - TextStyle(fontSize: 14, color: Colors.white, fontWeight: FontWeight.normal)) - ]), }; return Center(child: amountText); diff --git a/mobile/lib/features/wallet/domain/wallet_type.dart b/mobile/lib/features/wallet/domain/wallet_type.dart index 5d01b00e8..60a7bcf3b 100644 --- a/mobile/lib/features/wallet/domain/wallet_type.dart +++ b/mobile/lib/features/wallet/domain/wallet_type.dart @@ -1 +1 @@ -enum WalletType { lightning, onChain, stable } +enum WalletType { lightning, onChain } diff --git a/mobile/lib/features/wallet/scanner_screen.dart b/mobile/lib/features/wallet/scanner_screen.dart index fc8acf4ae..e6183e564 100644 --- a/mobile/lib/features/wallet/scanner_screen.dart +++ b/mobile/lib/features/wallet/scanner_screen.dart @@ -7,7 +7,6 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get_10101/common/color.dart'; import 'package:get_10101/features/wallet/domain/destination.dart'; import 'package:get_10101/features/wallet/domain/wallet_type.dart'; -import 'package:get_10101/features/wallet/send/send_lightning_screen.dart'; import 'package:get_10101/features/wallet/send/send_onchain_screen.dart'; import 'package:get_10101/features/wallet/wallet_change_notifier.dart'; import 'package:get_10101/features/wallet/wallet_screen.dart'; @@ -117,14 +116,10 @@ class _ScannerScreenState extends State { if (_formKey.currentState!.validate()) { switch (destination!.getWalletType()) { case WalletType.lightning: - GoRouter.of(context) - .go(SendLightningScreen.route, extra: destination); + _showNoLightningDialog(context); case WalletType.onChain: GoRouter.of(context) .go(SendOnChainScreen.route, extra: destination); - case WalletType.stable: - GoRouter.of(context) - .go(SendLightningScreen.route, extra: destination); } } }); @@ -195,14 +190,10 @@ class _ScannerScreenState extends State { if (_formKey.currentState!.validate()) { switch (destination!.getWalletType()) { case WalletType.lightning: - GoRouter.of(context) - .go(SendLightningScreen.route, extra: destination); + _showNoLightningDialog(context); case WalletType.onChain: GoRouter.of(context) .go(SendOnChainScreen.route, extra: destination); - case WalletType.stable: - GoRouter.of(context) - .go(SendLightningScreen.route, extra: destination); } } }); @@ -253,3 +244,31 @@ class _ScannerScreenState extends State { super.dispose(); } } + +Future _showNoLightningDialog(BuildContext context) async { + return showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Can\'t pay invoice'), + content: const SingleChildScrollView( + child: ListBody( + children: [ + Text('For the time being we have disabled paying Lightning invoices.'), + Text('Thank you for your understanding.'), + ], + ), + ), + actions: [ + TextButton( + child: const Text('Ok'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); +} diff --git a/mobile/lib/features/wallet/send/send_lightning_screen.dart b/mobile/lib/features/wallet/send/send_lightning_screen.dart deleted file mode 100644 index 3bac20040..000000000 --- a/mobile/lib/features/wallet/send/send_lightning_screen.dart +++ /dev/null @@ -1,481 +0,0 @@ -import 'dart:math'; - -import 'package:bitcoin_icons/bitcoin_icons.dart'; -import 'package:flutter/material.dart'; -import 'package:get_10101/common/custom_app_bar.dart'; -import 'package:get_10101/common/amount_text.dart'; -import 'package:get_10101/common/application/channel_info_service.dart'; -import 'package:get_10101/common/application/switch.dart'; -import 'package:get_10101/common/color.dart'; -import 'package:get_10101/common/domain/channel.dart'; -import 'package:get_10101/common/domain/model.dart'; -import 'package:get_10101/common/scrollable_safe_area.dart'; -import 'package:get_10101/features/trade/domain/direction.dart'; -import 'package:get_10101/features/trade/domain/leverage.dart'; -import 'package:get_10101/features/trade/position_change_notifier.dart'; -import 'package:get_10101/features/trade/trade_value_change_notifier.dart'; -import 'package:get_10101/features/wallet/application/util.dart'; -import 'package:get_10101/features/wallet/application/wallet_service.dart'; -import 'package:get_10101/features/wallet/domain/destination.dart'; -import 'package:get_10101/features/wallet/domain/wallet_type.dart'; -import 'package:get_10101/features/wallet/send/confirm_payment_modal.dart'; -import 'package:get_10101/features/wallet/wallet_change_notifier.dart'; -import 'package:get_10101/features/wallet/wallet_screen.dart'; -import 'package:intl/intl.dart'; -import 'package:provider/provider.dart'; - -class SendLightningScreen extends StatefulWidget { - static const route = "${WalletScreen.route}/$subRouteName"; - static const subRouteName = "send-lightning"; - - final LightningInvoice destination; - - const SendLightningScreen({super.key, required this.destination}); - - @override - State createState() => _SendLightningScreenState(); -} - -class _SendLightningScreenState extends State { - final _satsFormKey = GlobalKey(); - final _usdpFormKey = GlobalKey(); - - bool _payWithUsdp = false; - - ChannelInfo? channelInfo; - - Amount _satsAmount = Amount.zero(); - Amount _usdpAmount = Amount.zero(); - - final TextEditingController _satsController = TextEditingController(); - final TextEditingController _usdpController = TextEditingController(); - - @override - void initState() { - super.initState(); - final ChannelInfoService channelInfoService = context.read(); - final WalletService walletService = context.read().service; - final tradeValueChangeNotifier = context.read(); - init(channelInfoService, walletService, tradeValueChangeNotifier); - } - - @override - void dispose() { - super.dispose(); - _satsController.dispose(); - _usdpController.dispose(); - } - - Future init(ChannelInfoService channelInfoService, WalletService walletService, - TradeValuesChangeNotifier tradeValuesChangeNotifier) async { - channelInfo = await channelInfoService.getChannelInfo(); - setState(() { - _satsAmount = widget.destination.amount; - _satsController.text = _satsAmount.formatted(); - - final tradeValues = tradeValuesChangeNotifier.fromDirection(Direction.long); - tradeValues.updateLeverage(Leverage(1)); - tradeValues.updateMargin(_satsAmount); - - _usdpAmount = tradeValues.quantity ?? Amount.zero(); - _usdpController.text = _usdpAmount.formatted(); - }); - } - - @override - Widget build(BuildContext context) { - final positionChangeNotifier = context.read(); - final tradeValuesChangeNotifier = context.watch(); - - final formatter = NumberFormat("#,###,##0.00", "en"); - - final usdpBalance = positionChangeNotifier.getStableUSDAmountInFiat(); - final offChainBalance = getOffChainBalance(); - - return GestureDetector( - onTap: () => FocusManager.instance.primaryFocus?.unfocus(), - child: Scaffold( - resizeToAvoidBottomInset: true, - body: ScrollableSafeArea( - child: Container( - margin: const EdgeInsets.all(20.0), - child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - const TenTenOneAppBar(title: "Send"), - const SizedBox( - height: 20, - ), - Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - border: Border.all(color: Colors.grey.shade200), - borderRadius: BorderRadius.circular(10), - color: tenTenOnePurple.shade200.withOpacity(0.1)), - child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( - "Pay to:", - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), - textAlign: TextAlign.start, - ), - const SizedBox(height: 2), - Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text(truncateWithEllipsis(18, widget.destination.raw), - overflow: TextOverflow.ellipsis, style: const TextStyle(fontSize: 16)), - Container( - padding: const EdgeInsets.only(left: 10, right: 10, top: 5, bottom: 5), - decoration: BoxDecoration( - color: tenTenOnePurple, - border: Border.all(color: Colors.grey.shade200), - borderRadius: BorderRadius.circular(20), - ), - child: const Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Icon(BitcoinIcons.lightning, size: 14, color: Colors.white), - Text("Lightning", style: TextStyle(fontSize: 14, color: Colors.white)) - ], - ), - ) - ]) - ]), - ), - const SizedBox(height: 25), - Text( - isZeroValueInvoice ? "Enter amount" : "Amount", - textAlign: TextAlign.center, - style: const TextStyle(fontSize: 14, color: Colors.grey), - ), - const SizedBox(height: 10), - Container( - margin: const EdgeInsets.only(left: 40, right: 40), - child: Visibility( - maintainState: true, - visible: !_payWithUsdp, - child: buildSatsForm( - tradeValuesChangeNotifier, offChainBalance.$1, offChainBalance.$2))), - Container( - margin: const EdgeInsets.only(left: 40, right: 40), - child: Visibility( - maintainState: true, - visible: _payWithUsdp, - child: buildUsdpForm(tradeValuesChangeNotifier, usdpBalance), - ), - ), - const SizedBox(height: 25), - Visibility( - visible: widget.destination.description != "", - child: Column( - children: [ - Container( - padding: const EdgeInsets.only(top: 20, left: 20, right: 20, bottom: 20), - decoration: BoxDecoration( - border: Border.all(color: Colors.grey.shade200), - borderRadius: BorderRadius.circular(10), - color: tenTenOnePurple.shade200.withOpacity(0.1)), - child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - const Text( - "Memo:", - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), - textAlign: TextAlign.start, - ), - const SizedBox(height: 5), - Text(widget.destination.description, - maxLines: 2, - overflow: TextOverflow.ellipsis, - softWrap: true, - style: const TextStyle(fontSize: 16)) - ]), - ), - const SizedBox(height: 15), - ], - )), - const Text( - "Pay from:", - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), - textAlign: TextAlign.start, - ), - const SizedBox(height: 5), - Container( - decoration: BoxDecoration( - border: Border.all(color: Colors.grey.shade200), - borderRadius: BorderRadius.circular(10), - color: tenTenOnePurple.shade200.withOpacity(0.1)), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - GestureDetector( - onTap: () => setState(() => _payWithUsdp = false), - child: Container( - padding: const EdgeInsets.all(20), - child: Opacity( - opacity: _payWithUsdp ? 0.5 : 1.0, - child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Icon(BitcoinIcons.lightning, size: 18), - Text("Lightning", style: TextStyle(fontSize: 18)) - ]), - const SizedBox(height: 5), - Text(offChainBalance.$2.toString(), textAlign: TextAlign.start), - ])), - ), - ), - TenTenOneSwitch( - value: _payWithUsdp, - isDisabled: usdpBalance <= 0, - showDisabled: !_payWithUsdp, - onChanged: (value) => setState(() => _payWithUsdp = value)), - GestureDetector( - onTap: () => setState(() => _payWithUsdp = true), - child: Container( - padding: const EdgeInsets.all(20), - child: Opacity( - opacity: _payWithUsdp ? 1.0 : 0.5, - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - const Text("USD-P", style: TextStyle(fontSize: 18)), - const SizedBox(height: 5), - Text(formatter.format(usdpBalance), textAlign: TextAlign.end), - ], - ), - ), - ), - ) - ], - ), - ), - const SizedBox(height: 2), - const Spacer(), - const SizedBox(height: 10), - SizedBox( - width: MediaQuery.of(context).size.width * 0.9, - child: ElevatedButton( - onPressed: (_payWithUsdp - ? (_usdpFormKey.currentState?.validate() ?? false) - : (_satsFormKey.currentState?.validate() ?? false)) - ? () => showConfirmPaymentModal( - context, widget.destination, _payWithUsdp, _satsAmount, _usdpAmount) - : null, - style: ButtonStyle( - padding: MaterialStateProperty.all(const EdgeInsets.all(15)), - backgroundColor: MaterialStateProperty.resolveWith((states) { - if (states.contains(MaterialState.disabled)) { - return tenTenOnePurple.shade100; - } else { - return tenTenOnePurple; - } - }), - shape: MaterialStateProperty.resolveWith((states) { - if (states.contains(MaterialState.disabled)) { - return RoundedRectangleBorder( - borderRadius: BorderRadius.circular(30.0), - side: BorderSide(color: tenTenOnePurple.shade100), - ); - } else { - return RoundedRectangleBorder( - borderRadius: BorderRadius.circular(30.0), - side: const BorderSide(color: tenTenOnePurple), - ); - } - })), - child: const Text( - "Pay", - style: TextStyle(fontSize: 18, color: Colors.white), - )), - ), - ]), - ), - ), - ), - ); - } - - Form buildUsdpForm(TradeValuesChangeNotifier tradeValuesChangeNotifier, double usdpBalance) { - return Form( - key: _usdpFormKey, - child: FormField( - validator: (val) { - final amount = _usdpAmount; - - if (amount.sats <= 0) { - return "Amount cannot be 0"; - } - - if (amount.sats < 0) { - return "Amount cannot be negative"; - } - - if (amount.sats > usdpBalance) { - return "Not enough funds."; - } - - return null; - }, - builder: (FormFieldState formFieldState) { - return Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - TextField( - keyboardType: TextInputType.number, - textAlign: TextAlign.center, - controller: _usdpController, - decoration: const InputDecoration( - hintText: "0.00", - hintStyle: TextStyle(fontSize: 40), - enabledBorder: InputBorder.none, - border: InputBorder.none, - errorBorder: InputBorder.none, - suffix: Text( - "\$", - style: TextStyle(fontSize: 16), - )), - style: const TextStyle(fontSize: 40), - textAlignVertical: TextAlignVertical.center, - enabled: isZeroValueInvoice, - onChanged: (value) { - setState(() { - _usdpAmount = Amount.parseAmount(value); - final tradeValues = tradeValuesChangeNotifier.fromDirection(Direction.long); - tradeValues.updateQuantity(_usdpAmount); - _usdpController.text = _usdpAmount.formatted(); - - _satsAmount = tradeValues.margin ?? Amount.zero(); - _satsController.text = _satsAmount.formatted(); - _satsController.selection = - TextSelection.collapsed(offset: _satsController.text.length); - }); - }, - ), - Visibility( - visible: formFieldState.hasError, - replacement: Container(margin: const EdgeInsets.only(top: 30, bottom: 10)), - child: Container( - decoration: BoxDecoration( - color: Colors.redAccent.shade100.withOpacity(0.1), - border: Border.all(color: Colors.red), - borderRadius: BorderRadius.circular(10)), - padding: const EdgeInsets.all(10), - child: Wrap( - crossAxisAlignment: WrapCrossAlignment.center, - children: [ - const Icon(Icons.info_outline, color: Colors.black87, size: 18), - const SizedBox(width: 5), - Text( - formFieldState.errorText ?? "", - textAlign: TextAlign.center, - style: const TextStyle(color: Colors.black87, fontSize: 14), - ), - ], - ), - ), - ) - ], - ); - }, - ), - ); - } - - Form buildSatsForm( - TradeValuesChangeNotifier tradeValuesChangeNotifier, Amount balance, Amount useableBalance) { - return Form( - key: _satsFormKey, - child: FormField( - validator: (val) { - final amount = _satsAmount; - - if (amount.sats <= 0 && widget.destination.getWalletType() == WalletType.lightning) { - return "Amount cannot be 0"; - } - - if (amount.sats < 0) { - return "Amount cannot be negative"; - } - - if (amount.sats > balance.sats) { - return "Not enough funds."; - } - - if (amount.sats > useableBalance.sats) { - return "Not enough funds. ${formatSats(balance.sub(useableBalance))} have to remain."; - } - - return null; - }, - builder: (FormFieldState formFieldState) { - return Column( - children: [ - TextField( - keyboardType: TextInputType.number, - textAlign: TextAlign.center, - decoration: const InputDecoration( - hintText: "0.00", - hintStyle: TextStyle(fontSize: 40), - enabledBorder: InputBorder.none, - border: InputBorder.none, - errorBorder: InputBorder.none, - suffix: Text( - "sats", - style: TextStyle(fontSize: 16), - )), - style: const TextStyle(fontSize: 40), - textAlignVertical: TextAlignVertical.center, - enabled: widget.destination.amount.sats == 0, - controller: _satsController, - onChanged: (value) { - setState(() { - _satsAmount = Amount.parseAmount(value); - final tradeValues = tradeValuesChangeNotifier.fromDirection(Direction.long); - tradeValues.updateMargin(_satsAmount); - _satsController.text = _satsAmount.formatted(); - - _usdpAmount = tradeValues.quantity ?? Amount.zero(); - _usdpController.text = _usdpAmount.formatted(); - _usdpController.selection = - TextSelection.collapsed(offset: _usdpController.text.length); - }); - }, - ), - Visibility( - visible: formFieldState.hasError, - replacement: Container(margin: const EdgeInsets.only(top: 30, bottom: 10)), - child: Container( - decoration: BoxDecoration( - color: Colors.redAccent.shade100.withOpacity(0.1), - border: Border.all(color: Colors.red), - borderRadius: BorderRadius.circular(10)), - padding: const EdgeInsets.all(10), - child: Wrap( - crossAxisAlignment: WrapCrossAlignment.center, - children: [ - const Icon(Icons.info_outline, color: Colors.black87, size: 18), - const SizedBox(width: 5), - Text( - formFieldState.errorText ?? "", - textAlign: TextAlign.center, - style: const TextStyle(color: Colors.black87, fontSize: 14), - ), - ], - ), - ), - ) - ], - ); - }, - ), - ); - } - - (Amount, Amount) getOffChainBalance() { - final walletInfo = context.read().walletInfo; - final ChannelInfoService channelInfoService = context.read(); - Amount initialReserve = channelInfoService.getInitialReserve(); - int channelReserve = channelInfo?.reserve.sats ?? initialReserve.sats; - int balance = walletInfo.balances.offChain.sats; - - return (Amount(balance), Amount(max(balance - channelReserve, 0))); - } - - bool get isZeroValueInvoice => widget.destination.amount.sats == 0; -}