From e8acbd2c500c79f1ecb60405ce885437b4ed6ee6 Mon Sep 17 00:00:00 2001
From: vjrj <vjrj@comunes.org>
Date: Mon, 3 Apr 2023 00:03:37 +0200
Subject: [PATCH] Pay fail with retry message if faulty balance

---
 assets/translations/en.json  |  3 +-
 assets/translations/es.json  |  3 +-
 lib/ui/screens/pay_form.dart | 98 ++++++++++++++++++++++--------------
 3 files changed, 63 insertions(+), 41 deletions(-)

diff --git a/assets/translations/en.json b/assets/translations/en.json
index f6e342b8..a18421a5 100644
--- a/assets/translations/en.json
+++ b/assets/translations/en.json
@@ -119,5 +119,6 @@
   "long_press_to_edit": "Tap and hold to edit",
   "form_contact_pub_key": "Public key",
   "payment_error": "Payment error",
-  "payment_error_desc": "Oops! the payment failed. More details: {error}"
+  "payment_error_desc": "Oops! the payment failed. More details: {error}",
+  "payment_error_retry": "Oops! the payment failed. Please retry in some minutes."
 }
diff --git a/assets/translations/es.json b/assets/translations/es.json
index 69de3807..36e8edf6 100644
--- a/assets/translations/es.json
+++ b/assets/translations/es.json
@@ -119,5 +119,6 @@
   "form_contact_pub_key": "Clave pública",
   "reloading_nodes": "Refrescando nodos del tipo {type}",
   "payment_error": "Error en el pago",
-  "payment_error_desc": "¡Vaya! el pago falló. Más detalles: {error}"
+  "payment_error_desc": "¡Vaya! el pago falló. Más detalles: {error}",
+  "payment_error_retry": "¡Vaya! el pago falló. Inténtalo de nuevo en unos minutos"
 }
diff --git a/lib/ui/screens/pay_form.dart b/lib/ui/screens/pay_form.dart
index 8c8f956e..af8e41ca 100644
--- a/lib/ui/screens/pay_form.dart
+++ b/lib/ui/screens/pay_form.dart
@@ -77,45 +77,11 @@ class _PayFormState extends State<PayForm> {
                       !_weHaveBalance(context, state.amount!))
                   ? null
                   : () async {
-                      // We disable the number, anyway
-                      context.read<PaymentCubit>().sending();
-                      final String contactPubKey = state.contact!.pubKey;
-                      final bool? confirmed = await _confirmSend(
-                          context,
-                          state.amount.toString(),
-                          humanizePubKey(contactPubKey));
-                      if (!mounted) {
-                        return;
-                      }
-                      if (confirmed == null || !confirmed) {
-                        context.read<PaymentCubit>().sentFailed();
-                      } else {
-                        final String response = await pay(
-                            to: contactPubKey,
-                            comment: state.comment,
-                            amount: state.amount!);
-                        if (!mounted) {
-                          // Cannot show a tooltip if the widget is not now visible
-                          return;
-                        }
-                        if (response == 'success') {
-                          context.read<PaymentCubit>().sent();
-                          showTooltip(context, tr('payment_successful'),
-                              tr('payment_successful_desc'));
-                        } else {
-                          showTooltip(
-                              context,
-                              tr('payment_error'),
-                              tr('payment_error_desc',
-                                  namedArgs: <String, String>{
-                                    // We try to translate the error, like "insufficient balance"
-                                    'error': tr(response)
-                                  }));
-                          context.read<PaymentCubit>().sentFailed();
-                          // Shuffle the nodes so we can retry with other
-                          context.read<NodeListCubit>().shuffle(NodeType.gva);
-                          // FIXME - retry manually with other node
-                        }
+                      try {
+                        await payWithRetry(context, state, false);
+                      } on RetryException {
+                        // Here the transactions can be lost, so we must implement some manual retry use
+                        await payWithRetry(context, state, true);
                       }
                     },
               style: ElevatedButton.styleFrom(
@@ -181,6 +147,60 @@ class _PayFormState extends State<PayForm> {
       },
     );
   }
+
+  Future<void> payWithRetry(
+      BuildContext context, PaymentState state, bool useMempool) async {
+    logger('Trying to pay state with useMempool: $useMempool');
+    // We disable the number, anyway
+    context.read<PaymentCubit>().sending();
+    final String contactPubKey = state.contact!.pubKey;
+    final bool? confirmed = await _confirmSend(
+        context, state.amount.toString(), humanizePubKey(contactPubKey));
+    if (!mounted) {
+      return;
+    }
+    if (confirmed == null || !confirmed) {
+      context.read<PaymentCubit>().sentFailed();
+    } else {
+      final String response = await pay(
+          to: contactPubKey, comment: state.comment, amount: state.amount!);
+      if (!mounted) {
+        // Cannot show a tooltip if the widget is not now visible
+        return;
+      }
+      if (response == 'success') {
+        context.read<PaymentCubit>().sent();
+        showTooltip(
+            context, tr('payment_successful'), tr('payment_successful_desc'));
+      } else {
+        /* this retry didn't work
+        if (!useMempool) {
+          throw RetryException();
+        } */
+        final bool failedWithBalance = response == 'insufficient balance' &&
+            _weHaveBalance(context, state.amount!);
+        showPayError(
+            context,
+            failedWithBalance
+                ? tr('payment_error_retry')
+                : tr('payment_error_desc', namedArgs: <String, String>{
+                    // We try to translate the error, like "insufficient balance"
+                    'error': tr(response)
+                  }));
+      }
+    }
+  }
+
+  void showPayError(BuildContext context, String desc) {
+    showTooltip(context, tr('payment_error'), desc);
+    context.read<PaymentCubit>().sentFailed();
+    // Shuffle the nodes so we can retry with other
+    context.read<NodeListCubit>().shuffle(NodeType.gva, true);
+  }
+}
+
+class RetryException implements Exception {
+  RetryException();
 }
 
 class NoNewLineTextInputFormatter extends TextInputFormatter {
-- 
GitLab