From fc2c9a2bcc6dc192fdaa5fd36fefb49b62091a83 Mon Sep 17 00:00:00 2001
From: Adegoke David <64401859+Blazebrain@users.noreply.github.com>
Date: Fri, 14 Jun 2024 14:24:10 +0100
Subject: [PATCH 1/4] feat: Int overflow issue (#1482)

---
 cw_evm/lib/evm_chain_formatter.dart | 26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/cw_evm/lib/evm_chain_formatter.dart b/cw_evm/lib/evm_chain_formatter.dart
index cb9b7346c..797728885 100644
--- a/cw_evm/lib/evm_chain_formatter.dart
+++ b/cw_evm/lib/evm_chain_formatter.dart
@@ -1,15 +1,13 @@
-import 'package:intl/intl.dart';
-
-const evmChainAmountLength = 12;
-const evmChainAmountDivider = 1000000000000;
-final evmChainAmountFormat = NumberFormat()
-  ..maximumFractionDigits = evmChainAmountLength
-  ..minimumFractionDigits = 1;
+import 'dart:math';
 
 class EVMChainFormatter {
+  static int _divider = 0;
+
   static int parseEVMChainAmount(String amount) {
     try {
-      return (double.parse(amount) * evmChainAmountDivider).round();
+      final decimalLength = _getDividerForInput(amount);
+      _divider = decimalLength;
+      return (double.parse(amount) * pow(10, decimalLength)).round();
     } catch (_) {
       return 0;
     }
@@ -17,9 +15,19 @@ class EVMChainFormatter {
 
   static double parseEVMChainAmountToDouble(int amount) {
     try {
-      return amount / evmChainAmountDivider;
+      return amount / pow(10, _divider);
     } catch (_) {
       return 0;
     }
   }
+
+  static int _getDividerForInput(String amount) {
+    final result = amount.split('.');
+    if (result.length > 1) {
+      final decimalLength = result[1].length;
+      return decimalLength;
+    } else {
+      return 0;
+    }
+  }
 }

From 591342ec6a0fd26e3163e8536fd14789edeb2aa4 Mon Sep 17 00:00:00 2001
From: Matthew Fosse <matt@fosse.co>
Date: Tue, 18 Jun 2024 07:08:03 +0200
Subject: [PATCH 2/4] electrum updates (#1449)

* hotfixes

* copy over the rest of the fixes

* use hardened derivation path everywhere

* correct balance path for electrum

* revert index nullability and correct balance path for all cases

* only save wallet info if we changed it
---
 cw_bitcoin/lib/bitcoin_wallet.dart           |  3 +-
 cw_bitcoin/lib/electrum_derivations.dart     |  3 ++
 cw_bitcoin/lib/electrum_wallet.dart          |  3 +-
 cw_bitcoin/lib/electrum_wallet_snapshot.dart |  3 +-
 cw_bitcoin/lib/utils.dart                    | 36 ++++++++++--------
 lib/bitcoin/cw_bitcoin.dart                  | 40 +++++++++-----------
 lib/entities/default_settings_migration.dart | 15 ++++++++
 lib/main.dart                                |  2 +-
 lib/view_model/wallet_creation_vm.dart       |  6 +--
 tool/configure.dart                          |  1 +
 10 files changed, 66 insertions(+), 46 deletions(-)

diff --git a/cw_bitcoin/lib/bitcoin_wallet.dart b/cw_bitcoin/lib/bitcoin_wallet.dart
index 3954631e8..d061480ed 100644
--- a/cw_bitcoin/lib/bitcoin_wallet.dart
+++ b/cw_bitcoin/lib/bitcoin_wallet.dart
@@ -6,6 +6,7 @@ import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
 import 'package:convert/convert.dart';
 import 'package:cw_bitcoin/bitcoin_address_record.dart';
 import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
+import 'package:cw_bitcoin/electrum_derivations.dart';
 import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
 import 'package:cw_bitcoin/electrum_balance.dart';
 import 'package:cw_bitcoin/electrum_wallet.dart';
@@ -150,7 +151,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
     );
 
     // set the default if not present:
-    walletInfo.derivationInfo!.derivationPath = snp.derivationPath ?? "m/0'/0";
+    walletInfo.derivationInfo!.derivationPath = snp.derivationPath ?? electrum_path;
     walletInfo.derivationInfo!.derivationType = snp.derivationType ?? DerivationType.electrum;
 
     Uint8List? seedBytes = null;
diff --git a/cw_bitcoin/lib/electrum_derivations.dart b/cw_bitcoin/lib/electrum_derivations.dart
index 7e19f1cb4..749e5c7af 100644
--- a/cw_bitcoin/lib/electrum_derivations.dart
+++ b/cw_bitcoin/lib/electrum_derivations.dart
@@ -108,3 +108,6 @@ Map<DerivationType, List<DerivationInfo>> electrum_derivations = {
     ),
   ],
 };
+
+
+String electrum_path = electrum_derivations[DerivationType.electrum]!.first.derivationPath!;
\ No newline at end of file
diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart
index d3736e076..db42e2356 100644
--- a/cw_bitcoin/lib/electrum_wallet.dart
+++ b/cw_bitcoin/lib/electrum_wallet.dart
@@ -17,6 +17,7 @@ import 'package:cw_bitcoin/bitcoin_unspent.dart';
 import 'package:cw_bitcoin/bitcoin_wallet_keys.dart';
 import 'package:cw_bitcoin/electrum.dart';
 import 'package:cw_bitcoin/electrum_balance.dart';
+import 'package:cw_bitcoin/electrum_derivations.dart';
 import 'package:cw_bitcoin/electrum_transaction_history.dart';
 import 'package:cw_bitcoin/electrum_transaction_info.dart';
 import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
@@ -133,7 +134,7 @@ abstract class ElectrumWalletBase
       return currency == CryptoCurrency.bch
           ? bitcoinCashHDWallet(seedBytes)
           : bitcoin.HDWallet.fromSeed(seedBytes, network: networkType)
-              .derivePath(_hardenedDerivationPath(derivationInfo?.derivationPath ?? "m/0'"));
+              .derivePath(_hardenedDerivationPath(derivationInfo?.derivationPath ?? electrum_path));
     }
 
     return bitcoin.HDWallet.fromBase58(xpub!);
