From d2ffe43ffe4dc3e0c25f04b603a54243142db4d5 Mon Sep 17 00:00:00 2001 From: ruben beck Date: Fri, 18 Aug 2023 09:24:38 +0200 Subject: [PATCH] add error handling when channel creation is not possible --- lib/bloc/account/account_bloc.dart | 15 ++++-- lib/bloc/account/payment_error.dart | 10 ++++ .../create_invoice/create_invoice_page.dart | 32 +++++++++---- lib/utils/payment_validator.dart | 7 ++- lib/widgets/receivable_btc_box.dart | 47 ++++++++++++++----- 5 files changed, 84 insertions(+), 27 deletions(-) diff --git a/lib/bloc/account/account_bloc.dart b/lib/bloc/account/account_bloc.dart index 9df943ce9..cfa22c624 100644 --- a/lib/bloc/account/account_bloc.dart +++ b/lib/bloc/account/account_bloc.dart @@ -221,6 +221,7 @@ class AccountBloc extends Cubit with HydratedMixin { int amount, bool outgoing, { int? channelMinimumFee, + bool? channelCreationPossible, }) { _log.v("validatePayment: $amount, $outgoing, $channelMinimumFee"); var accState = state; @@ -230,14 +231,18 @@ class AccountBloc extends Cubit with HydratedMixin { } if (!outgoing) { - if (channelMinimumFee != null && + if (channelCreationPossible != null && !channelCreationPossible && accState.maxInboundLiquidity == 0) { + throw NoChannelCreationZeroLiqudityError(); + } else if (channelCreationPossible != null && + !channelCreationPossible && + accState.maxInboundLiquidity < 0) { + throw PaymentExcededLiqudityChannelCreationNotPossibleError(accState.maxInboundLiquidity); + } else if (channelMinimumFee != null && (amount > accState.maxInboundLiquidity && amount <= channelMinimumFee)) { throw PaymentBelowSetupFeesError(channelMinimumFee); - } - if (channelMinimumFee == null && amount > accState.maxInboundLiquidity) { + } else if (channelMinimumFee == null && amount > accState.maxInboundLiquidity) { throw PaymentExceedLiquidityError(accState.maxInboundLiquidity); - } - if (amount > accState.maxAllowedToReceive) { + } else if (amount > accState.maxAllowedToReceive) { throw PaymentExceededLimitError(accState.maxAllowedToReceive); } } diff --git a/lib/bloc/account/payment_error.dart b/lib/bloc/account/payment_error.dart index a976cdc32..349ef036d 100644 --- a/lib/bloc/account/payment_error.dart +++ b/lib/bloc/account/payment_error.dart @@ -41,3 +41,13 @@ class PaymentExceedLiquidityError implements Exception { this.limitSat, ); } + +class PaymentExcededLiqudityChannelCreationNotPossibleError implements Exception { + final int limitSat; + + const PaymentExcededLiqudityChannelCreationNotPossibleError( + this.limitSat, + ); +} + +class NoChannelCreationZeroLiqudityError implements Exception {} diff --git a/lib/routes/create_invoice/create_invoice_page.dart b/lib/routes/create_invoice/create_invoice_page.dart index 56036dfa1..f4b2b204f 100644 --- a/lib/routes/create_invoice/create_invoice_page.dart +++ b/lib/routes/create_invoice/create_invoice_page.dart @@ -55,6 +55,7 @@ class CreateInvoicePageState extends State { final _amountController = TextEditingController(); final _amountFocusNode = FocusNode(); var _doneAction = KeyboardDoneAction(); + bool channelCreationPossible = false; @override void initState() { @@ -65,6 +66,12 @@ class CreateInvoicePageState extends State { _amountController.text = (data.maxWithdrawable ~/ 1000).toString(); _descriptionController.text = data.defaultDescription; } + + final lspState = context.read().state; + if (lspState != null) { + channelCreationPossible = lspState.isChannelOpeningAvailiable; + } + super.initState(); } @@ -124,16 +131,20 @@ class CreateInvoicePageState extends State { builder: (context, accountState, currencyState, lspState) { return ReceivableBTCBox( onTap: () { - lspState!.isChannelOpeningAvailiable - ? _amountController.text = currencyState.bitcoinCurrency.format( - accountState.maxAllowedToReceive, - includeDisplayName: false, - userInput: true, - ) - : _amountController.text = currencyState.bitcoinCurrency.format( - accountState.maxInboundLiquidity, - includeDisplayName: false, - userInput: true); + if (!channelCreationPossible && accountState.maxInboundLiquidity < 0) { + _amountController.text = currencyState.bitcoinCurrency.format( + accountState.maxInboundLiquidity, + includeDisplayName: false, + userInput: true, + ); + } else if (!channelCreationPossible && accountState.maxInboundLiquidity > 0) { + // do nothing + } else { + _amountController.text = currencyState.bitcoinCurrency.format( + accountState.maxAllowedToReceive, + includeDisplayName: false, + userInput: true); + } }, ); }, @@ -271,6 +282,7 @@ class CreateInvoicePageState extends State { amount, outgoing, channelMinimumFee: channelMinimumFee, + channelCreationPossible: channelCreationPossible, ); } } diff --git a/lib/utils/payment_validator.dart b/lib/utils/payment_validator.dart index f9a050c3b..d06fe1ee9 100644 --- a/lib/utils/payment_validator.dart +++ b/lib/utils/payment_validator.dart @@ -51,7 +51,7 @@ class PaymentValidator { currency.format(e.reserveAmount), ); } on PaymentExceedLiquidityError catch (e) { - // TODO: Add translation + // TODO(ubbabeck): Add translation return "Insufficient inbound liquidity (${currency.format(e.limitSat)})"; } on InsufficientLocalBalanceError { return texts.invoice_payment_validator_error_insufficient_local_balance; @@ -60,6 +60,11 @@ class PaymentValidator { return texts.invoice_payment_validator_error_payment_below_setup_fees_error( currency.format(e.setupFees), ); + } on PaymentExcededLiqudityChannelCreationNotPossibleError catch (e) { + // TODO(ubbabeck) Add translation + return "Maximum allowed amount to receive is ${e.limitSat}"; + } on NoChannelCreationZeroLiqudityError { + return "You cannot receive funds, channel creation not possible."; } catch (e) { _log.v("Got Generic error", ex: e); return texts.invoice_payment_validator_error_unknown( diff --git a/lib/widgets/receivable_btc_box.dart b/lib/widgets/receivable_btc_box.dart index f94e63f3d..0c1ca3bdf 100644 --- a/lib/widgets/receivable_btc_box.dart +++ b/lib/widgets/receivable_btc_box.dart @@ -44,20 +44,45 @@ class ReceivableBTCBoxState extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - AutoSizeText( - widget.receiveLabel ?? - texts.invoice_receive_label( - currencyState.bitcoinCurrency.format( - lspState!.isChannelOpeningAvailiable - ? accountState.maxAllowedToReceive - : accountState.maxInboundLiquidity, + (accountState.maxInboundLiquidity > 0 && + lspState != null && + !lspState!.isChannelOpeningAvailiable) + ? AutoSizeText( + widget.receiveLabel ?? + texts.invoice_receive_label( + currencyState.bitcoinCurrency.format( + lspState!.isChannelOpeningAvailiable + ? accountState.maxAllowedToReceive + : accountState.maxInboundLiquidity, + ), + ), + style: theme.textStyle, + maxLines: 1, + minFontSize: MinFontSize(context).minFontSize, + ) + : const WarningBox( + boxPadding: EdgeInsets.only(top: 8), + child: AutoSizeText( + // TODO(ubbabeck) add translations + "Channel creation not possible cannot receive funds. Please try again later, contact or change your LSP provider.", + textAlign: TextAlign.center, ), ), - style: theme.textStyle, - maxLines: 1, - minFontSize: MinFontSize(context).minFontSize, - ), accountState.isFeesApplicable ? FeeMessage() : const SizedBox(), + (lspState != null && + !lspState!.isChannelOpeningAvailiable && + accountState.maxInboundLiquidity < 0) + ? WarningBox( + boxPadding: const EdgeInsets.only(top: 22), + contentPadding: const EdgeInsets.all(8), + child: AutoSizeText( + // TODO(ubbabeck) add translations + "LSP cannot open channel now. Retry later. Maximum allowed to receive: ${currencyState.bitcoinCurrency.format(accountState.maxInboundLiquidity)}.", + textAlign: TextAlign.center, + minFontSize: MinFontSize(context).minFontSize, + ), + ) + : const SizedBox(), ], ), ),