From 2bfce21058b7cc7973b9df7b5394f60315c0e0e3 Mon Sep 17 00:00:00 2001
From: julian <julian@cypherstack.com>
Date: Wed, 26 Apr 2023 09:27:29 -0600
Subject: [PATCH] btc restore gap fix

---
 .../coins/bitcoin/bitcoin_wallet.dart         | 27 ++++++++++++++++---
 1 file changed, 23 insertions(+), 4 deletions(-)

diff --git a/lib/services/coins/bitcoin/bitcoin_wallet.dart b/lib/services/coins/bitcoin/bitcoin_wallet.dart
index dd3301835..86d84b0c0 100644
--- a/lib/services/coins/bitcoin/bitcoin_wallet.dart
+++ b/lib/services/coins/bitcoin/bitcoin_wallet.dart
@@ -423,7 +423,7 @@ class BitcoinWallet extends CoinServiceAPI
         level: LogLevel.Info);
   }
 
-  Future<Tuple2<List<isar_models.Address>, DerivePathType>> _checkGaps(
+  Future<Tuple3<List<isar_models.Address>, DerivePathType, int>> _checkGaps(
     int maxNumberOfIndexesToCheck,
     int maxUnusedAddressGap,
     int txCountBatchSize,
@@ -433,6 +433,8 @@ class BitcoinWallet extends CoinServiceAPI
   ) async {
     List<isar_models.Address> addressArray = [];
     int gapCounter = 0;
+    int highestIndexWithHistory = 0;
+
     for (int index = 0;
         index < maxNumberOfIndexesToCheck && gapCounter < maxUnusedAddressGap;
         index += txCountBatchSize) {
@@ -506,6 +508,9 @@ class BitcoinWallet extends CoinServiceAPI
         if (count > 0) {
           iterationsAddressArray.add(txCountCallArgs["${_id}_$k"]!);
 
+          // update highest
+          highestIndexWithHistory = index + k;
+
           // reset counter
           gapCounter = 0;
         }
@@ -518,7 +523,7 @@ class BitcoinWallet extends CoinServiceAPI
       // cache all the transactions while waiting for the current function to finish.
       unawaited(getTransactionCacheEarly(iterationsAddressArray));
     }
-    return Tuple2(addressArray, type);
+    return Tuple3(addressArray, type, highestIndexWithHistory);
   }
 
   Future<void> getTransactionCacheEarly(List<String> allAddresses) async {
@@ -562,9 +567,9 @@ class BitcoinWallet extends CoinServiceAPI
       DerivePathType.bip84,
     ];
 
-    final List<Future<Tuple2<List<isar_models.Address>, DerivePathType>>>
+    final List<Future<Tuple3<List<isar_models.Address>, DerivePathType, int>>>
         receiveFutures = [];
-    final List<Future<Tuple2<List<isar_models.Address>, DerivePathType>>>
+    final List<Future<Tuple3<List<isar_models.Address>, DerivePathType, int>>>
         changeFutures = [];
 
     const receiveChain = 0;
@@ -623,6 +628,7 @@ class BitcoinWallet extends CoinServiceAPI
 
       final List<isar_models.Address> addressesToStore = [];
 
+      int highestReceivingIndexWithHistory = 0;
       // If restoring a wallet that never received any funds, then set receivingArray manually
       // If we didn't do this, it'd store an empty array
       for (final tuple in receiveResults) {
@@ -634,10 +640,13 @@ class BitcoinWallet extends CoinServiceAPI
           );
           addressesToStore.add(address);
         } else {
+          highestReceivingIndexWithHistory =
+              max(tuple.item3, highestReceivingIndexWithHistory);
           addressesToStore.addAll(tuple.item1);
         }
       }
 
+      int highestChangeIndexWithHistory = 0;
       // If restoring a wallet that never sent any funds with change, then set changeArray
       // manually. If we didn't do this, it'd store an empty array.
       for (final tuple in changeResults) {
@@ -649,10 +658,20 @@ class BitcoinWallet extends CoinServiceAPI
           );
           addressesToStore.add(address);
         } else {
+          highestChangeIndexWithHistory =
+              max(tuple.item3, highestChangeIndexWithHistory);
           addressesToStore.addAll(tuple.item1);
         }
       }
 
+      // remove extra addresses to help minimize risk of creating a large gap
+      addressesToStore.removeWhere((e) =>
+          e.subType == isar_models.AddressSubType.change &&
+          e.derivationIndex > highestChangeIndexWithHistory);
+      addressesToStore.removeWhere((e) =>
+          e.subType == isar_models.AddressSubType.receiving &&
+          e.derivationIndex > highestReceivingIndexWithHistory);
+
       if (isRescan) {
         await db.updateOrPutAddresses(addressesToStore);
       } else {