diff --git a/cw_bitcoin/lib/electrum_wallet_snapshot.dart b/cw_bitcoin/lib/electrum_wallet_snapshot.dart
index 3e3f39131..15ad1cf63 100644
--- a/cw_bitcoin/lib/electrum_wallet_snapshot.dart
+++ b/cw_bitcoin/lib/electrum_wallet_snapshot.dart
@@ -2,6 +2,7 @@ import 'dart:convert';
 import 'package:bitcoin_base/bitcoin_base.dart';
 import 'package:cw_bitcoin/bitcoin_address_record.dart';
 import 'package:cw_bitcoin/electrum_balance.dart';
+import 'package:cw_bitcoin/electrum_derivations.dart';
 import 'package:cw_core/pathForWallet.dart';
 import 'package:cw_core/wallet_info.dart';
 import 'package:cw_core/utils/file.dart';
@@ -71,7 +72,7 @@ class ElectrumWalletSnapshot {
 
     final derivationType = DerivationType
         .values[(data['derivationTypeIndex'] as int?) ?? DerivationType.electrum.index];
-    final derivationPath = data['derivationPath'] as String? ?? "m/0'/0";
+    final derivationPath = data['derivationPath'] as String? ?? electrum_path;
 
     try {
       regularAddressIndexByType = {
diff --git a/cw_bitcoin/lib/utils.dart b/cw_bitcoin/lib/utils.dart
index b3707e764..e3ebc00db 100644
--- a/cw_bitcoin/lib/utils.dart
+++ b/cw_bitcoin/lib/utils.dart
@@ -5,58 +5,64 @@ import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
 import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData;
 import 'package:hex/hex.dart';
 
-bitcoin.PaymentData generatePaymentData({required bitcoin.HDWallet hd, int? index}) {
-  final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
+bitcoin.PaymentData generatePaymentData({
+  required bitcoin.HDWallet hd,
+  required int index,
+}) {
+  final pubKey = hd.derive(index).pubKey!;
   return PaymentData(pubkey: Uint8List.fromList(HEX.decode(pubKey)));
 }
 
-ECPrivate generateECPrivate(
-    {required bitcoin.HDWallet hd, required BasedUtxoNetwork network, int? index}) {
-  final wif = index != null ? hd.derive(index).wif! : hd.wif!;
+ECPrivate generateECPrivate({
+  required bitcoin.HDWallet hd,
+  required BasedUtxoNetwork network,
+  required int index,
+}) {
+  final wif = hd.derive(index).wif!;
   return ECPrivate.fromWif(wif, netVersion: network.wifNetVer);
 }
 
 String generateP2WPKHAddress({
   required bitcoin.HDWallet hd,
   required BasedUtxoNetwork network,
-  int? index,
+  required int index,
 }) {
-  final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
+  final pubKey = hd.derive(index).pubKey!;
   return ECPublic.fromHex(pubKey).toP2wpkhAddress().toAddress(network);
 }
 
 String generateP2SHAddress({
   required bitcoin.HDWallet hd,
   required BasedUtxoNetwork network,
-  int? index,
+  required int index,
 }) {
-  final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
+  final pubKey = hd.derive(index).pubKey!;
   return ECPublic.fromHex(pubKey).toP2wpkhInP2sh().toAddress(network);
 }
 
 String generateP2WSHAddress({
   required bitcoin.HDWallet hd,
   required BasedUtxoNetwork network,
-  int? index,
+  required int index,
 }) {
-  final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
+  final pubKey = hd.derive(index).pubKey!;
   return ECPublic.fromHex(pubKey).toP2wshAddress().toAddress(network);
 }
 
 String generateP2PKHAddress({
   required bitcoin.HDWallet hd,
   required BasedUtxoNetwork network,
-  int? index,
+  required int index,
 }) {
-  final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
+  final pubKey = hd.derive(index).pubKey!;
   return ECPublic.fromHex(pubKey).toP2pkhAddress().toAddress(network);
 }
 
 String generateP2TRAddress({
   required bitcoin.HDWallet hd,
   required BasedUtxoNetwork network,
-  int? index,
+  required int index,
 }) {
-  final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
+  final pubKey = hd.derive(index).pubKey!;
   return ECPublic.fromHex(pubKey).toTaprootAddress().toAddress(network);
 }
diff --git a/lib/bitcoin/cw_bitcoin.dart b/lib/bitcoin/cw_bitcoin.dart
index 15d2ffadf..c62030504 100644
--- a/lib/bitcoin/cw_bitcoin.dart
+++ b/lib/bitcoin/cw_bitcoin.dart
@@ -295,14 +295,7 @@ class CWBitcoin extends Bitcoin {
 
     List<DerivationType> types = await compareDerivationMethods(mnemonic: mnemonic, node: node);
     if (types.length == 1 && types.first == DerivationType.electrum) {
-      return [
-        DerivationInfo(
-          derivationType: DerivationType.electrum,
-          derivationPath: "m/0'",
-          description: "Electrum",
-          scriptType: "p2wpkh",
-        )
-      ];
+      return [getElectrumDerivations()[DerivationType.electrum]!.first];
     }
 
     final electrumClient = ElectrumClient();
@@ -339,38 +332,34 @@ class CWBitcoin extends Bitcoin {
             scriptType: dInfo.scriptType,
           );
 
-          String derivationPath = dInfoCopy.derivationPath!;
-          int derivationDepth = _countOccurrences(derivationPath, "/");
-
-          // the correct derivation depth is dependant on the derivation type:
-          // the derivation paths defined in electrum_derivations are at the ROOT level, i.e.:
-          // electrum's format doesn't specify subaddresses, just subaccounts:
+          String balancePath = dInfoCopy.derivationPath!;
+          int derivationDepth = _countOccurrences(balancePath, "/");
 
           // for BIP44
-          if (derivationDepth == 3) {
-            // we add "/0/0" so that we generate account 0, index 0 and correctly get balance
-            derivationPath += "/0/0";
+          if (derivationDepth == 3 || derivationDepth == 1) {
+            // we add "/0" so that we generate account 0
+            balancePath += "/0";
           }
 
-          // var hd = bip32.BIP32.fromSeed(seedBytes).derivePath(derivationPath);
           final hd = btc.HDWallet.fromSeed(
             seedBytes,
             network: networkType,
-          ).derivePath(derivationPath);
+          ).derivePath(balancePath);
 
+          // derive address at index 0:
           String? address;
           switch (dInfoCopy.scriptType) {
             case "p2wpkh":
-              address = generateP2WPKHAddress(hd: hd, network: network);
+              address = generateP2WPKHAddress(hd: hd, network: network, index: 0);
               break;
             case "p2pkh":
-              address = generateP2PKHAddress(hd: hd, network: network);
+              address = generateP2PKHAddress(hd: hd, network: network, index: 0);
               break;
             case "p2wpkh-p2sh":
-              address = generateP2SHAddress(hd: hd, network: network);
+              address = generateP2SHAddress(hd: hd, network: network, index: 0);
               break;
             case "p2tr":
-              address = generateP2TRAddress(hd: hd, network: network);
+              address = generateP2TRAddress(hd: hd, network: network, index: 0);
               break;
             default:
               continue;
@@ -396,6 +385,11 @@ class CWBitcoin extends Bitcoin {
     return list;
   }
 
+  @override
+  Map<DerivationType, List<DerivationInfo>> getElectrumDerivations() {
+    return electrum_derivations;
+  }
+
   @override
   bool hasTaprootInput(PendingTransaction pendingTransaction) {
     return (pendingTransaction as PendingBitcoinTransaction).hasTaprootInputs;
diff --git a/lib/entities/default_settings_migration.dart b/lib/entities/default_settings_migration.dart
index dcde1d3ce..d25c76dc7 100644
--- a/lib/entities/default_settings_migration.dart
+++ b/lib/entities/default_settings_migration.dart
@@ -233,6 +233,8 @@ Future<void> defaultSettingsMigration(
         case 36:
           await changeTronCurrentNodeToDefault(sharedPreferences: sharedPreferences, nodes: nodes);
           break;
+        case 37:
+          await fixBtcDerivationPaths(walletInfoSource);
         default:
           break;
       }
@@ -775,6 +777,19 @@ Future<void> changeDefaultMoneroNode(
   }
 }
 
+Future<void> fixBtcDerivationPaths(Box<WalletInfo> walletsInfoSource) async {
+  for (WalletInfo walletInfo in walletsInfoSource.values) {
+    if (walletInfo.type == WalletType.bitcoin ||
+        walletInfo.type == WalletType.bitcoinCash ||
+        walletInfo.type == WalletType.litecoin) {
+      if (walletInfo.derivationInfo?.derivationPath == "m/0'/0") {
+        walletInfo.derivationInfo!.derivationPath = "m/0'";
+        await walletInfo.save();
+      }
+    }
+  }
+}
+
 Future<void> updateBtcNanoWalletInfos(Box<WalletInfo> walletsInfoSource) async {
   for (WalletInfo walletInfo in walletsInfoSource.values) {
     if (walletInfo.type == WalletType.nano || walletInfo.type == WalletType.bitcoin) {
diff --git a/lib/main.dart b/lib/main.dart
index 5bcd9ffdb..46bd7c608 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -202,7 +202,7 @@ Future<void> initializeAppConfigs() async {
     transactionDescriptions: transactionDescriptions,
     secureStorage: secureStorage,
     anonpayInvoiceInfo: anonpayInvoiceInfo,
-    initialMigrationVersion: 36,
+    initialMigrationVersion: 37,
   );
 }
 
diff --git a/lib/view_model/wallet_creation_vm.dart b/lib/view_model/wallet_creation_vm.dart
index f825f0c47..841a88e7e 100644
--- a/lib/view_model/wallet_creation_vm.dart
+++ b/lib/view_model/wallet_creation_vm.dart
@@ -1,3 +1,4 @@
+import 'package:cake_wallet/bitcoin/bitcoin.dart';
 import 'package:cake_wallet/core/wallet_creation_service.dart';
 import 'package:cake_wallet/di.dart';
 import 'package:cake_wallet/entities/background_tasks.dart';
@@ -98,10 +99,7 @@ abstract class WalletCreationVMBase with Store {
         );
       case WalletType.bitcoin:
       case WalletType.litecoin:
-        return DerivationInfo(
-          derivationType: DerivationType.electrum,
-          derivationPath: "m/0'",
-        );
+        return bitcoin!.getElectrumDerivations()[DerivationType.electrum]!.first;
       default:
         return null;
     }
diff --git a/tool/configure.dart b/tool/configure.dart
index fc9bd5b91..e7ad676be 100644
--- a/tool/configure.dart
+++ b/tool/configure.dart
@@ -186,6 +186,7 @@ abstract class Bitcoin {
       {required String mnemonic, required Node node});
   Future<List<DerivationInfo>> getDerivationsFromMnemonic(
       {required String mnemonic, required Node node, String? passphrase});
+  Map<DerivationType, List<DerivationInfo>> getElectrumDerivations();
   Future<void> setAddressType(Object wallet, dynamic option);
   ReceivePageOption getSelectedAddressType(Object wallet);
   List<ReceivePageOption> getBitcoinReceivePageOptions();

From 5b3161fb2958b6dd0fae0249a35b3979999367f3 Mon Sep 17 00:00:00 2001
From: Konstantin Ullrich <konstantinullrich12@gmail.com>
Date: Tue, 18 Jun 2024 02:00:07 -0400
Subject: [PATCH 3/4] Add Recovery Height to Wallet seed page for monero
 (#1470)

---
 cw_monero/lib/monero_wallet.dart           |  2 ++
 lib/monero/cw_monero.dart                  |  6 ++++++
 lib/view_model/wallet_keys_view_model.dart | 19 ++++++++++++-------
 res/values/strings_ar.arb                  |  1 +
 res/values/strings_bg.arb                  |  1 +
 res/values/strings_cs.arb                  |  1 +
 res/values/strings_de.arb                  |  3 ++-
 res/values/strings_en.arb                  |  1 +
 res/values/strings_es.arb                  |  1 +
 res/values/strings_fr.arb                  |  1 +
 res/values/strings_ha.arb                  |  1 +
 res/values/strings_hi.arb                  |  1 +
 res/values/strings_hr.arb                  |  1 +
 res/values/strings_id.arb                  |  1 +
 res/values/strings_it.arb                  |  1 +
 res/values/strings_ja.arb                  |  1 +
 res/values/strings_ko.arb                  |  1 +
 res/values/strings_my.arb                  |  1 +
 res/values/strings_nl.arb                  |  1 +
 res/values/strings_pl.arb                  |  1 +
 res/values/strings_pt.arb                  |  1 +
 res/values/strings_ru.arb                  |  1 +
 res/values/strings_th.arb                  |  1 +
 res/values/strings_tl.arb                  |  1 +
 res/values/strings_tr.arb                  |  1 +
 res/values/strings_uk.arb                  |  1 +
 res/values/strings_ur.arb                  |  1 +
 res/values/strings_yo.arb                  |  1 +
 res/values/strings_zh.arb                  |  1 +
 tool/configure.dart                        |  1 +
 30 files changed, 48 insertions(+), 8 deletions(-)

diff --git a/cw_monero/lib/monero_wallet.dart b/cw_monero/lib/monero_wallet.dart
index c270bb113..8af6b653c 100644
--- a/cw_monero/lib/monero_wallet.dart
+++ b/cw_monero/lib/monero_wallet.dart
@@ -108,6 +108,8 @@ abstract class MoneroWalletBase
       publicSpendKey: monero_wallet.getPublicSpendKey(),
       publicViewKey: monero_wallet.getPublicViewKey());
 
+  int? get restoreHeight => transactionHistory.transactions.values.firstOrNull?.height;
+
   monero_wallet.SyncListener? _listener;
   ReactionDisposer? _onAccountChangeReaction;
   bool _isTransactionUpdating;
diff --git a/lib/monero/cw_monero.dart b/lib/monero/cw_monero.dart
index 959ae92ce..b4d85089a 100644
--- a/lib/monero/cw_monero.dart
+++ b/lib/monero/cw_monero.dart
@@ -244,6 +244,12 @@ class CWMonero extends Monero {
     };
   }
 
+  @override
+  int? getRestoreHeight(Object wallet) {
+    final moneroWallet = wallet as MoneroWallet;
+    return moneroWallet.restoreHeight;
+  }
+
   @override
   Object createMoneroTransactionCreationCredentials(
           {required List<Output> outputs, required TransactionPriority priority}) =>
diff --git a/lib/view_model/wallet_keys_view_model.dart b/lib/view_model/wallet_keys_view_model.dart
index 6b5ae5559..060770273 100644
--- a/lib/view_model/wallet_keys_view_model.dart
+++ b/lib/view_model/wallet_keys_view_model.dart
@@ -1,16 +1,15 @@
-import 'package:cake_wallet/bitcoin/bitcoin.dart';
+import 'package:cake_wallet/generated/i18n.dart';
+import 'package:cake_wallet/haven/haven.dart';
+import 'package:cake_wallet/monero/monero.dart';
 import 'package:cake_wallet/reactions/wallet_connect.dart';
+import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
 import 'package:cake_wallet/store/app_store.dart';
 import 'package:cw_core/transaction_direction.dart';
 import 'package:cw_core/transaction_info.dart';
-import 'package:cw_core/wallet_type.dart';
-import 'package:mobx/mobx.dart';
-import 'package:cake_wallet/generated/i18n.dart';
 import 'package:cw_core/wallet_base.dart';
-import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
-import 'package:cake_wallet/monero/monero.dart';
-import 'package:cake_wallet/haven/haven.dart';
+import 'package:cw_core/wallet_type.dart';
 import 'package:cw_monero/api/wallet.dart' as monero_wallet;
+import 'package:mobx/mobx.dart';
 import 'package:polyseed/polyseed.dart';
 
 part 'wallet_keys_view_model.g.dart';
@@ -83,6 +82,12 @@ abstract class WalletKeysViewModelBase with Store {
                 .toLegacySeed(legacyLang);
         items.add(StandartListItem(title: S.current.wallet_seed_legacy, value: legacySeed));
       }
+
+      final restoreHeight = monero!.getRestoreHeight(_appStore.wallet!);
+      if (restoreHeight != null) {
+        items.add(StandartListItem(
+            title: S.current.wallet_recovery_height, value: restoreHeight.toString()));
+      }
     }
 
     if (_appStore.wallet!.type == WalletType.haven) {
diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb
index fa2747230..db6a4cae2 100644
--- a/res/values/strings_ar.arb
+++ b/res/values/strings_ar.arb
@@ -834,6 +834,7 @@
   "wallet_menu": "قائمة",
   "wallet_name": "اسم المحفظة",
   "wallet_name_exists": "توجد بالفعل محفظة بهذا الاسم. الرجاء اختيار اسم مختلف أو إعادة تسمية المحفظة الأخرى أولاً.",
+  "wallet_recovery_height": "ارتفاع الاسترداد",
   "wallet_restoration_store_incorrect_seed_length": "طول السييد غير صحيح",
   "wallet_seed": "سييد المحفظة",
   "wallet_seed_legacy": "بذرة محفظة قديمة",
diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb
index 430a26134..06132c244 100644
--- a/res/values/strings_bg.arb
+++ b/res/values/strings_bg.arb
@@ -834,6 +834,7 @@
   "wallet_menu": "Меню",
   "wallet_name": "Име на портфейл",
   "wallet_name_exists": "Вече има портфейл с това име. Моля, изберете друго име или преименувайте другия портфейл.",
+  "wallet_recovery_height": "Височина на възстановяване",
   "wallet_restoration_store_incorrect_seed_length": "Грешна дължина на seed-а",
   "wallet_seed": "Seed на портфейла",
   "wallet_seed_legacy": "Наследено портфейл семе",
diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb
index 6a92cb2e5..589f89fd7 100644
--- a/res/values/strings_cs.arb
+++ b/res/values/strings_cs.arb
@@ -834,6 +834,7 @@
   "wallet_menu": "Menu",
   "wallet_name": "Název peněženky",
   "wallet_name_exists": "Peněženka s tímto názvem už existuje. Prosím zvolte si jiný název, nebo nejprve přejmenujte nejprve druhou peněženku.",
+  "wallet_recovery_height": "Výška zotavení",
   "wallet_restoration_store_incorrect_seed_length": "Nesprávná délka seedu",
   "wallet_seed": "Seed peněženky",
   "wallet_seed_legacy": "Starší semeno peněženky",
diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb
index 2e4203edd..a4b816f5b 100644
--- a/res/values/strings_de.arb
+++ b/res/values/strings_de.arb
@@ -837,6 +837,7 @@
   "wallet_menu": "Wallet-Menü",
   "wallet_name": "Walletname",
   "wallet_name_exists": "Wallet mit diesem Namen existiert bereits",
+  "wallet_recovery_height": "Erstellungshöhe",
   "wallet_restoration_store_incorrect_seed_length": "Falsche Seed-Länge",
   "wallet_seed": "Wallet-Seed",
   "wallet_seed_legacy": "Legacy Wallet Seed",
@@ -875,4 +876,4 @@
   "you_will_get": "Konvertieren zu",
   "you_will_send": "Konvertieren von",
   "yy": "YY"
-}
\ No newline at end of file
+}
diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb
index 1b3da32ab..ac82c9e0f 100644
--- a/res/values/strings_en.arb
+++ b/res/values/strings_en.arb
@@ -834,6 +834,7 @@
   "wallet_menu": "Menu",
   "wallet_name": "Wallet name",
   "wallet_name_exists": "A wallet with that name already exists. Please choose a different name or rename the other wallet first.",
+  "wallet_recovery_height": "Recovery Height",
   "wallet_restoration_store_incorrect_seed_length": "Incorrect seed length",
   "wallet_seed": "Wallet seed",
   "wallet_seed_legacy": "Legacy wallet seed",
diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb
index 215cece6e..5fba46830 100644
--- a/res/values/strings_es.arb
+++ b/res/values/strings_es.arb
@@ -835,6 +835,7 @@
   "wallet_menu": "Menú de billetera",
   "wallet_name": "Nombre de la billetera",
   "wallet_name_exists": "Wallet con ese nombre ya ha existido",
+  "wallet_recovery_height": "Altura de recuperación",
   "wallet_restoration_store_incorrect_seed_length": "Longitud de semilla incorrecta",
   "wallet_seed": "Semilla de billetera",
   "wallet_seed_legacy": "Semilla de billetera heredada",
diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb
index 997dbc38c..2477c09b1 100644
--- a/res/values/strings_fr.arb
+++ b/res/values/strings_fr.arb
@@ -834,6 +834,7 @@
   "wallet_menu": "Menu",
   "wallet_name": "Nom du Portefeuille (Wallet)",
   "wallet_name_exists": "Un portefeuille (wallet) portant ce nom existe déjà",
+  "wallet_recovery_height": "Hauteur de récupération",
   "wallet_restoration_store_incorrect_seed_length": "Longueur de phrase secrète (seed) incorrecte",
   "wallet_seed": "Phrase secrète (seed) du portefeuille (wallet)",
   "wallet_seed_legacy": "Graine de portefeuille hérité",
diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb
index 478bc458d..c96568a76 100644
--- a/res/values/strings_ha.arb
+++ b/res/values/strings_ha.arb
@@ -836,6 +836,7 @@
   "wallet_menu": "Menu",
   "wallet_name": "Sunan walat",
   "wallet_name_exists": "Wallet mai wannan sunan ya riga ya wanzu. Da fatan za a zaɓi wani suna daban ko sake suna ɗayan walat tukuna.",
+  "wallet_recovery_height": "Mai Tsaro",
   "wallet_restoration_store_incorrect_seed_length": "kalmar sirrin iri ba daidai ba",
   "wallet_seed": "kalmar sirri na walat",
   "wallet_seed_legacy": "Tallarin walat walat",
diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb
index 4f3a77fdb..ef740b4d6 100644
--- a/res/values/strings_hi.arb
+++ b/res/values/strings_hi.arb
@@ -836,6 +836,7 @@
   "wallet_menu": "बटुआ मेनू",
   "wallet_name": "बटुए का नाम",
   "wallet_name_exists": "उस नाम वाला वॉलेट पहले से मौजूद है",
+  "wallet_recovery_height": "वसूली ऊंचाई",
   "wallet_restoration_store_incorrect_seed_length": "गलत बीज की लंबाई",
   "wallet_seed": "बटुआ का बीज",
   "wallet_seed_legacy": "विरासत बटुए बीज",
diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb
index faef9cd78..295a01165 100644
--- a/res/values/strings_hr.arb
+++ b/res/values/strings_hr.arb
@@ -834,6 +834,7 @@
   "wallet_menu": "Izbornik",
   "wallet_name": "Ime novčanika",
   "wallet_name_exists": "Novčanik s tim nazivom već postoji",
+  "wallet_recovery_height": "Visina oporavka",
   "wallet_restoration_store_incorrect_seed_length": "Netočna dužina pristupnog izraza",
   "wallet_seed": "Pristupni izraz novčanika",
   "wallet_seed_legacy": "Sjeme naslijeđenog novčanika",
diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb
index e718f24da..8b28e928f 100644
--- a/res/values/strings_id.arb
+++ b/res/values/strings_id.arb
@@ -837,6 +837,7 @@
   "wallet_menu": "Menu",
   "wallet_name": "Nama Dompet",
   "wallet_name_exists": "Nama dompet sudah ada. Silakan pilih nama yang berbeda atau ganti nama dompet yang lain terlebih dahulu.",
+  "wallet_recovery_height": "Tinggi pemulihan",
   "wallet_restoration_store_incorrect_seed_length": "Panjang seed yang salah",
   "wallet_seed": "Seed dompet",
   "wallet_seed_legacy": "Biji dompet warisan",
diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb
index 6a25ad9e0..b1bd7cd6d 100644
--- a/res/values/strings_it.arb
+++ b/res/values/strings_it.arb
@@ -837,6 +837,7 @@
   "wallet_menu": "Menù",
   "wallet_name": "Nome del Portafoglio",
   "wallet_name_exists": "Il portafoglio con quel nome è già esistito",
+  "wallet_recovery_height": "Altezza di recupero",
   "wallet_restoration_store_incorrect_seed_length": "Lunghezza seme non corretta",
   "wallet_seed": "Seme Portafoglio",
   "wallet_seed_legacy": "Seme di portafoglio legacy",
diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb
index 56786cabc..5803b86d5 100644
--- a/res/values/strings_ja.arb
+++ b/res/values/strings_ja.arb
@@ -835,6 +835,7 @@
   "wallet_menu": "ウォレットメニュー",
   "wallet_name": "ウォレット名",
   "wallet_name_exists": "その名前のウォレットはすでに存在しています",
+  "wallet_recovery_height": "回復の高さ",
   "wallet_restoration_store_incorrect_seed_length": "誤ったシード長s",
   "wallet_seed": "ウォレットシード",
   "wallet_seed_legacy": "レガシーウォレットシード",
diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb
index 5de972a6e..874ec2c27 100644
--- a/res/values/strings_ko.arb
+++ b/res/values/strings_ko.arb
@@ -835,6 +835,7 @@
   "wallet_menu": "월렛 메뉴",
   "wallet_name": "지갑 이름",
   "wallet_name_exists": "해당 이름의 지갑이 이미 존재합니다.",
+  "wallet_recovery_height": "복구 높이",
   "wallet_restoration_store_incorrect_seed_length": "시드 길이가 잘못되었습니다",
   "wallet_seed": "지갑 시드",
   "wallet_seed_legacy": "레거시 지갑 시드",
diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb
index 497e1bb0c..890362fcd 100644
--- a/res/values/strings_my.arb
+++ b/res/values/strings_my.arb
@@ -834,6 +834,7 @@
   "wallet_menu": "မီနူး",
   "wallet_name": "ပိုက်ဆံအိတ်နာမည",
   "wallet_name_exists": "ထိုအမည်ဖြင့် ပိုက်ဆံအိတ်တစ်ခု ရှိနှင့်ပြီးဖြစ်သည်။ အခြားအမည်တစ်ခုကို ရွေးပါ သို့မဟုတ် အခြားပိုက်ဆံအိတ်ကို ဦးစွာ အမည်ပြောင်းပါ။",
+  "wallet_recovery_height": "ပြန်လည်ထူထောင်ရေးအမြင့်",
   "wallet_restoration_store_incorrect_seed_length": "မျိုးစေ့အရှည် မမှန်ပါ။",
   "wallet_seed": "ပိုက်ဆံအိတ်စေ့",
   "wallet_seed_legacy": "အမွေအနှစ်ပိုက်ဆံအိတ်မျိုးစေ့",
diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb
index 1bc1f8cd7..25b7f6b3a 100644
--- a/res/values/strings_nl.arb
+++ b/res/values/strings_nl.arb
@@ -835,6 +835,7 @@
   "wallet_menu": "Portemonnee-menu",
   "wallet_name": "Portemonnee naam",
   "wallet_name_exists": "Portemonnee met die naam bestaat al",
+  "wallet_recovery_height": "Herstelhoogte",
   "wallet_restoration_store_incorrect_seed_length": "Onjuiste zaadlengte",
   "wallet_seed": "Portemonnee zaad",
   "wallet_seed_legacy": "Legacy portemonnee zaad",
diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb
index ff8826c1e..1567a0841 100644
--- a/res/values/strings_pl.arb
+++ b/res/values/strings_pl.arb
@@ -834,6 +834,7 @@
   "wallet_menu": "Menu portfela",
   "wallet_name": "Nazwa portfela",
   "wallet_name_exists": "Portfel o tej nazwie już istnieje",
+  "wallet_recovery_height": "Wysokość odzysku",
   "wallet_restoration_store_incorrect_seed_length": "Nieprawidłowa długość frazy seed",
   "wallet_seed": "Seed portfela",
   "wallet_seed_legacy": "Dziedziczne ziarno portfela",
diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb
index 67ce2980a..272c0862e 100644
--- a/res/values/strings_pt.arb
+++ b/res/values/strings_pt.arb
@@ -837,6 +837,7 @@
   "wallet_menu": "Menu",
   "wallet_name": "Nome da carteira",
   "wallet_name_exists": "A carteira com esse nome já existe",
+  "wallet_recovery_height": "Altura de recuperação",
   "wallet_restoration_store_incorrect_seed_length": "Comprimento de semente incorreto",
   "wallet_seed": "Semente de carteira",
   "wallet_seed_legacy": "Semente de carteira herdada",
diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb
index 673f1472d..a8943db97 100644
--- a/res/values/strings_ru.arb
+++ b/res/values/strings_ru.arb
@@ -835,6 +835,7 @@
   "wallet_menu": "Меню кошелька",
   "wallet_name": "Имя кошелька",
   "wallet_name_exists": "Кошелек с таким именем уже существует",
+  "wallet_recovery_height": "Высота восстановления",
   "wallet_restoration_store_incorrect_seed_length": "Неверная длина мнемонической фразы",
   "wallet_seed": "Мнемоническая фраза кошелька",
   "wallet_seed_legacy": "Наследие семя кошелька",
diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb
index 1779b9da1..c4d282761 100644
--- a/res/values/strings_th.arb
+++ b/res/values/strings_th.arb
@@ -834,6 +834,7 @@
   "wallet_menu": "เมนู",
   "wallet_name": "ชื่อกระเป๋า",
   "wallet_name_exists": "กระเป๋าที่มีชื่อนี้มีอยู่แล้ว โปรดเลือกชื่ออื่นหรือเปลี่ยนชื่อกระเป๋าอื่นก่อน",
+  "wallet_recovery_height": "ความสูงของการกู้คืน",
   "wallet_restoration_store_incorrect_seed_length": "ความยาวของซีดไม่ถูกต้อง",
   "wallet_seed": "ซีดของกระเป๋า",
   "wallet_seed_legacy": "เมล็ดกระเป๋าเงินมรดก",
diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb
index e358d6daf..775ab4c3d 100644
--- a/res/values/strings_tl.arb
+++ b/res/values/strings_tl.arb
@@ -834,6 +834,7 @@
   "wallet_menu": "Menu",
   "wallet_name": "Pangalan ng Wallet",
   "wallet_name_exists": "Ang isang pitaka na may pangalang iyon ay mayroon na. Mangyaring pumili ng ibang pangalan o palitan muna ang iba pang pitaka.",
+  "wallet_recovery_height": "Taas ng pagbawi",
   "wallet_restoration_store_incorrect_seed_length": "Maling haba ng binhi",
   "wallet_seed": "SEED ng Wallet",
   "wallet_seed_legacy": "Legacy wallet seed",
diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb
index 76bd79d8a..239a1aa2e 100644
--- a/res/values/strings_tr.arb
+++ b/res/values/strings_tr.arb
@@ -834,6 +834,7 @@
   "wallet_menu": "Menü",
   "wallet_name": "Cüzdan ismi",
   "wallet_name_exists": "Bu isimde bir cüzdan zaten mevcut. Lütfen farklı bir isim seç veya önce diğer cüzdanı yeniden adlandır.",
+  "wallet_recovery_height": "Kurtarma Yüksekliği",
   "wallet_restoration_store_incorrect_seed_length": "Yanlış tohum uzunluğu",
   "wallet_seed": "Cüzdan tohumu",
   "wallet_seed_legacy": "Eski cüzdan tohumu",
diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb
index e1d470e1e..3a45752d6 100644
--- a/res/values/strings_uk.arb
+++ b/res/values/strings_uk.arb
@@ -835,6 +835,7 @@
   "wallet_menu": "Меню гаманця",
   "wallet_name": "Ім'я гаманця",
   "wallet_name_exists": "Гаманець з такою назвою вже існує",
+  "wallet_recovery_height": "Висота відновлення",
   "wallet_restoration_store_incorrect_seed_length": "Невірна довжина мнемонічної фрази",
   "wallet_seed": "Мнемонічна фраза гаманця",
   "wallet_seed_legacy": "Спадець насіння гаманця",
diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb
index 02c5216ef..2ab1f927b 100644
--- a/res/values/strings_ur.arb
+++ b/res/values/strings_ur.arb
@@ -836,6 +836,7 @@
   "wallet_menu": "مینو",
   "wallet_name": "بٹوے کا نام",
   "wallet_name_exists": "اس نام کا پرس پہلے سے موجود ہے۔ براہ کرم ایک مختلف نام منتخب کریں یا پہلے دوسرے بٹوے کا نام تبدیل کریں۔",
+  "wallet_recovery_height": "بحالی کی اونچائی",
   "wallet_restoration_store_incorrect_seed_length": "غلط بیج کی لمبائی",
   "wallet_seed": "بٹوے کا بیج",
   "wallet_seed_legacy": "میراثی پرس کا بیج",
diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb
index 221b189e1..f9751f9f1 100644
--- a/res/values/strings_yo.arb
+++ b/res/values/strings_yo.arb
@@ -835,6 +835,7 @@
   "wallet_menu": "Mẹ́nù",
   "wallet_name": "Orúkọ àpamọ́wọ́",
   "wallet_name_exists": "Ẹ ti ní àpamọ́wọ́ pẹ̀lú orúkọ̀ yẹn. Ẹ jọ̀wọ́ yàn orúkọ̀ tó yàtọ̀ tàbí pààrọ̀ orúkọ ti àpamọ́wọ́ tẹ́lẹ̀.",
+  "wallet_recovery_height": "Iga Imularada",
   "wallet_restoration_store_incorrect_seed_length": "Gígùn hóró tí a máa ń lò kọ́ ni èyí",
   "wallet_seed": "Hóró àpamọ́wọ́",
   "wallet_seed_legacy": "Irugbin akole",
diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb
index d98801cb2..f3b8ee176 100644
--- a/res/values/strings_zh.arb
+++ b/res/values/strings_zh.arb
@@ -834,6 +834,7 @@
   "wallet_menu": "钱包菜单",
   "wallet_name": "钱包名称",
   "wallet_name_exists": "同名的钱包已经存在",
+  "wallet_recovery_height": "恢复高度",
   "wallet_restoration_store_incorrect_seed_length": "种子长度错误",
   "wallet_seed": "钱包种子",
   "wallet_seed_legacy": "旧的钱包种子",
diff --git a/tool/configure.dart b/tool/configure.dart
index e7ad676be..b1018a5a0 100644
--- a/tool/configure.dart
+++ b/tool/configure.dart
@@ -363,6 +363,7 @@ abstract class Monero {
   WalletCredentials createMoneroRestoreWalletFromSeedCredentials({required String name, required String password, required int height, required String mnemonic});
   WalletCredentials createMoneroNewWalletCredentials({required String name, required String language, required bool isPolyseed, String password});
   Map<String, String> getKeys(Object wallet);
+  int? getRestoreHeight(Object wallet);
   Object createMoneroTransactionCreationCredentials({required List<Output> outputs, required TransactionPriority priority});
   Object createMoneroTransactionCreationCredentialsRaw({required List<OutputInfo> outputs, required TransactionPriority priority});
   String formatterMoneroAmountToString({required int amount});

From ab293548d23f848894c069e607ca2bf095cfaa06 Mon Sep 17 00:00:00 2001
From: tuxsudo <tuxsudo@tux.pizza>
Date: Tue, 18 Jun 2024 16:16:39 +0000
Subject: [PATCH 4/4] Remove emotes from issue templates

---
 .github/ISSUE_TEMPLATE/{bug-report-🪲-.md => bug-report.md}       | 0
 ...nhancement-request-✨.md => feature-or-enhancement-request.md} | 0
 2 files changed, 0 insertions(+), 0 deletions(-)
 rename .github/ISSUE_TEMPLATE/{bug-report-🪲-.md => bug-report.md} (100%)
 rename .github/ISSUE_TEMPLATE/{feature-or-enhancement-request-✨.md => feature-or-enhancement-request.md} (100%)

diff --git a/.github/ISSUE_TEMPLATE/bug-report-🪲-.md b/.github/ISSUE_TEMPLATE/bug-report.md
similarity index 100%
rename from .github/ISSUE_TEMPLATE/bug-report-🪲-.md
rename to .github/ISSUE_TEMPLATE/bug-report.md
diff --git a/.github/ISSUE_TEMPLATE/feature-or-enhancement-request-✨.md b/.github/ISSUE_TEMPLATE/feature-or-enhancement-request.md
similarity index 100%
rename from .github/ISSUE_TEMPLATE/feature-or-enhancement-request-✨.md
rename to .github/ISSUE_TEMPLATE/feature-or-enhancement-request.md