From f43aeadc3f8ed5296e320ed97d572c5558d29646 Mon Sep 17 00:00:00 2001
From: detherminal <76167420+detherminal@users.noreply.github.com>
Date: Mon, 12 Jun 2023 22:03:32 +0300
Subject: [PATCH 01/39] feat: add xtz

---
 lib/models/isar/stack_theme.dart              |   9 +
 .../add_edit_node_view.dart                   |   1 +
 lib/services/coins/coin_service.dart          |  10 +
 lib/services/coins/tezos/tezos_wallet.dart    | 314 ++++++++++++++++++
 lib/themes/coin_icon_provider.dart            |   2 +
 lib/themes/coin_image_provider.dart           |   4 +
 lib/themes/color_theme.dart                   |   3 +
 lib/themes/stack_colors.dart                  |   2 +
 lib/utilities/address_utils.dart              |   2 +
 lib/utilities/block_explorers.dart            |   2 +
 lib/utilities/constants.dart                  |  11 +
 lib/utilities/default_nodes.dart              |  18 +-
 lib/utilities/enums/coin_enum.dart            |  21 ++
 .../enums/derive_path_type_enum.dart          |   1 +
 pubspec.lock                                  |  80 ++++-
 pubspec.yaml                                  |   2 +
 16 files changed, 477 insertions(+), 5 deletions(-)
 create mode 100644 lib/services/coins/tezos/tezos_wallet.dart

diff --git a/lib/models/isar/stack_theme.dart b/lib/models/isar/stack_theme.dart
index 5809e4443..67fbb0ab7 100644
--- a/lib/models/isar/stack_theme.dart
+++ b/lib/models/isar/stack_theme.dart
@@ -1902,6 +1902,7 @@ class ThemeAssets implements IThemeAssets {
   late final String wownero;
   late final String namecoin;
   late final String particl;
+  late final String tezos;
   late final String bitcoinImage;
   late final String bitcoincashImage;
   late final String dogecoinImage;
@@ -1913,6 +1914,7 @@ class ThemeAssets implements IThemeAssets {
   late final String wowneroImage;
   late final String namecoinImage;
   late final String particlImage;
+  late final String tezosImage;
   late final String bitcoinImageSecondary;
   late final String bitcoincashImageSecondary;
   late final String dogecoinImageSecondary;
@@ -1924,6 +1926,7 @@ class ThemeAssets implements IThemeAssets {
   late final String wowneroImageSecondary;
   late final String namecoinImageSecondary;
   late final String particlImageSecondary;
+  late final String tezosImageSecondary;
   @override
   late final String? loadingGif;
   @override
@@ -1997,6 +2000,8 @@ class ThemeAssets implements IThemeAssets {
           "$applicationThemesDirectoryPath/$themeId/assets/${json["namecoin"] as String}"
       ..particl =
           "$applicationThemesDirectoryPath/$themeId/assets/${json["particl"] as String}"
+      ..tezos =
+          "$applicationThemesDirectoryPath/$themeId/assets/${json["bitcoin"] as String}" // TODO: change to tezos
       ..bitcoinImage =
           "$applicationThemesDirectoryPath/$themeId/assets/${json["bitcoin_image"] as String}"
       ..bitcoincashImage =
@@ -2019,6 +2024,8 @@ class ThemeAssets implements IThemeAssets {
           "$applicationThemesDirectoryPath/$themeId/assets/${json["namecoin_image"] as String}"
       ..particlImage =
           "$applicationThemesDirectoryPath/$themeId/assets/${json["particl_image"] as String}"
+      ..tezosImage =
+          "$applicationThemesDirectoryPath/$themeId/assets/${json["bitcoin_image"] as String}" // TODO: change to tezos
       ..bitcoinImageSecondary =
           "$applicationThemesDirectoryPath/$themeId/assets/${json["bitcoin_image_secondary"] as String}"
       ..bitcoincashImageSecondary =
@@ -2041,6 +2048,8 @@ class ThemeAssets implements IThemeAssets {
           "$applicationThemesDirectoryPath/$themeId/assets/${json["namecoin_image_secondary"] as String}"
       ..particlImageSecondary =
           "$applicationThemesDirectoryPath/$themeId/assets/${json["particl_image_secondary"] as String}"
+      ..tezosImageSecondary =
+          "$applicationThemesDirectoryPath/$themeId/assets/${json["bitcoin_image_secondary"] as String}" // TODO: change to tezos
       ..loadingGif = json["loading_gif"] is String
           ? "$applicationThemesDirectoryPath/$themeId/assets/${json["loading_gif"] as String}"
           : null
diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
index 1ff1a1359..b29f4718c 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
@@ -711,6 +711,7 @@ class _NodeFormState extends ConsumerState<NodeForm> {
       case Coin.namecoin:
       case Coin.bitcoincash:
       case Coin.particl:
+      case Coin.tezos:
       case Coin.bitcoinTestNet:
       case Coin.litecoinTestNet:
       case Coin.bitcoincashTestnet:
diff --git a/lib/services/coins/coin_service.dart b/lib/services/coins/coin_service.dart
index 48fa59630..a6d1b023b 100644
--- a/lib/services/coins/coin_service.dart
+++ b/lib/services/coins/coin_service.dart
@@ -15,6 +15,7 @@ import 'package:stackwallet/services/coins/litecoin/litecoin_wallet.dart';
 import 'package:stackwallet/services/coins/monero/monero_wallet.dart';
 import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart';
 import 'package:stackwallet/services/coins/particl/particl_wallet.dart';
+import 'package:stackwallet/services/coins/tezos/tezos_wallet.dart';
 import 'package:stackwallet/services/coins/wownero/wownero_wallet.dart';
 import 'package:stackwallet/services/transaction_notification_tracker.dart';
 import 'package:stackwallet/utilities/amount/amount.dart';
@@ -204,6 +205,15 @@ abstract class CoinServiceAPI {
             cachedClient: cachedClient,
             tracker: tracker);
 
+      case Coin.tezos:
+        return TezosWallet(
+          walletId: walletId,
+          walletName: walletName,
+          coin: coin,
+          secureStore: secureStorageInterface,
+          tracker: tracker,
+        );
+
       case Coin.wownero:
         return WowneroWallet(
           walletId: walletId,
diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart
new file mode 100644
index 000000000..fca4eabc2
--- /dev/null
+++ b/lib/services/coins/tezos/tezos_wallet.dart
@@ -0,0 +1,314 @@
+import 'dart:async';
+
+import 'package:http/http.dart';
+import 'package:stackwallet/models/balance.dart';
+import 'package:stackwallet/models/isar/models/blockchain_data/address.dart';
+import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart';
+import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart';
+import 'package:stackwallet/models/paymint/fee_object_model.dart';
+import 'package:stackwallet/services/coins/coin_service.dart';
+import 'package:stackwallet/services/node_service.dart';
+import 'package:stackwallet/utilities/amount/amount.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
+import 'package:stackwallet/utilities/default_nodes.dart';
+
+import 'package:tezart/tezart.dart';
+
+import '../../../db/isar/main_db.dart';
+import '../../../models/node_model.dart';
+import '../../../utilities/flutter_secure_storage_interface.dart';
+import '../../../utilities/logger.dart';
+import '../../../utilities/prefs.dart';
+import '../../mixins/wallet_cache.dart';
+import '../../mixins/wallet_db.dart';
+import '../../transaction_notification_tracker.dart';
+
+const int MINIMUM_CONFIRMATIONS = 1;
+
+class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
+  TezosWallet({
+    required String walletId,
+    required String walletName,
+    required Coin coin,
+    required SecureStorageInterface secureStore,
+    required TransactionNotificationTracker tracker,
+    MainDB? mockableOverride,
+  }) {
+    txTracker = tracker;
+    _walletId = walletId;
+    _walletName = walletName;
+    _coin = coin;
+    _secureStore = secureStore;
+    initCache(walletId, coin);
+    initWalletDB(mockableOverride: mockableOverride);
+  }
+
+  NodeModel? _xtzNode;
+
+  NodeModel getCurrentNode() {
+    return _xtzNode ?? NodeService(secureStorageInterface: _secureStore).getPrimaryNodeFor(coin: Coin.tezos) ?? DefaultNodes.getNodeFor(Coin.tezos);
+  }
+
+  @override
+  String get walletId => _walletId;
+  late String _walletId;
+
+  @override
+  String get walletName => _walletName;
+  late String _walletName;
+
+  @override
+  set walletName(String name) => _walletName = name;
+
+  @override
+  set isFavorite(bool markFavorite) {
+    _isFavorite = markFavorite;
+    updateCachedIsFavorite(markFavorite);
+  }
+
+  @override
+  bool get isFavorite => _isFavorite ??= getCachedIsFavorite();
+  bool? _isFavorite;
+
+  @override
+  Coin get coin => _coin;
+  late Coin _coin;
+
+  late SecureStorageInterface _secureStore;
+  late final TransactionNotificationTracker txTracker;
+  final _prefs = Prefs.instance;
+
+  Timer? timer;
+  bool _shouldAutoSync = false;
+
+  @override
+  bool get shouldAutoSync => _shouldAutoSync;
+
+  @override
+  set shouldAutoSync(bool shouldAutoSync) {
+    if (_shouldAutoSync != shouldAutoSync) {
+      _shouldAutoSync = shouldAutoSync;
+      if (!shouldAutoSync) {
+        timer?.cancel();
+        timer = null;
+      } else {
+        refresh();
+      }
+    }
+  }
+
+  @override
+  Balance get balance => _balance ??= getCachedBalance();
+  Balance? _balance;
+
+  @override
+  Future<String> confirmSend({required Map<String, dynamic> txData}) {
+    // TODO: implement confirmSend,
+    // NOTE FROM DETHERMINAL: I couldnt write this function because I dont have any tezos to test with
+    throw UnimplementedError();
+  }
+
+  @override
+  Future<String> get currentReceivingAddress async {
+    var mneString = await mnemonicString;
+    if (mneString == null) {
+      throw Exception("No mnemonic found!");
+    }
+    return Future.value(Keystore.fromMnemonic(mneString).address);
+  }
+
+  @override
+  Future<Amount> estimateFeeFor(Amount amount, int feeRate) {
+    // TODO: implement estimateFeeFor
+    throw UnimplementedError();
+  }
+
+  @override
+  Future<void> exit() {
+    _hasCalledExit = true;
+    return Future.value();
+  }
+
+  @override
+  // TODO: implement fees
+  Future<FeeObject> get fees => throw UnimplementedError();
+
+  @override
+  Future<void> fullRescan(int maxUnusedAddressGap, int maxNumberOfIndexesToCheck) {
+    // TODO: implement fullRescan
+    throw UnimplementedError();
+  }
+
+  @override
+  Future<bool> generateNewAddress() {
+    // TODO: implement generateNewAddress
+    throw UnimplementedError();
+  }
+
+  @override
+  bool get hasCalledExit => _hasCalledExit;
+  bool _hasCalledExit = false;
+
+  @override
+  Future<void> initializeExisting() async {
+    await _prefs.init();
+  }
+
+  @override
+  Future<void> initializeNew() async {
+    var newKeystore = Keystore.random();
+    await _secureStore.write(
+      key: '${_walletId}_mnemonic',
+      value: newKeystore.mnemonic,
+    );
+    await _secureStore.write(
+      key: '${_walletId}_mnemonicPassphrase',
+      value: "",
+    );
+
+    final address = Address(
+        walletId: walletId,
+        value: newKeystore.address,
+        publicKey: [], // TODO: Add public key
+        derivationIndex: 0,
+        derivationPath: null,
+        type: AddressType.unknown,
+        subType: AddressSubType.unknown,
+    );
+
+    await db.putAddress(address);
+
+    await Future.wait([
+      updateCachedId(walletId),
+      updateCachedIsFavorite(false),
+    ]);
+  }
+
+  @override
+  bool get isConnected => _isConnected;
+  bool _isConnected = false;
+
+  @override
+  bool get isRefreshing => refreshMutex;
+  bool refreshMutex = false;
+
+  @override
+  // TODO: implement maxFee
+  Future<int> get maxFee => throw UnimplementedError();
+
+  @override
+  Future<List<String>> get mnemonic async {
+    final mnemonic = await mnemonicString;
+    final mnemonicPassphrase = await this.mnemonicPassphrase;
+    if (mnemonic == null) {
+      throw Exception("No mnemonic found!");
+    }
+    if (mnemonicPassphrase == null) {
+      throw Exception("No mnemonic passphrase found!");
+    }
+    return mnemonic.split(" ");
+  }
+
+  @override
+  Future<String?> get mnemonicPassphrase => _secureStore.read(key: '${_walletId}_mnemonicPassphrase');
+
+  @override
+  Future<String?> get mnemonicString => _secureStore.read(key: '${_walletId}_mnemonic');
+
+  @override
+  Future<Map<String, dynamic>> prepareSend({required String address, required Amount amount, Map<String, dynamic>? args}) {
+    // TODO: implement prepareSend
+    // NOTE FROM DETHERMINAL: I couldnt write this function because I dont have any tezos to test with
+    throw UnimplementedError();
+  }
+
+  @override
+  Future<void> recoverFromMnemonic({required String mnemonic, String? mnemonicPassphrase, required int maxUnusedAddressGap, required int maxNumberOfIndexesToCheck, required int height}) async {
+    if ((await mnemonicString) != null ||
+        (await this.mnemonicPassphrase) != null) {
+      throw Exception("Attempted to overwrite mnemonic on restore!");
+    }
+    await _secureStore.write(
+        key: '${_walletId}_mnemonic', value: mnemonic.trim());
+    await _secureStore.write(
+      key: '${_walletId}_mnemonicPassphrase',
+      value: mnemonicPassphrase ?? "",
+    );
+
+    final address = Address(
+        walletId: walletId,
+        value: Keystore.fromMnemonic(mnemonic).address,
+        publicKey: [], // TODO: Add public key
+        derivationIndex: 0,
+        derivationPath: null,
+        type: AddressType.unknown,
+        subType: AddressSubType.unknown,
+    );
+
+    await db.putAddress(address);
+
+    await Future.wait([
+      updateCachedId(walletId),
+      updateCachedIsFavorite(false),
+    ]);
+  }
+
+  Future<void> updateBalance() async {
+    var api = "https://api.mainnet.tzkt.io/v1/accounts/${await currentReceivingAddress}/balance"; // TODO: Can we use current node instead of this?
+    var theBalance = await get(Uri.parse(api)).then((value) => value.body);
+    Logging.instance.log("Balance for ${await currentReceivingAddress}: $theBalance", level: LogLevel.Info);
+    var balanceInAmount = Amount(rawValue: BigInt.parse(theBalance.toString()), fractionDigits: 6);
+    _balance = Balance(
+      total: balanceInAmount,
+      spendable: balanceInAmount,
+      blockedTotal: Amount(rawValue: BigInt.parse("0"), fractionDigits: 6),
+      pendingSpendable: Amount(rawValue: BigInt.parse("0"), fractionDigits: 6),
+    );
+    await updateCachedBalance(_balance!);
+  }
+
+  @override
+  Future<void> refresh() {
+    updateBalance();
+    return Future.value();
+  }
+
+  @override
+  int get storedChainHeight => getCachedChainHeight();
+
+  @override
+  Future<bool> testNetworkConnection() {
+    // TODO: implement testNetworkConnection
+    throw UnimplementedError();
+  }
+
+  @override
+  // TODO: implement transactions
+  Future<List<Transaction>> get transactions async {
+    // TODO: Maybe we can use this -> https://api.tzkt.io/#operation/Accounts_GetBalanceHistory
+  }
+
+  @override
+  Future<void> updateNode(bool shouldRefresh) async {
+    _xtzNode = NodeService(secureStorageInterface: _secureStore).getPrimaryNodeFor(coin: coin) ?? DefaultNodes.getNodeFor(coin);
+
+    if (shouldRefresh) {
+      await refresh();
+    }
+  }
+
+  @override
+  Future<void> updateSentCachedTxData(Map<String, dynamic> txData) {
+    // TODO: implement updateSentCachedTxData
+    throw UnimplementedError();
+  }
+
+  @override
+  // TODO: implement utxos
+  Future<List<UTXO>> get utxos => throw UnimplementedError();
+
+  @override
+  bool validateAddress(String address) {
+    return RegExp(r"^tz[1-9A-HJ-NP-Za-km-z]{34}$").hasMatch(address);
+  }
+}
diff --git a/lib/themes/coin_icon_provider.dart b/lib/themes/coin_icon_provider.dart
index 6c17969e6..3792560e6 100644
--- a/lib/themes/coin_icon_provider.dart
+++ b/lib/themes/coin_icon_provider.dart
@@ -35,6 +35,8 @@ final coinIconProvider = Provider.family<String, Coin>((ref, coin) {
         return assets.namecoin;
       case Coin.particl:
         return assets.particl;
+      case Coin.tezos:
+        return assets.tezos;
       case Coin.ethereum:
         return assets.ethereum;
     }
diff --git a/lib/themes/coin_image_provider.dart b/lib/themes/coin_image_provider.dart
index 239e1d1cb..3de9ab40a 100644
--- a/lib/themes/coin_image_provider.dart
+++ b/lib/themes/coin_image_provider.dart
@@ -31,6 +31,8 @@ final coinImageProvider = Provider.family<String, Coin>((ref, coin) {
         return assets.namecoinImage;
       case Coin.particl:
         return assets.particlImage;
+      case Coin.tezos:
+        return assets.tezosImage;
       case Coin.bitcoinTestNet:
         return assets.bitcoinImage;
       case Coin.bitcoincashTestnet:
@@ -75,6 +77,8 @@ final coinImageSecondaryProvider = Provider.family<String, Coin>((ref, coin) {
         return assets.namecoinImageSecondary;
       case Coin.particl:
         return assets.particlImageSecondary;
+      case Coin.tezos:
+        return assets.tezosImageSecondary;
       case Coin.bitcoinTestNet:
         return assets.bitcoinImageSecondary;
       case Coin.bitcoincashTestnet:
diff --git a/lib/themes/color_theme.dart b/lib/themes/color_theme.dart
index b4f00adcf..7946139c3 100644
--- a/lib/themes/color_theme.dart
+++ b/lib/themes/color_theme.dart
@@ -18,6 +18,7 @@ class CoinThemeColorDefault {
   Color get namecoin => const Color(0xFF91B1E1);
   Color get wownero => const Color(0xFFED80C1);
   Color get particl => const Color(0xFF8175BD);
+  Color get tezos => const Color(0xFF0F61FF);
 
   Color forCoin(Coin coin) {
     switch (coin) {
@@ -50,6 +51,8 @@ class CoinThemeColorDefault {
         return wownero;
       case Coin.particl:
         return particl;
+      case Coin.tezos:
+        return tezos;
     }
   }
 }
diff --git a/lib/themes/stack_colors.dart b/lib/themes/stack_colors.dart
index 6717615b1..8f5dbbe15 100644
--- a/lib/themes/stack_colors.dart
+++ b/lib/themes/stack_colors.dart
@@ -1697,6 +1697,8 @@ class StackColors extends ThemeExtension<StackColors> {
         return _coin.wownero;
       case Coin.particl:
         return _coin.particl;
+      case Coin.tezos:
+        return _coin.tezos;
     }
   }
 
diff --git a/lib/utilities/address_utils.dart b/lib/utilities/address_utils.dart
index 44850bc65..a151abbdf 100644
--- a/lib/utilities/address_utils.dart
+++ b/lib/utilities/address_utils.dart
@@ -74,6 +74,8 @@ class AddressUtils {
         return Address.validateAddress(address, namecoin, namecoin.bech32!);
       case Coin.particl:
         return Address.validateAddress(address, particl);
+      case Coin.tezos:
+        return RegExp(r"^tz[1-9A-HJ-NP-Za-km-z]{34}$").hasMatch(address);
       case Coin.bitcoinTestNet:
         return Address.validateAddress(address, testnet);
       case Coin.litecoinTestNet:
diff --git a/lib/utilities/block_explorers.dart b/lib/utilities/block_explorers.dart
index cf0628fd2..4f4228e27 100644
--- a/lib/utilities/block_explorers.dart
+++ b/lib/utilities/block_explorers.dart
@@ -43,6 +43,8 @@ Uri getDefaultBlockExplorerUrlFor({
       return Uri.parse("https://chainz.cryptoid.info/nmc/tx.dws?$txid.htm");
     case Coin.particl:
       return Uri.parse("https://chainz.cryptoid.info/part/tx.dws?$txid.htm");
+    case Coin.tezos:
+      return Uri.parse("https://tzstats.com/$txid");
   }
 }
 
diff --git a/lib/utilities/constants.dart b/lib/utilities/constants.dart
index b3295b3c8..2fdacc64b 100644
--- a/lib/utilities/constants.dart
+++ b/lib/utilities/constants.dart
@@ -29,12 +29,14 @@ abstract class Constants {
   static const int _satsPerCoinECash = 100;
   static const int _satsPerCoinMonero = 1000000000000;
   static const int _satsPerCoinWownero = 100000000000;
+  static const int _satsPerCoinTezos = 1000000;
   static const int _satsPerCoin = 100000000;
   static const int _decimalPlaces = 8;
   static const int _decimalPlacesWownero = 11;
   static const int _decimalPlacesMonero = 12;
   static const int _decimalPlacesEthereum = 18;
   static const int _decimalPlacesECash = 2;
+  static const int _decimalPlacesTezos = 6;
 
   static const int notificationsMax = 0xFFFFFFFF;
   static const Duration networkAliveTimerDuration = Duration(seconds: 10);
@@ -76,6 +78,9 @@ abstract class Constants {
 
       case Coin.eCash:
         return _satsPerCoinECash;
+
+      case Coin.tezos:
+        return _satsPerCoinTezos;
     }
   }
 
@@ -107,6 +112,9 @@ abstract class Constants {
 
       case Coin.eCash:
         return _decimalPlacesECash;
+
+      case Coin.tezos:
+        return _decimalPlacesTezos;
     }
   }
 
@@ -180,6 +188,9 @@ abstract class Constants {
 
       case Coin.particl:
         return 600;
+
+      case Coin.tezos:
+        return 60;
     }
   }
 
diff --git a/lib/utilities/default_nodes.dart b/lib/utilities/default_nodes.dart
index 0f8425c88..8c48f5340 100644
--- a/lib/utilities/default_nodes.dart
+++ b/lib/utilities/default_nodes.dart
@@ -169,7 +169,20 @@ abstract class DefaultNodes {
       enabled: true,
       coinName: Coin.particl.name,
       isFailover: true,
-      isDown: false);
+      isDown: false
+  );
+
+  static NodeModel get tezos => NodeModel( // TODO: Change this to original one
+      host: "https://mainnet.api.tez.ie",
+      port: 443,
+      name: defaultName,
+      id: _nodeId(Coin.tezos),
+      useSSL: true,
+      enabled: true,
+      coinName: Coin.tezos.name,
+      isFailover: true,
+      isDown: false
+  );
 
   static NodeModel get bitcoinTestnet => NodeModel(
         host: "bitcoin-testnet.stackwallet.com",
@@ -269,6 +282,9 @@ abstract class DefaultNodes {
       case Coin.particl:
         return particl;
 
+      case Coin.tezos:
+        return tezos;
+
       case Coin.bitcoinTestNet:
         return bitcoinTestnet;
 
diff --git a/lib/utilities/enums/coin_enum.dart b/lib/utilities/enums/coin_enum.dart
index f1109a626..096e26db5 100644
--- a/lib/utilities/enums/coin_enum.dart
+++ b/lib/utilities/enums/coin_enum.dart
@@ -16,6 +16,7 @@ import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart'
     as nmc;
 import 'package:stackwallet/services/coins/particl/particl_wallet.dart'
     as particl;
+import 'package:stackwallet/services/coins/tezos/tezos_wallet.dart' as tezos;
 import 'package:stackwallet/services/coins/wownero/wownero_wallet.dart' as wow;
 import 'package:stackwallet/utilities/constants.dart';
 
@@ -31,6 +32,7 @@ enum Coin {
   monero,
   namecoin,
   particl,
+  tezos,
   wownero,
 
   ///
@@ -71,6 +73,8 @@ extension CoinExt on Coin {
         return "Monero";
       case Coin.particl:
         return "Particl";
+      case Coin.tezos:
+        return "Tezos";
       case Coin.wownero:
         return "Wownero";
       case Coin.namecoin:
@@ -110,6 +114,8 @@ extension CoinExt on Coin {
         return "XMR";
       case Coin.particl:
         return "PART";
+      case Coin.tezos:
+        return "XTZ";
       case Coin.wownero:
         return "WOW";
       case Coin.namecoin:
@@ -150,6 +156,8 @@ extension CoinExt on Coin {
         return "monero";
       case Coin.particl:
         return "particl";
+      case Coin.tezos:
+        return "tezos";
       case Coin.wownero:
         return "wownero";
       case Coin.namecoin:
@@ -187,6 +195,7 @@ extension CoinExt on Coin {
       case Coin.epicCash:
       case Coin.ethereum:
       case Coin.monero:
+      case Coin.tezos:
       case Coin.wownero:
         return false;
     }
@@ -207,6 +216,7 @@ extension CoinExt on Coin {
       case Coin.eCash:
       case Coin.epicCash:
       case Coin.monero:
+      case Coin.tezos:
       case Coin.wownero:
       case Coin.dogecoinTestNet:
       case Coin.bitcoinTestNet:
@@ -229,6 +239,7 @@ extension CoinExt on Coin {
       case Coin.epicCash:
       case Coin.ethereum:
       case Coin.monero:
+      case Coin.tezos:
       case Coin.wownero:
       case Coin.eCash:
         return false;
@@ -254,6 +265,7 @@ extension CoinExt on Coin {
       case Coin.epicCash:
       case Coin.ethereum:
       case Coin.monero:
+      case Coin.tezos:
       case Coin.wownero:
       case Coin.eCash:
         return this;
@@ -312,6 +324,9 @@ extension CoinExt on Coin {
       case Coin.particl:
         return particl.MINIMUM_CONFIRMATIONS;
 
+      case Coin.tezos:
+        return tezos.MINIMUM_CONFIRMATIONS;
+
       case Coin.wownero:
         return wow.MINIMUM_CONFIRMATIONS;
 
@@ -367,6 +382,10 @@ Coin coinFromPrettyName(String name) {
     case "particl":
       return Coin.particl;
 
+    case "Tezos":
+    case "tezos":
+      return Coin.tezos;
+
     case "Namecoin":
     case "namecoin":
       return Coin.namecoin;
@@ -436,6 +455,8 @@ Coin coinFromTickerCaseInsensitive(String ticker) {
       return Coin.namecoin;
     case "part":
       return Coin.particl;
+    case "xtz":
+      return Coin.tezos;
     case "tltc":
       return Coin.litecoinTestNet;
     case "tbtc":
diff --git a/lib/utilities/enums/derive_path_type_enum.dart b/lib/utilities/enums/derive_path_type_enum.dart
index 72899f5bd..315a355db 100644
--- a/lib/utilities/enums/derive_path_type_enum.dart
+++ b/lib/utilities/enums/derive_path_type_enum.dart
@@ -37,6 +37,7 @@ extension DerivePathTypeExt on DerivePathType {
       case Coin.epicCash:
       case Coin.monero:
       case Coin.wownero:
+      case Coin.tezos: // TODO: Is this true?
         throw UnsupportedError(
             "$coin does not use bitcoin style derivation paths");
     }
diff --git a/pubspec.lock b/pubspec.lock
index 600a92d67..14c0aca59 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -5,18 +5,18 @@ packages:
     dependency: transitive
     description:
       name: _fe_analyzer_shared
-      sha256: "4897882604d919befd350648c7f91926a9d5de99e67b455bf0917cc2362f4bb8"
+      sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a
       url: "https://pub.dev"
     source: hosted
-    version: "47.0.0"
+    version: "61.0.0"
   analyzer:
     dependency: "direct dev"
     description:
       name: analyzer
-      sha256: "690e335554a8385bc9d787117d9eb52c0c03ee207a607e593de3c9d71b1cfe80"
+      sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562
       url: "https://pub.dev"
     source: hosted
-    version: "4.7.0"
+    version: "5.13.0"
   animations:
     dependency: "direct main"
     description:
@@ -33,6 +33,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.12.29"
+  ansicolor:
+    dependency: transitive
+    description:
+      name: ansicolor
+      sha256: "607f8fa9786f392043f169898923e6c59b4518242b68b8862eb8a8b7d9c30b4a"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.0.1"
   app_settings:
     dependency: "direct main"
     description:
@@ -490,6 +498,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.5.5"
+  dio:
+    dependency: transitive
+    description:
+      name: dio
+      sha256: "7d328c4d898a61efc3cd93655a0955858e29a0aa647f0f9e02d59b3bb275e2e8"
+      url: "https://pub.dev"
+    source: hosted
+    version: "4.0.6"
   dropdown_button2:
     dependency: "direct main"
     description:
@@ -966,6 +982,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "3.0.2"
+  json_serializable:
+    dependency: transitive
+    description:
+      name: json_serializable
+      sha256: dadc08bd61f72559f938dd08ec20dbfec6c709bba83515085ea943d2078d187a
+      url: "https://pub.dev"
+    source: hosted
+    version: "6.6.1"
   jsonrpc2:
     dependency: "direct main"
     description:
@@ -1037,6 +1061,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.2.0"
+  memoize:
+    dependency: transitive
+    description:
+      name: memoize
+      sha256: "51481d328c86cbdc59711369179bac88551ca0556569249be5317e66fc796cac"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.0.0"
   meta:
     dependency: transitive
     description:
@@ -1285,6 +1317,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "5.1.0"
+  pinenacl:
+    dependency: transitive
+    description:
+      name: pinenacl
+      sha256: e5fb0bce1717b7f136f35ee98b5c02b3e6383211f8a77ca882fa7812232a07b9
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.3.4"
   platform:
     dependency: transitive
     description:
@@ -1317,6 +1357,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.5.1"
+  pretty_dio_logger:
+    dependency: transitive
+    description:
+      name: pretty_dio_logger
+      sha256: "948f7eeb36e7aa0760b51c1a8e3331d4b21e36fabd39efca81f585ed93893544"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.2.0-beta-1"
   process:
     dependency: transitive
     description:
@@ -1365,6 +1413,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "4.0.0"
+  quiver:
+    dependency: transitive
+    description:
+      name: quiver
+      sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.2.1"
   rational:
     dependency: "direct main"
     description:
@@ -1373,6 +1429,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.2.2"
+  retry:
+    dependency: transitive
+    description:
+      name: retry
+      sha256: a8a1e475a100a0bdc73f529ca8ea1e9c9c76bec8ad86a1f47780139a34ce7aea
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.1.1"
   riverpod:
     dependency: transitive
     description:
@@ -1659,6 +1723,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.4.20"
+  tezart:
+    dependency: "direct main"
+    description:
+      name: tezart
+      sha256: "35d526f2e6ca250c64461ebfb4fa9f64b6599fab8c4242c8e89ae27d4ac2e15a"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.0.5"
   time:
     dependency: transitive
     description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 3533282bf..25cd1e354 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -153,6 +153,7 @@ dependencies:
   rational: ^2.2.2
   archive: ^3.3.2
   desktop_drop: ^0.4.1
+  tezart: ^2.0.5
 
 dev_dependencies:
   flutter_test:
@@ -198,6 +199,7 @@ dependency_overrides:
       url: https://github.com/cypherstack/stack-bip39.git
       ref: 3bef5acc21340f3cc78df0ad1dce5868a3ed68a5
   crypto: 3.0.2
+  analyzer: ^5.2.0
 # For information on the generic Dart part of this file, see the
 # following page: https://dart.dev/tools/pub/pubspec
 

From d04df00691dd71acae9261e18d831a5f2b08b0df Mon Sep 17 00:00:00 2001
From: detherminal <76167420+detherminal@users.noreply.github.com>
Date: Wed, 21 Jun 2023 14:29:28 +0300
Subject: [PATCH 02/39] feat: update xtz

---
 lib/services/coins/tezos/tezos_wallet.dart | 146 +++++++++++++++++----
 lib/utilities/constants.dart               |   1 +
 lib/utilities/default_nodes.dart           |   2 +-
 3 files changed, 123 insertions(+), 26 deletions(-)

diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart
index fca4eabc2..9048c1d04 100644
--- a/lib/services/coins/tezos/tezos_wallet.dart
+++ b/lib/services/coins/tezos/tezos_wallet.dart
@@ -1,6 +1,9 @@
 import 'dart:async';
+import 'dart:convert';
+import 'dart:ffi';
 
 import 'package:http/http.dart';
+import 'package:isar/isar.dart';
 import 'package:stackwallet/models/balance.dart';
 import 'package:stackwallet/models/isar/models/blockchain_data/address.dart';
 import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart';
@@ -11,8 +14,10 @@ import 'package:stackwallet/services/node_service.dart';
 import 'package:stackwallet/utilities/amount/amount.dart';
 import 'package:stackwallet/utilities/enums/coin_enum.dart';
 import 'package:stackwallet/utilities/default_nodes.dart';
+import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
 
 import 'package:tezart/tezart.dart';
+import 'package:tuple/tuple.dart';
 
 import '../../../db/isar/main_db.dart';
 import '../../../models/node_model.dart';
@@ -49,6 +54,10 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
     return _xtzNode ?? NodeService(secureStorageInterface: _secureStore).getPrimaryNodeFor(coin: Coin.tezos) ?? DefaultNodes.getNodeFor(Coin.tezos);
   }
 
+  Future<Keystore> getKeystore() async {
+    return Keystore.fromMnemonic((await mnemonicString).toString());
+  }
+
   @override
   String get walletId => _walletId;
   late String _walletId;
@@ -102,10 +111,36 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   Balance? _balance;
 
   @override
-  Future<String> confirmSend({required Map<String, dynamic> txData}) {
-    // TODO: implement confirmSend,
-    // NOTE FROM DETHERMINAL: I couldnt write this function because I dont have any tezos to test with
-    throw UnimplementedError();
+  Future<Map<String, dynamic>> prepareSend({required String address, required Amount amount, Map<String, dynamic>? args}) async {
+    try {
+      if (amount.decimals != coin.decimals) {
+        throw Exception("Amount decimals do not match coin decimals!");
+      }
+      var fee = int.parse((await estimateFeeFor(amount, (args!["feeRate"] as FeeRateType).index)).raw.toString());
+      Map<String, dynamic> txData = {
+        "fee": fee,
+        "address": address,
+        "recipientAmt": amount,
+      };
+      return Future.value(txData);
+    } catch (e) {
+      return Future.error(e);
+    }
+  }
+
+  @override
+  Future<String> confirmSend({required Map<String, dynamic> txData}) async {
+    try {
+      final node = getCurrentNode().host + getCurrentNode().port.toString();
+      final int amountInMicroTez = ((int.parse((txData["recipientAmt"] as Amount).raw.toString()) * 1000000)).round();
+      final int feeInMicroTez = int.parse(txData["fee"].toString());
+      final String destinationAddress = txData["address"] as String;
+      final String sourceAddress = await currentReceivingAddress;
+      return Future.value(""); // TODO: return tx hash
+    } catch (e) {
+      Logging.instance.log(e.toString(), level: LogLevel.Error);
+      return Future.error(e);
+    }
   }
 
   @override
@@ -114,13 +149,14 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
     if (mneString == null) {
       throw Exception("No mnemonic found!");
     }
-    return Future.value(Keystore.fromMnemonic(mneString).address);
+    return Future.value((Keystore.fromMnemonic(mneString)).address);
   }
 
   @override
   Future<Amount> estimateFeeFor(Amount amount, int feeRate) {
-    // TODO: implement estimateFeeFor
-    throw UnimplementedError();
+    return Future.value(
+      Amount(rawValue: BigInt.parse(100000.toString()), fractionDigits: coin.decimals),
+    );
   }
 
   @override
@@ -130,13 +166,22 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   }
 
   @override
-  // TODO: implement fees
-  Future<FeeObject> get fees => throw UnimplementedError();
+  Future<FeeObject> get fees async {
+    // TODO: Change this to get fees from node and fix numberOfBlocks
+    return FeeObject(
+        numberOfBlocksFast: 1,
+        numberOfBlocksAverage: 1,
+        numberOfBlocksSlow: 1,
+        fast: 1000000,
+        medium: 100000,
+        slow: 10000,
+    );
+  }
 
   @override
   Future<void> fullRescan(int maxUnusedAddressGap, int maxNumberOfIndexesToCheck) {
-    // TODO: implement fullRescan
-    throw UnimplementedError();
+    refresh();
+    return Future.value();
   }
 
   @override
@@ -215,13 +260,6 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   @override
   Future<String?> get mnemonicString => _secureStore.read(key: '${_walletId}_mnemonic');
 
-  @override
-  Future<Map<String, dynamic>> prepareSend({required String address, required Amount amount, Map<String, dynamic>? args}) {
-    // TODO: implement prepareSend
-    // NOTE FROM DETHERMINAL: I couldnt write this function because I dont have any tezos to test with
-    throw UnimplementedError();
-  }
-
   @override
   Future<void> recoverFromMnemonic({required String mnemonic, String? mnemonicPassphrase, required int maxUnusedAddressGap, required int maxNumberOfIndexesToCheck, required int height}) async {
     if ((await mnemonicString) != null ||
@@ -267,9 +305,66 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
     await updateCachedBalance(_balance!);
   }
 
+  Future<void> updateTransactions() async {
+    var api = "https://api.mainnet.tzkt.io/v1/accounts/${await currentReceivingAddress}/balance_history"; // TODO: Can we use current node instead of this?
+    var returnedTxs = await get(Uri.parse(api)).then((value) => value.body);
+    Logging.instance.log(
+        "Transactions for ${await currentReceivingAddress}: $returnedTxs",
+        level: LogLevel.Info);
+    List<Tuple2<Transaction, Address>> txs = [];
+    Object? jsonTxs = jsonDecode(returnedTxs);
+    if (jsonTxs == null) {
+      await db.addNewTransactionData(txs, walletId);
+    } else {
+      for (var tx in jsonTxs as List) {
+        var theTx = Transaction(
+            walletId: walletId,
+            txid: "",
+            timestamp: DateTime.parse(tx["timestamp"].toString()).toUtc().millisecondsSinceEpoch ~/ 1000,
+            type: TransactionType.unknown,
+            subType: TransactionSubType.none,
+            amount: int.parse(tx["balance"].toString()),
+            amountString: Amount(
+                rawValue: BigInt.parse(tx["balance"].toString()),
+                fractionDigits: 6
+            ).toJsonString(),
+            fee: 0,
+            height: int.parse(tx["level"].toString()),
+            isCancelled: false,
+            isLelantus: false,
+            slateId: "",
+            otherData: "",
+            inputs: [],
+            outputs: [],
+            nonce: 0
+        );
+        var theAddress = Address(
+            walletId: walletId,
+            value: await currentReceivingAddress,
+            publicKey: [], // TODO: Add public key
+            derivationIndex: 0,
+            derivationPath: null,
+            type: AddressType.unknown,
+            subType: AddressSubType.unknown,
+        );
+        txs.add(Tuple2(theTx, theAddress));
+      }
+      await db.addNewTransactionData(txs, walletId);
+    }
+  }
+
+  Future<void> updateChainHeight() async {
+    var api = "https://api.tzkt.io/v1/blocks/count"; // TODO: Can we use current node instead of this?
+    var returnedHeight = await get(Uri.parse(api)).then((value) => value.body);
+    final int intHeight = int.parse(returnedHeight.toString());
+    await updateCachedChainHeight(intHeight);
+  }
+
   @override
   Future<void> refresh() {
+    updateChainHeight();
     updateBalance();
+    updateTransactions();
     return Future.value();
   }
 
@@ -277,16 +372,17 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   int get storedChainHeight => getCachedChainHeight();
 
   @override
-  Future<bool> testNetworkConnection() {
-    // TODO: implement testNetworkConnection
-    throw UnimplementedError();
+  Future<bool> testNetworkConnection() async{
+    try {
+      await get(Uri.parse("https://api.mainnet.tzkt.io/v1/accounts/${await currentReceivingAddress}/balance"));
+      return true;
+    } catch (e) {
+      return false;
+    }
   }
 
   @override
-  // TODO: implement transactions
-  Future<List<Transaction>> get transactions async {
-    // TODO: Maybe we can use this -> https://api.tzkt.io/#operation/Accounts_GetBalanceHistory
-  }
+  Future<List<Transaction>> get transactions => db.getTransactions(walletId).findAll();
 
   @override
   Future<void> updateNode(bool shouldRefresh) async {
diff --git a/lib/utilities/constants.dart b/lib/utilities/constants.dart
index 2fdacc64b..b74de5b98 100644
--- a/lib/utilities/constants.dart
+++ b/lib/utilities/constants.dart
@@ -136,6 +136,7 @@ abstract class Constants {
       case Coin.ethereum:
       case Coin.namecoin:
       case Coin.particl:
+      case Coin.tezos:
         values.addAll([24, 21, 18, 15, 12]);
         break;
 
diff --git a/lib/utilities/default_nodes.dart b/lib/utilities/default_nodes.dart
index 8c48f5340..ad9310c3d 100644
--- a/lib/utilities/default_nodes.dart
+++ b/lib/utilities/default_nodes.dart
@@ -173,7 +173,7 @@ abstract class DefaultNodes {
   );
 
   static NodeModel get tezos => NodeModel( // TODO: Change this to original one
-      host: "https://mainnet.api.tez.ie",
+      host: "mainnet.api.tez.ie",
       port: 443,
       name: defaultName,
       id: _nodeId(Coin.tezos),

From 0ae747aebc48ade08b02ad2e9b22a1a809099b1a Mon Sep 17 00:00:00 2001
From: detherminal <76167420+detherminal@users.noreply.github.com>
Date: Mon, 12 Jun 2023 22:03:32 +0300
Subject: [PATCH 03/39] feat: add xtz

---
 lib/models/isar/stack_theme.dart              |   9 +
 .../add_edit_node_view.dart                   |   1 +
 lib/services/coins/coin_service.dart          |  10 +
 lib/services/coins/tezos/tezos_wallet.dart    | 314 ++++++++++++++++++
 lib/themes/coin_icon_provider.dart            |   2 +
 lib/themes/coin_image_provider.dart           |   4 +
 lib/themes/color_theme.dart                   |   3 +
 lib/themes/stack_colors.dart                  |   2 +
 lib/utilities/address_utils.dart              |   2 +
 lib/utilities/block_explorers.dart            |   2 +
 lib/utilities/constants.dart                  |  14 +
 lib/utilities/default_nodes.dart              |  18 +-
 lib/utilities/enums/coin_enum.dart            |  21 ++
 .../enums/derive_path_type_enum.dart          |   1 +
 pubspec.lock                                  | 260 +++++++++------
 pubspec.yaml                                  |   6 +-
 16 files changed, 571 insertions(+), 98 deletions(-)
 create mode 100644 lib/services/coins/tezos/tezos_wallet.dart

diff --git a/lib/models/isar/stack_theme.dart b/lib/models/isar/stack_theme.dart
index 557090584..f6f7c351d 100644
--- a/lib/models/isar/stack_theme.dart
+++ b/lib/models/isar/stack_theme.dart
@@ -1921,6 +1921,7 @@ class ThemeAssets implements IThemeAssets {
   late final String wownero;
   late final String namecoin;
   late final String particl;
+  late final String tezos;
   late final String bitcoinImage;
   late final String bitcoincashImage;
   late final String dogecoinImage;
@@ -1932,6 +1933,7 @@ class ThemeAssets implements IThemeAssets {
   late final String wowneroImage;
   late final String namecoinImage;
   late final String particlImage;
+  late final String tezosImage;
   late final String bitcoinImageSecondary;
   late final String bitcoincashImageSecondary;
   late final String dogecoinImageSecondary;
@@ -1943,6 +1945,7 @@ class ThemeAssets implements IThemeAssets {
   late final String wowneroImageSecondary;
   late final String namecoinImageSecondary;
   late final String particlImageSecondary;
+  late final String tezosImageSecondary;
   @override
   late final String? loadingGif;
   @override
@@ -1988,6 +1991,8 @@ class ThemeAssets implements IThemeAssets {
       ..wownero = "$themeId/assets/${json["wownero"] as String}"
       ..namecoin = "$themeId/assets/${json["namecoin"] as String}"
       ..particl = "$themeId/assets/${json["particl"] as String}"
+      ..tezos =
+          "$themeId/assets/${json["bitcoin"] as String}"
       ..bitcoinImage = "$themeId/assets/${json["bitcoin_image"] as String}"
       ..bitcoincashImage =
           "$themeId/assets/${json["bitcoincash_image"] as String}"
@@ -2000,6 +2005,8 @@ class ThemeAssets implements IThemeAssets {
       ..wowneroImage = "$themeId/assets/${json["wownero_image"] as String}"
       ..namecoinImage = "$themeId/assets/${json["namecoin_image"] as String}"
       ..particlImage = "$themeId/assets/${json["particl_image"] as String}"
+      ..tezosImage =
+          "$themeId/assets/${json["bitcoin_image"] as String}"
       ..bitcoinImageSecondary =
           "$themeId/assets/${json["bitcoin_image_secondary"] as String}"
       ..bitcoincashImageSecondary =
@@ -2022,6 +2029,8 @@ class ThemeAssets implements IThemeAssets {
           "$themeId/assets/${json["namecoin_image_secondary"] as String}"
       ..particlImageSecondary =
           "$themeId/assets/${json["particl_image_secondary"] as String}"
+      ..tezosImageSecondary =
+          "$themeId/assets/${json["bitcoin_image_secondary"] as String}" // TODO: change to tezos
       ..loadingGif = json["loading_gif"] is String
           ? "$themeId/assets/${json["loading_gif"] as String}"
           : null
diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
index 3e5d3e3e4..c2543088d 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
@@ -727,6 +727,7 @@ class _NodeFormState extends ConsumerState<NodeForm> {
       case Coin.namecoin:
       case Coin.bitcoincash:
       case Coin.particl:
+      case Coin.tezos:
       case Coin.bitcoinTestNet:
       case Coin.litecoinTestNet:
       case Coin.bitcoincashTestnet:
diff --git a/lib/services/coins/coin_service.dart b/lib/services/coins/coin_service.dart
index 00a52eba5..3c1542805 100644
--- a/lib/services/coins/coin_service.dart
+++ b/lib/services/coins/coin_service.dart
@@ -27,6 +27,7 @@ import 'package:stackwallet/services/coins/monero/monero_wallet.dart';
 import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart';
 import 'package:stackwallet/services/coins/nano/nano_wallet.dart';
 import 'package:stackwallet/services/coins/particl/particl_wallet.dart';
+import 'package:stackwallet/services/coins/tezos/tezos_wallet.dart';
 import 'package:stackwallet/services/coins/wownero/wownero_wallet.dart';
 import 'package:stackwallet/services/transaction_notification_tracker.dart';
 import 'package:stackwallet/utilities/amount/amount.dart';
@@ -218,6 +219,15 @@ abstract class CoinServiceAPI {
             cachedClient: cachedClient,
             tracker: tracker);
 
+      case Coin.tezos:
+        return TezosWallet(
+          walletId: walletId,
+          walletName: walletName,
+          coin: coin,
+          secureStore: secureStorageInterface,
+          tracker: tracker,
+        );
+
       case Coin.wownero:
         return WowneroWallet(
           walletId: walletId,
diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart
new file mode 100644
index 000000000..fca4eabc2
--- /dev/null
+++ b/lib/services/coins/tezos/tezos_wallet.dart
@@ -0,0 +1,314 @@
+import 'dart:async';
+
+import 'package:http/http.dart';
+import 'package:stackwallet/models/balance.dart';
+import 'package:stackwallet/models/isar/models/blockchain_data/address.dart';
+import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart';
+import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart';
+import 'package:stackwallet/models/paymint/fee_object_model.dart';
+import 'package:stackwallet/services/coins/coin_service.dart';
+import 'package:stackwallet/services/node_service.dart';
+import 'package:stackwallet/utilities/amount/amount.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
+import 'package:stackwallet/utilities/default_nodes.dart';
+
+import 'package:tezart/tezart.dart';
+
+import '../../../db/isar/main_db.dart';
+import '../../../models/node_model.dart';
+import '../../../utilities/flutter_secure_storage_interface.dart';
+import '../../../utilities/logger.dart';
+import '../../../utilities/prefs.dart';
+import '../../mixins/wallet_cache.dart';
+import '../../mixins/wallet_db.dart';
+import '../../transaction_notification_tracker.dart';
+
+const int MINIMUM_CONFIRMATIONS = 1;
+
+class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
+  TezosWallet({
+    required String walletId,
+    required String walletName,
+    required Coin coin,
+    required SecureStorageInterface secureStore,
+    required TransactionNotificationTracker tracker,
+    MainDB? mockableOverride,
+  }) {
+    txTracker = tracker;
+    _walletId = walletId;
+    _walletName = walletName;
+    _coin = coin;
+    _secureStore = secureStore;
+    initCache(walletId, coin);
+    initWalletDB(mockableOverride: mockableOverride);
+  }
+
+  NodeModel? _xtzNode;
+
+  NodeModel getCurrentNode() {
+    return _xtzNode ?? NodeService(secureStorageInterface: _secureStore).getPrimaryNodeFor(coin: Coin.tezos) ?? DefaultNodes.getNodeFor(Coin.tezos);
+  }
+
+  @override
+  String get walletId => _walletId;
+  late String _walletId;
+
+  @override
+  String get walletName => _walletName;
+  late String _walletName;
+
+  @override
+  set walletName(String name) => _walletName = name;
+
+  @override
+  set isFavorite(bool markFavorite) {
+    _isFavorite = markFavorite;
+    updateCachedIsFavorite(markFavorite);
+  }
+
+  @override
+  bool get isFavorite => _isFavorite ??= getCachedIsFavorite();
+  bool? _isFavorite;
+
+  @override
+  Coin get coin => _coin;
+  late Coin _coin;
+
+  late SecureStorageInterface _secureStore;
+  late final TransactionNotificationTracker txTracker;
+  final _prefs = Prefs.instance;
+
+  Timer? timer;
+  bool _shouldAutoSync = false;
+
+  @override
+  bool get shouldAutoSync => _shouldAutoSync;
+
+  @override
+  set shouldAutoSync(bool shouldAutoSync) {
+    if (_shouldAutoSync != shouldAutoSync) {
+      _shouldAutoSync = shouldAutoSync;
+      if (!shouldAutoSync) {
+        timer?.cancel();
+        timer = null;
+      } else {
+        refresh();
+      }
+    }
+  }
+
+  @override
+  Balance get balance => _balance ??= getCachedBalance();
+  Balance? _balance;
+
+  @override
+  Future<String> confirmSend({required Map<String, dynamic> txData}) {
+    // TODO: implement confirmSend,
+    // NOTE FROM DETHERMINAL: I couldnt write this function because I dont have any tezos to test with
+    throw UnimplementedError();
+  }
+
+  @override
+  Future<String> get currentReceivingAddress async {
+    var mneString = await mnemonicString;
+    if (mneString == null) {
+      throw Exception("No mnemonic found!");
+    }
+    return Future.value(Keystore.fromMnemonic(mneString).address);
+  }
+
+  @override
+  Future<Amount> estimateFeeFor(Amount amount, int feeRate) {
+    // TODO: implement estimateFeeFor
+    throw UnimplementedError();
+  }
+
+  @override
+  Future<void> exit() {
+    _hasCalledExit = true;
+    return Future.value();
+  }
+
+  @override
+  // TODO: implement fees
+  Future<FeeObject> get fees => throw UnimplementedError();
+
+  @override
+  Future<void> fullRescan(int maxUnusedAddressGap, int maxNumberOfIndexesToCheck) {
+    // TODO: implement fullRescan
+    throw UnimplementedError();
+  }
+
+  @override
+  Future<bool> generateNewAddress() {
+    // TODO: implement generateNewAddress
+    throw UnimplementedError();
+  }
+
+  @override
+  bool get hasCalledExit => _hasCalledExit;
+  bool _hasCalledExit = false;
+
+  @override
+  Future<void> initializeExisting() async {
+    await _prefs.init();
+  }
+
+  @override
+  Future<void> initializeNew() async {
+    var newKeystore = Keystore.random();
+    await _secureStore.write(
+      key: '${_walletId}_mnemonic',
+      value: newKeystore.mnemonic,
+    );
+    await _secureStore.write(
+      key: '${_walletId}_mnemonicPassphrase',
+      value: "",
+    );
+
+    final address = Address(
+        walletId: walletId,
+        value: newKeystore.address,
+        publicKey: [], // TODO: Add public key
+        derivationIndex: 0,
+        derivationPath: null,
+        type: AddressType.unknown,
+        subType: AddressSubType.unknown,
+    );
+
+    await db.putAddress(address);
+
+    await Future.wait([
+      updateCachedId(walletId),
+      updateCachedIsFavorite(false),
+    ]);
+  }
+
+  @override
+  bool get isConnected => _isConnected;
+  bool _isConnected = false;
+
+  @override
+  bool get isRefreshing => refreshMutex;
+  bool refreshMutex = false;
+
+  @override
+  // TODO: implement maxFee
+  Future<int> get maxFee => throw UnimplementedError();
+
+  @override
+  Future<List<String>> get mnemonic async {
+    final mnemonic = await mnemonicString;
+    final mnemonicPassphrase = await this.mnemonicPassphrase;
+    if (mnemonic == null) {
+      throw Exception("No mnemonic found!");
+    }
+    if (mnemonicPassphrase == null) {
+      throw Exception("No mnemonic passphrase found!");
+    }
+    return mnemonic.split(" ");
+  }
+
+  @override
+  Future<String?> get mnemonicPassphrase => _secureStore.read(key: '${_walletId}_mnemonicPassphrase');
+
+  @override
+  Future<String?> get mnemonicString => _secureStore.read(key: '${_walletId}_mnemonic');
+
+  @override
+  Future<Map<String, dynamic>> prepareSend({required String address, required Amount amount, Map<String, dynamic>? args}) {
+    // TODO: implement prepareSend
+    // NOTE FROM DETHERMINAL: I couldnt write this function because I dont have any tezos to test with
+    throw UnimplementedError();
+  }
+
+  @override
+  Future<void> recoverFromMnemonic({required String mnemonic, String? mnemonicPassphrase, required int maxUnusedAddressGap, required int maxNumberOfIndexesToCheck, required int height}) async {
+    if ((await mnemonicString) != null ||
+        (await this.mnemonicPassphrase) != null) {
+      throw Exception("Attempted to overwrite mnemonic on restore!");
+    }
+    await _secureStore.write(
+        key: '${_walletId}_mnemonic', value: mnemonic.trim());
+    await _secureStore.write(
+      key: '${_walletId}_mnemonicPassphrase',
+      value: mnemonicPassphrase ?? "",
+    );
+
+    final address = Address(
+        walletId: walletId,
+        value: Keystore.fromMnemonic(mnemonic).address,
+        publicKey: [], // TODO: Add public key
+        derivationIndex: 0,
+        derivationPath: null,
+        type: AddressType.unknown,
+        subType: AddressSubType.unknown,
+    );
+
+    await db.putAddress(address);
+
+    await Future.wait([
+      updateCachedId(walletId),
+      updateCachedIsFavorite(false),
+    ]);
+  }
+
+  Future<void> updateBalance() async {
+    var api = "https://api.mainnet.tzkt.io/v1/accounts/${await currentReceivingAddress}/balance"; // TODO: Can we use current node instead of this?
+    var theBalance = await get(Uri.parse(api)).then((value) => value.body);
+    Logging.instance.log("Balance for ${await currentReceivingAddress}: $theBalance", level: LogLevel.Info);
+    var balanceInAmount = Amount(rawValue: BigInt.parse(theBalance.toString()), fractionDigits: 6);
+    _balance = Balance(
+      total: balanceInAmount,
+      spendable: balanceInAmount,
+      blockedTotal: Amount(rawValue: BigInt.parse("0"), fractionDigits: 6),
+      pendingSpendable: Amount(rawValue: BigInt.parse("0"), fractionDigits: 6),
+    );
+    await updateCachedBalance(_balance!);
+  }
+
+  @override
+  Future<void> refresh() {
+    updateBalance();
+    return Future.value();
+  }
+
+  @override
+  int get storedChainHeight => getCachedChainHeight();
+
+  @override
+  Future<bool> testNetworkConnection() {
+    // TODO: implement testNetworkConnection
+    throw UnimplementedError();
+  }
+
+  @override
+  // TODO: implement transactions
+  Future<List<Transaction>> get transactions async {
+    // TODO: Maybe we can use this -> https://api.tzkt.io/#operation/Accounts_GetBalanceHistory
+  }
+
+  @override
+  Future<void> updateNode(bool shouldRefresh) async {
+    _xtzNode = NodeService(secureStorageInterface: _secureStore).getPrimaryNodeFor(coin: coin) ?? DefaultNodes.getNodeFor(coin);
+
+    if (shouldRefresh) {
+      await refresh();
+    }
+  }
+
+  @override
+  Future<void> updateSentCachedTxData(Map<String, dynamic> txData) {
+    // TODO: implement updateSentCachedTxData
+    throw UnimplementedError();
+  }
+
+  @override
+  // TODO: implement utxos
+  Future<List<UTXO>> get utxos => throw UnimplementedError();
+
+  @override
+  bool validateAddress(String address) {
+    return RegExp(r"^tz[1-9A-HJ-NP-Za-km-z]{34}$").hasMatch(address);
+  }
+}
diff --git a/lib/themes/coin_icon_provider.dart b/lib/themes/coin_icon_provider.dart
index 9bd3990bb..acbfaed3f 100644
--- a/lib/themes/coin_icon_provider.dart
+++ b/lib/themes/coin_icon_provider.dart
@@ -43,6 +43,8 @@ final coinIconProvider = Provider.family<String, Coin>((ref, coin) {
         return assets.namecoin;
       case Coin.particl:
         return assets.particl;
+      case Coin.tezos:
+        return assets.tezos;
       case Coin.ethereum:
         return assets.ethereum;
       default:
diff --git a/lib/themes/coin_image_provider.dart b/lib/themes/coin_image_provider.dart
index 6ca839fb9..d72e7b778 100644
--- a/lib/themes/coin_image_provider.dart
+++ b/lib/themes/coin_image_provider.dart
@@ -41,6 +41,8 @@ final coinImageProvider = Provider.family<String, Coin>((ref, coin) {
         return assets.namecoinImage;
       case Coin.particl:
         return assets.particlImage;
+      case Coin.tezos:
+        return assets.tezosImage;
       case Coin.bitcoinTestNet:
         return assets.bitcoinImage;
       case Coin.bitcoincashTestnet:
@@ -89,6 +91,8 @@ final coinImageSecondaryProvider = Provider.family<String, Coin>((ref, coin) {
         return assets.namecoinImageSecondary;
       case Coin.particl:
         return assets.particlImageSecondary;
+      case Coin.tezos:
+        return assets.tezosImageSecondary;
       case Coin.bitcoinTestNet:
         return assets.bitcoinImageSecondary;
       case Coin.bitcoincashTestnet:
diff --git a/lib/themes/color_theme.dart b/lib/themes/color_theme.dart
index bcfa45ac9..1ea9253a4 100644
--- a/lib/themes/color_theme.dart
+++ b/lib/themes/color_theme.dart
@@ -30,6 +30,7 @@ class CoinThemeColorDefault {
   Color get particl => const Color(0xFF8175BD);
   Color get nano => const Color(0xFF209CE9);
   Color get banano => const Color(0xFFFBDD11);
+  Color get tezos => const Color(0xFF0F61FF);
 
   Color forCoin(Coin coin) {
     switch (coin) {
@@ -66,6 +67,8 @@ class CoinThemeColorDefault {
         return nano;
       case Coin.banano:
         return banano;
+      case Coin.tezos:
+        return tezos;
     }
   }
 }
diff --git a/lib/themes/stack_colors.dart b/lib/themes/stack_colors.dart
index b9e58a5ca..4c3362b95 100644
--- a/lib/themes/stack_colors.dart
+++ b/lib/themes/stack_colors.dart
@@ -1711,6 +1711,8 @@ class StackColors extends ThemeExtension<StackColors> {
         return _coin.nano;
       case Coin.banano:
         return _coin.banano;
+      case Coin.tezos:
+        return _coin.tezos;
     }
   }
 
diff --git a/lib/utilities/address_utils.dart b/lib/utilities/address_utils.dart
index 0093e1d00..77cff70ab 100644
--- a/lib/utilities/address_utils.dart
+++ b/lib/utilities/address_utils.dart
@@ -109,6 +109,8 @@ class AddressUtils {
         return NanoAccounts.isValid(NanoAccountType.NANO, address);
       case Coin.banano:
         return NanoAccounts.isValid(NanoAccountType.BANANO, address);
+      case Coin.tezos:
+        return RegExp(r"^tz[1-9A-HJ-NP-Za-km-z]{34}$").hasMatch(address);
       case Coin.bitcoinTestNet:
         return Address.validateAddress(address, testnet);
       case Coin.litecoinTestNet:
diff --git a/lib/utilities/block_explorers.dart b/lib/utilities/block_explorers.dart
index 7ff0cf349..bcca709e6 100644
--- a/lib/utilities/block_explorers.dart
+++ b/lib/utilities/block_explorers.dart
@@ -58,6 +58,8 @@ Uri getDefaultBlockExplorerUrlFor({
       return Uri.parse("https://www.nanolooker.com/block/$txid");
     case Coin.banano:
       return Uri.parse("https://www.bananolooker.com/block/$txid");
+    case Coin.tezos:
+      return Uri.parse("https://tzstats.com/$txid");
   }
 }
 
diff --git a/lib/utilities/constants.dart b/lib/utilities/constants.dart
index 2dd7be287..f23c1827a 100644
--- a/lib/utilities/constants.dart
+++ b/lib/utilities/constants.dart
@@ -44,6 +44,7 @@ abstract class Constants {
   static final BigInt _satsPerCoinBanano =
       BigInt.parse("100000000000000000000000000000"); // 1*10^29
   static final BigInt _satsPerCoin = BigInt.from(100000000);
+  static final BigInt _satsPerCoinTezos = BigInt.from(1000000);
   static const int _decimalPlaces = 8;
   static const int _decimalPlacesNano = 30;
   static const int _decimalPlacesBanano = 29;
@@ -51,6 +52,7 @@ abstract class Constants {
   static const int _decimalPlacesMonero = 12;
   static const int _decimalPlacesEthereum = 18;
   static const int _decimalPlacesECash = 2;
+  static const int _decimalPlacesTezos = 6;
 
   static const int notificationsMax = 0xFFFFFFFF;
   static const Duration networkAliveTimerDuration = Duration(seconds: 10);
@@ -96,6 +98,9 @@ abstract class Constants {
 
       case Coin.eCash:
         return _satsPerCoinECash;
+
+      case Coin.tezos:
+        return _satsPerCoinTezos;
     }
   }
 
@@ -133,6 +138,9 @@ abstract class Constants {
 
       case Coin.eCash:
         return _decimalPlacesECash;
+
+      case Coin.tezos:
+        return _decimalPlacesTezos;
     }
   }
 
@@ -160,6 +168,8 @@ abstract class Constants {
       case Coin.banano:
         values.addAll([24, 12]);
         break;
+      case Coin.tezos:
+        values.addAll([24, 12]);
 
       case Coin.monero:
         values.addAll([25]);
@@ -214,6 +224,9 @@ abstract class Constants {
       case Coin.nano: // TODO: Verify this
       case Coin.banano: // TODO: Verify this
         return 1;
+
+      case Coin.tezos:
+        return 60;
     }
   }
 
@@ -241,6 +254,7 @@ abstract class Constants {
 
       case Coin.nano:
       case Coin.banano:
+      case Coin.tezos:
         return 24;
 
       case Coin.monero:
diff --git a/lib/utilities/default_nodes.dart b/lib/utilities/default_nodes.dart
index c8ff94120..05e192f77 100644
--- a/lib/utilities/default_nodes.dart
+++ b/lib/utilities/default_nodes.dart
@@ -179,7 +179,20 @@ abstract class DefaultNodes {
       enabled: true,
       coinName: Coin.particl.name,
       isFailover: true,
-      isDown: false);
+      isDown: false
+  );
+
+  static NodeModel get tezos => NodeModel( // TODO: Change this to original one
+      host: "https://mainnet.api.tez.ie",
+      port: 443,
+      name: defaultName,
+      id: _nodeId(Coin.tezos),
+      useSSL: true,
+      enabled: true,
+      coinName: Coin.tezos.name,
+      isFailover: true,
+      isDown: false
+  );
 
   static NodeModel get nano => NodeModel(
       host: "https://rainstorm.city/api",
@@ -300,12 +313,13 @@ abstract class DefaultNodes {
 
       case Coin.particl:
         return particl;
-
       case Coin.nano:
         return nano;
 
       case Coin.banano:
         return banano;
+      case Coin.tezos:
+        return tezos;
 
       case Coin.bitcoinTestNet:
         return bitcoinTestnet;
diff --git a/lib/utilities/enums/coin_enum.dart b/lib/utilities/enums/coin_enum.dart
index c656b2c62..f4a1eebbb 100644
--- a/lib/utilities/enums/coin_enum.dart
+++ b/lib/utilities/enums/coin_enum.dart
@@ -27,6 +27,7 @@ import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart'
 import 'package:stackwallet/services/coins/nano/nano_wallet.dart' as nano;
 import 'package:stackwallet/services/coins/particl/particl_wallet.dart'
     as particl;
+import 'package:stackwallet/services/coins/tezos/tezos_wallet.dart' as tezos;
 import 'package:stackwallet/services/coins/wownero/wownero_wallet.dart' as wow;
 import 'package:stackwallet/utilities/constants.dart';
 
@@ -44,6 +45,7 @@ enum Coin {
   namecoin,
   nano,
   particl,
+  tezos,
   wownero,
 
   ///
@@ -84,6 +86,8 @@ extension CoinExt on Coin {
         return "Monero";
       case Coin.particl:
         return "Particl";
+      case Coin.tezos:
+        return "Tezos";
       case Coin.wownero:
         return "Wownero";
       case Coin.namecoin:
@@ -127,6 +131,8 @@ extension CoinExt on Coin {
         return "XMR";
       case Coin.particl:
         return "PART";
+      case Coin.tezos:
+        return "XTZ";
       case Coin.wownero:
         return "WOW";
       case Coin.namecoin:
@@ -171,6 +177,8 @@ extension CoinExt on Coin {
         return "monero";
       case Coin.particl:
         return "particl";
+      case Coin.tezos:
+        return "tezos";
       case Coin.wownero:
         return "wownero";
       case Coin.namecoin:
@@ -212,6 +220,7 @@ extension CoinExt on Coin {
       case Coin.epicCash:
       case Coin.ethereum:
       case Coin.monero:
+      case Coin.tezos:
       case Coin.wownero:
       case Coin.nano:
       case Coin.banano:
@@ -234,6 +243,7 @@ extension CoinExt on Coin {
       case Coin.eCash:
       case Coin.epicCash:
       case Coin.monero:
+      case Coin.tezos:
       case Coin.wownero:
       case Coin.dogecoinTestNet:
       case Coin.bitcoinTestNet:
@@ -258,6 +268,7 @@ extension CoinExt on Coin {
       case Coin.epicCash:
       case Coin.ethereum:
       case Coin.monero:
+      case Coin.tezos:
       case Coin.wownero:
       case Coin.nano:
       case Coin.banano:
@@ -285,6 +296,7 @@ extension CoinExt on Coin {
       case Coin.epicCash:
       case Coin.ethereum:
       case Coin.monero:
+      case Coin.tezos:
       case Coin.wownero:
       case Coin.nano:
       case Coin.banano:
@@ -345,6 +357,9 @@ extension CoinExt on Coin {
       case Coin.particl:
         return particl.MINIMUM_CONFIRMATIONS;
 
+      case Coin.tezos:
+        return tezos.MINIMUM_CONFIRMATIONS;
+
       case Coin.wownero:
         return wow.MINIMUM_CONFIRMATIONS;
 
@@ -404,6 +419,10 @@ Coin coinFromPrettyName(String name) {
     case "particl":
       return Coin.particl;
 
+    case "Tezos":
+    case "tezos":
+      return Coin.tezos;
+
     case "Namecoin":
     case "namecoin":
       return Coin.namecoin;
@@ -481,6 +500,8 @@ Coin coinFromTickerCaseInsensitive(String ticker) {
       return Coin.namecoin;
     case "part":
       return Coin.particl;
+    case "xtz":
+      return Coin.tezos;
     case "tltc":
       return Coin.litecoinTestNet;
     case "tbtc":
diff --git a/lib/utilities/enums/derive_path_type_enum.dart b/lib/utilities/enums/derive_path_type_enum.dart
index f3e7f86df..99d26e24c 100644
--- a/lib/utilities/enums/derive_path_type_enum.dart
+++ b/lib/utilities/enums/derive_path_type_enum.dart
@@ -49,6 +49,7 @@ extension DerivePathTypeExt on DerivePathType {
       case Coin.wownero:
       case Coin.nano:
       case Coin.banano:
+      case Coin.tezos: // TODO: Is this true?
         throw UnsupportedError(
             "$coin does not use bitcoin style derivation paths");
     }
diff --git a/pubspec.lock b/pubspec.lock
index 2dcd3c598..4bcb94925 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -25,6 +25,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.12.30"
+  ansicolor:
+    dependency: transitive
+    description:
+      name: ansicolor
+      sha256: "607f8fa9786f392043f169898923e6c59b4518242b68b8862eb8a8b7d9c30b4a"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.0.1"
   archive:
     dependency: "direct main"
     description:
@@ -37,18 +45,18 @@ packages:
     dependency: transitive
     description:
       name: args
-      sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a
+      sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
       url: "https://pub.dev"
     source: hosted
-    version: "2.4.1"
+    version: "2.4.2"
   asn1lib:
     dependency: transitive
     description:
       name: asn1lib
-      sha256: ab96a1cb3beeccf8145c52e449233fe68364c9641623acd3adad66f8184f1039
+      sha256: b74e3842a52c61f8819a1ec8444b4de5419b41a7465e69d4aa681445377398b0
       url: "https://pub.dev"
     source: hosted
-    version: "1.4.0"
+    version: "1.4.1"
   async:
     dependency: "direct main"
     description:
@@ -146,10 +154,10 @@ packages:
     dependency: transitive
     description:
       name: build
-      sha256: "43865b79fbb78532e4bff7c33087aa43b1d488c4fdef014eaef568af6d8016dc"
+      sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
       url: "https://pub.dev"
     source: hosted
-    version: "2.4.0"
+    version: "2.4.1"
   build_config:
     dependency: transitive
     description:
@@ -170,26 +178,26 @@ packages:
     dependency: transitive
     description:
       name: build_resolvers
-      sha256: db49b8609ef8c81cca2b310618c3017c00f03a92af44c04d310b907b2d692d95
+      sha256: "6c4dd11d05d056e76320b828a1db0fc01ccd376922526f8e9d6c796a5adbac20"
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.0"
+    version: "2.2.1"
   build_runner:
     dependency: "direct dev"
     description:
       name: build_runner
-      sha256: "220ae4553e50d7c21a17c051afc7b183d28a24a420502e842f303f8e4e6edced"
+      sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b"
       url: "https://pub.dev"
     source: hosted
-    version: "2.4.4"
+    version: "2.4.6"
   build_runner_core:
     dependency: transitive
     description:
       name: build_runner_core
-      sha256: "88a57f2ac99849362e73878334caa9f06ee25f31d2adced882b8337838c84e1e"
+      sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41"
       url: "https://pub.dev"
     source: hosted
-    version: "7.2.9"
+    version: "7.2.10"
   built_collection:
     dependency: transitive
     description:
@@ -202,10 +210,10 @@ packages:
     dependency: transitive
     description:
       name: built_value
-      sha256: "7dd62d9faf105c434f3d829bbe9c4be02ec67f5ed94832222116122df67c5452"
+      sha256: "598a2a682e2a7a90f08ba39c0aaa9374c5112340f0a2e275f61b59389543d166"
       url: "https://pub.dev"
     source: hosted
-    version: "8.6.0"
+    version: "8.6.1"
   characters:
     dependency: transitive
     description:
@@ -242,10 +250,10 @@ packages:
     dependency: transitive
     description:
       name: code_builder
-      sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe"
+      sha256: "4ad01d6e56db961d29661561effde45e519939fdaeb46c351275b182eac70189"
       url: "https://pub.dev"
     source: hosted
-    version: "4.4.0"
+    version: "4.5.0"
   collection:
     dependency: transitive
     description:
@@ -298,10 +306,10 @@ packages:
     dependency: "direct main"
     description:
       name: crypto
-      sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67
+      sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
       url: "https://pub.dev"
     source: hosted
-    version: "3.0.2"
+    version: "3.0.3"
   cryptography:
     dependency: transitive
     description:
@@ -314,10 +322,10 @@ packages:
     dependency: transitive
     description:
       name: csslib
-      sha256: "831883fb353c8bdc1d71979e5b342c7d88acfbc643113c14ae51e2442ea0f20f"
+      sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb"
       url: "https://pub.dev"
     source: hosted
-    version: "0.17.3"
+    version: "1.0.0"
   cw_core:
     dependency: "direct main"
     description:
@@ -382,18 +390,18 @@ packages:
     dependency: transitive
     description:
       name: dart_style
-      sha256: f4f1f73ab3fd2afcbcca165ee601fe980d966af6a21b5970c6c9376955c528ad
+      sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55"
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.1"
+    version: "2.3.2"
   dartx:
     dependency: transitive
     description:
       name: dartx
-      sha256: "45d7176701f16c5a5e00a4798791c1964bc231491b879369c818dd9a9c764871"
+      sha256: "8b25435617027257d43e6508b5fe061012880ddfdaa75a71d607c3de2a13d244"
       url: "https://pub.dev"
     source: hosted
-    version: "1.1.0"
+    version: "1.2.0"
   dbus:
     dependency: transitive
     description:
@@ -406,10 +414,10 @@ packages:
     dependency: "direct main"
     description:
       name: decimal
-      sha256: eece91944f523657c75a3a008a90ec7f7eb3986191153a78570c7d0ac8ef3d01
+      sha256: "24a261d5d5c87e86c7651c417a5dbdf8bcd7080dd592533910e8d0505a279f21"
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.2"
+    version: "2.3.3"
   dependency_validator:
     dependency: "direct dev"
     description:
@@ -450,14 +458,22 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.6.0"
+  dio:
+    dependency: transitive
+    description:
+      name: dio
+      sha256: "7d328c4d898a61efc3cd93655a0955858e29a0aa647f0f9e02d59b3bb275e2e8"
+      url: "https://pub.dev"
+    source: hosted
+    version: "4.0.6"
   dropdown_button2:
     dependency: "direct main"
     description:
       name: dropdown_button2
-      sha256: "374f2390161bf782b4896f0b1b24cbb2b5daaa1cfb11047c3307461dcdf44e07"
+      sha256: "83c54a5022f898d63e3abe21240b64b937e676103207287e6705d3f9bb04d654"
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.3"
+    version: "2.3.6"
   eip1559:
     dependency: transitive
     description:
@@ -542,10 +558,10 @@ packages:
     dependency: "direct main"
     description:
       name: file_picker
-      sha256: "9d6e95ec73abbd31ec54d0e0df8a961017e165aba1395e462e5b31ea0c165daf"
+      sha256: b1729fc96627dd44012d0a901558177418818d6bd428df59dcfeb594e5f66432
       url: "https://pub.dev"
     source: hosted
-    version: "5.3.1"
+    version: "5.3.2"
   fixnum:
     dependency: transitive
     description:
@@ -606,10 +622,10 @@ packages:
     dependency: "direct dev"
     description:
       name: flutter_lints
-      sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
+      sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
       url: "https://pub.dev"
     source: hosted
-    version: "2.0.1"
+    version: "2.0.2"
   flutter_local_notifications:
     dependency: "direct main"
     description:
@@ -670,10 +686,10 @@ packages:
     dependency: "direct main"
     description:
       name: flutter_rounded_date_picker
-      sha256: e7143cc5cbf3aec1536286653e38b0809abc99fb76c91bd910dbd98ae003d890
+      sha256: e6aa2dc5d3b44e8bbe85ef901be69eac59ba4136427f11f4c8b2a303e1e774e7
       url: "https://pub.dev"
     source: hosted
-    version: "3.0.3"
+    version: "3.0.4"
   flutter_secure_storage:
     dependency: "direct main"
     description:
@@ -821,10 +837,10 @@ packages:
     dependency: transitive
     description:
       name: html
-      sha256: "58e3491f7bf0b6a4ea5110c0c688877460d1a6366731155c4a4580e7ded773e8"
+      sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a"
       url: "https://pub.dev"
     source: hosted
-    version: "0.15.3"
+    version: "0.15.4"
   http:
     dependency: "direct main"
     description:
@@ -934,6 +950,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "3.0.2"
+  json_serializable:
+    dependency: transitive
+    description:
+      name: json_serializable
+      sha256: aa1f5a8912615733e0fdc7a02af03308933c93235bdc8d50d0b0c8a8ccb0b969
+      url: "https://pub.dev"
+    source: hosted
+    version: "6.7.1"
   keyboard_dismisser:
     dependency: "direct main"
     description:
@@ -953,10 +977,10 @@ packages:
     dependency: transitive
     description:
       name: lints
-      sha256: "6b0206b0bf4f04961fc5438198ccb3a885685cd67d4d4a32cc20ad7f8adbe015"
+      sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.0"
+    version: "2.1.1"
   local_auth:
     dependency: "direct main"
     description:
@@ -977,10 +1001,10 @@ packages:
     dependency: "direct main"
     description:
       name: lottie
-      sha256: "23522951540d20a57a60202ed7022e6376bed206a4eee1c347a91f58bd57eb9f"
+      sha256: "0793a5866062e5cc8a8b24892fa94c3095953ea914a7fdf790f550dd7537fe60"
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.2"
+    version: "2.5.0"
   matcher:
     dependency: transitive
     description:
@@ -997,6 +1021,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.2.0"
+  memoize:
+    dependency: transitive
+    description:
+      name: memoize
+      sha256: "51481d328c86cbdc59711369179bac88551ca0556569249be5317e66fc796cac"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.0.0"
   meta:
     dependency: transitive
     description:
@@ -1033,10 +1065,10 @@ packages:
     dependency: "direct dev"
     description:
       name: mockito
-      sha256: "8b46d7eb40abdda92d62edd01546051f0c27365e65608c284de336dccfef88cc"
+      sha256: "7d5b53bcd556c1bc7ffbe4e4d5a19c3e112b7e925e9e172dd7c6ad0630812616"
       url: "https://pub.dev"
     source: hosted
-    version: "5.4.1"
+    version: "5.4.2"
   mocktail:
     dependency: transitive
     description:
@@ -1145,10 +1177,10 @@ packages:
     dependency: transitive
     description:
       name: path_provider_foundation
-      sha256: "1995d88ec2948dac43edf8fe58eb434d35d22a2940ecee1a9fefcd62beee6eb3"
+      sha256: "916731ccbdce44d545414dd9961f26ba5fbaa74bcbb55237d8e65a623a8c7297"
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.3"
+    version: "2.2.4"
   path_provider_linux:
     dependency: transitive
     description:
@@ -1169,50 +1201,50 @@ packages:
     dependency: transitive
     description:
       name: path_provider_windows
-      sha256: d3f80b32e83ec208ac95253e0cd4d298e104fbc63cb29c5c69edaed43b0c69d6
+      sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96"
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.6"
+    version: "2.1.7"
   permission_handler:
     dependency: "direct main"
     description:
       name: permission_handler
-      sha256: "33c6a1253d1f95fd06fa74b65b7ba907ae9811f9d5c1d3150e51417d04b8d6a8"
+      sha256: "63e5216aae014a72fe9579ccd027323395ce7a98271d9defa9d57320d001af81"
       url: "https://pub.dev"
     source: hosted
-    version: "10.2.0"
+    version: "10.4.3"
   permission_handler_android:
     dependency: transitive
     description:
       name: permission_handler_android
-      sha256: d8cc6a62ded6d0f49c6eac337e080b066ee3bce4d405bd9439a61e1f1927bfe8
+      sha256: c0c9754479a4c4b1c1f3862ddc11930c9b3f03bef2816bb4ea6eed1e13551d6f
       url: "https://pub.dev"
     source: hosted
-    version: "10.2.1"
+    version: "10.3.2"
   permission_handler_apple:
     dependency: transitive
     description:
       name: permission_handler_apple
-      sha256: ee96ac32f5a8e6f80756e25b25b9f8e535816c8e6665a96b6d70681f8c4f7e85
+      sha256: "99e220bce3f8877c78e4ace901082fb29fa1b4ebde529ad0932d8d664b34f3f5"
       url: "https://pub.dev"
     source: hosted
-    version: "9.0.8"
+    version: "9.1.4"
   permission_handler_platform_interface:
     dependency: transitive
     description:
       name: permission_handler_platform_interface
-      sha256: "68abbc472002b5e6dfce47fe9898c6b7d8328d58b5d2524f75e277c07a97eb84"
+      sha256: "7c6b1500385dd1d2ca61bb89e2488ca178e274a69144d26bbd65e33eae7c02a9"
       url: "https://pub.dev"
     source: hosted
-    version: "3.9.0"
+    version: "3.11.3"
   permission_handler_windows:
     dependency: transitive
     description:
       name: permission_handler_windows
-      sha256: f67cab14b4328574938ecea2db3475dad7af7ead6afab6338772c5f88963e38b
+      sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098
       url: "https://pub.dev"
     source: hosted
-    version: "0.1.2"
+    version: "0.1.3"
   petitparser:
     dependency: transitive
     description:
@@ -1221,6 +1253,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "5.4.0"
+  pinenacl:
+    dependency: transitive
+    description:
+      name: pinenacl
+      sha256: e5fb0bce1717b7f136f35ee98b5c02b3e6383211f8a77ca882fa7812232a07b9
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.3.4"
   platform:
     dependency: transitive
     description:
@@ -1253,6 +1293,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.5.1"
+  pretty_dio_logger:
+    dependency: transitive
+    description:
+      name: pretty_dio_logger
+      sha256: "948f7eeb36e7aa0760b51c1a8e3331d4b21e36fabd39efca81f585ed93893544"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.2.0-beta-1"
   process:
     dependency: transitive
     description:
@@ -1301,6 +1349,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "4.1.0"
+  quiver:
+    dependency: transitive
+    description:
+      name: quiver
+      sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.2.1"
   rational:
     dependency: transitive
     description:
@@ -1309,6 +1365,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.2.2"
+  retry:
+    dependency: transitive
+    description:
+      name: retry
+      sha256: "822e118d5b3aafed083109c72d5f484c6dc66707885e07c0fbcb8b986bba7efc"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.1.2"
   riverpod:
     dependency: transitive
     description:
@@ -1353,58 +1417,58 @@ packages:
     dependency: transitive
     description:
       name: shared_preferences
-      sha256: "16d3fb6b3692ad244a695c0183fca18cf81fd4b821664394a781de42386bf022"
+      sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1"
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.1"
+    version: "2.2.0"
   shared_preferences_android:
     dependency: transitive
     description:
       name: shared_preferences_android
-      sha256: "6478c6bbbecfe9aced34c483171e90d7c078f5883558b30ec3163cf18402c749"
+      sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.4"
+    version: "2.2.0"
   shared_preferences_foundation:
     dependency: transitive
     description:
       name: shared_preferences_foundation
-      sha256: e014107bb79d6d3297196f4f2d0db54b5d1f85b8ea8ff63b8e8b391a02700feb
+      sha256: f39696b83e844923b642ce9dd4bd31736c17e697f6731a5adf445b1274cf3cd4
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.2"
+    version: "2.3.2"
   shared_preferences_linux:
     dependency: transitive
     description:
       name: shared_preferences_linux
-      sha256: "9d387433ca65717bbf1be88f4d5bb18f10508917a8fa2fb02e0fd0d7479a9afa"
+      sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1"
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.0"
+    version: "2.3.0"
   shared_preferences_platform_interface:
     dependency: transitive
     description:
       name: shared_preferences_platform_interface
-      sha256: fb5cf25c0235df2d0640ac1b1174f6466bd311f621574997ac59018a6664548d
+      sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1"
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.0"
+    version: "2.3.0"
   shared_preferences_web:
     dependency: transitive
     description:
       name: shared_preferences_web
-      sha256: "74083203a8eae241e0de4a0d597dbedab3b8fef5563f33cf3c12d7e93c655ca5"
+      sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a"
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.0"
+    version: "2.2.0"
   shared_preferences_windows:
     dependency: transitive
     description:
       name: shared_preferences_windows
-      sha256: "5e588e2efef56916a3b229c3bfe81e6a525665a454519ca51dbcc4236a274173"
+      sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.0"
+    version: "2.3.0"
   shelf:
     dependency: transitive
     description:
@@ -1446,18 +1510,18 @@ packages:
     dependency: transitive
     description:
       name: source_gen
-      sha256: "373f96cf5a8744bc9816c1ff41cf5391bbdbe3d7a96fe98c622b6738a8a7bd33"
+      sha256: fc0da689e5302edb6177fdd964efcb7f58912f43c28c2047a808f5bfff643d16
       url: "https://pub.dev"
     source: hosted
-    version: "1.3.2"
+    version: "1.4.0"
   source_helper:
     dependency: transitive
     description:
       name: source_helper
-      sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f"
+      sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd"
       url: "https://pub.dev"
     source: hosted
-    version: "1.3.3"
+    version: "1.3.4"
   source_map_stack_trace:
     dependency: transitive
     description:
@@ -1579,6 +1643,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.5.1"
+  tezart:
+    dependency: "direct main"
+    description:
+      name: tezart
+      sha256: "35d526f2e6ca250c64461ebfb4fa9f64b6599fab8c4242c8e89ae27d4ac2e15a"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.0.5"
   time:
     dependency: transitive
     description:
@@ -1615,10 +1687,10 @@ packages:
     dependency: "direct main"
     description:
       name: tuple
-      sha256: "0ea99cd2f9352b2586583ab2ce6489d1f95a5f6de6fb9492faaf97ae2060f0aa"
+      sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
       url: "https://pub.dev"
     source: hosted
-    version: "2.0.1"
+    version: "2.0.2"
   typed_data:
     dependency: transitive
     description:
@@ -1631,26 +1703,26 @@ packages:
     dependency: transitive
     description:
       name: universal_io
-      sha256: "06866290206d196064fd61df4c7aea1ffe9a4e7c4ccaa8fcded42dd41948005d"
+      sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad"
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.0"
+    version: "2.2.2"
   url_launcher:
     dependency: "direct main"
     description:
       name: url_launcher
-      sha256: eb1e00ab44303d50dd487aab67ebc575456c146c6af44422f9c13889984c00f3
+      sha256: "781bd58a1eb16069412365c98597726cd8810ae27435f04b3b4d3a470bacd61e"
       url: "https://pub.dev"
     source: hosted
-    version: "6.1.11"
+    version: "6.1.12"
   url_launcher_android:
     dependency: transitive
     description:
       name: url_launcher_android
-      sha256: eed4e6a1164aa9794409325c3b707ff424d4d1c2a785e7db67f8bbda00e36e51
+      sha256: "15f5acbf0dce90146a0f5a2c4a002b1814a6303c4c5c075aa2623b2d16156f03"
       url: "https://pub.dev"
     source: hosted
-    version: "6.0.35"
+    version: "6.0.36"
   url_launcher_ios:
     dependency: transitive
     description:
@@ -1671,34 +1743,34 @@ packages:
     dependency: transitive
     description:
       name: url_launcher_macos
-      sha256: "91ee3e75ea9dadf38036200c5d3743518f4a5eb77a8d13fda1ee5764373f185e"
+      sha256: "1c4fdc0bfea61a70792ce97157e5cc17260f61abbe4f39354513f39ec6fd73b1"
       url: "https://pub.dev"
     source: hosted
-    version: "3.0.5"
+    version: "3.0.6"
   url_launcher_platform_interface:
     dependency: transitive
     description:
       name: url_launcher_platform_interface
-      sha256: "6c9ca697a5ae218ce56cece69d46128169a58aa8653c1b01d26fcd4aad8c4370"
+      sha256: bfdfa402f1f3298637d71ca8ecfe840b4696698213d5346e9d12d4ab647ee2ea
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.2"
+    version: "2.1.3"
   url_launcher_web:
     dependency: transitive
     description:
       name: url_launcher_web
-      sha256: "6bb1e5d7fe53daf02a8fee85352432a40b1f868a81880e99ec7440113d5cfcab"
+      sha256: cc26720eefe98c1b71d85f9dc7ef0cada5132617046369d9dc296b3ecaa5cbb4
       url: "https://pub.dev"
     source: hosted
-    version: "2.0.17"
+    version: "2.0.18"
   url_launcher_windows:
     dependency: transitive
     description:
       name: url_launcher_windows
-      sha256: "254708f17f7c20a9c8c471f67d86d76d4a3f9c1591aad1e15292008aceb82771"
+      sha256: "7967065dd2b5fccc18c653b97958fdf839c5478c28e767c61ee879f4e7882422"
       url: "https://pub.dev"
     source: hosted
-    version: "3.0.6"
+    version: "3.0.7"
   uuid:
     dependency: "direct main"
     description:
@@ -1824,18 +1896,18 @@ packages:
     dependency: transitive
     description:
       name: win32
-      sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c"
+      sha256: dfdf0136e0aa7a1b474ea133e67cb0154a0acd2599c4f3ada3b49d38d38793ee
       url: "https://pub.dev"
     source: hosted
-    version: "4.1.4"
+    version: "5.0.5"
   win32_registry:
     dependency: transitive
     description:
       name: win32_registry
-      sha256: "1c52f994bdccb77103a6231ad4ea331a244dbcef5d1f37d8462f713143b0bfae"
+      sha256: e4506d60b7244251bc59df15656a3093501c37fb5af02105a944d73eb95be4c9
       url: "https://pub.dev"
     source: hosted
-    version: "1.1.0"
+    version: "1.1.1"
   window_size:
     dependency: "direct main"
     description:
diff --git a/pubspec.yaml b/pubspec.yaml
index fd5eac1dc..000ecd8a0 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -138,6 +138,7 @@ dependencies:
   desktop_drop: ^0.4.1
   nanodart: ^2.0.0
   basic_utils: ^5.5.4
+  tezart: ^2.0.5
 
 dev_dependencies:
   flutter_test:
@@ -196,9 +197,10 @@ dependency_overrides:
   bip39:
     git:
       url: https://github.com/cypherstack/stack-bip39.git
+
       ref: 0cd6d54e2860bea68fc50c801cb9db2a760192fb
-
-
+  crypto: ^3.0.2
+  analyzer: ^5.2.0
 # For information on the generic Dart part of this file, see the
 # following page: https://dart.dev/tools/pub/pubspec
 

From d387fcc7b9a916e3c3ef74cdefa3ab7357f6e334 Mon Sep 17 00:00:00 2001
From: detherminal <76167420+detherminal@users.noreply.github.com>
Date: Wed, 21 Jun 2023 14:29:28 +0300
Subject: [PATCH 04/39] feat: update xtz

---
 lib/services/coins/tezos/tezos_wallet.dart | 146 +++++++++++++++++----
 lib/utilities/constants.dart               |   1 -
 lib/utilities/default_nodes.dart           |   2 +-
 3 files changed, 122 insertions(+), 27 deletions(-)

diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart
index fca4eabc2..9048c1d04 100644
--- a/lib/services/coins/tezos/tezos_wallet.dart
+++ b/lib/services/coins/tezos/tezos_wallet.dart
@@ -1,6 +1,9 @@
 import 'dart:async';
+import 'dart:convert';
+import 'dart:ffi';
 
 import 'package:http/http.dart';
+import 'package:isar/isar.dart';
 import 'package:stackwallet/models/balance.dart';
 import 'package:stackwallet/models/isar/models/blockchain_data/address.dart';
 import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart';
@@ -11,8 +14,10 @@ import 'package:stackwallet/services/node_service.dart';
 import 'package:stackwallet/utilities/amount/amount.dart';
 import 'package:stackwallet/utilities/enums/coin_enum.dart';
 import 'package:stackwallet/utilities/default_nodes.dart';
+import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
 
 import 'package:tezart/tezart.dart';
+import 'package:tuple/tuple.dart';
 
 import '../../../db/isar/main_db.dart';
 import '../../../models/node_model.dart';
@@ -49,6 +54,10 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
     return _xtzNode ?? NodeService(secureStorageInterface: _secureStore).getPrimaryNodeFor(coin: Coin.tezos) ?? DefaultNodes.getNodeFor(Coin.tezos);
   }
 
+  Future<Keystore> getKeystore() async {
+    return Keystore.fromMnemonic((await mnemonicString).toString());
+  }
+
   @override
   String get walletId => _walletId;
   late String _walletId;
@@ -102,10 +111,36 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   Balance? _balance;
 
   @override
-  Future<String> confirmSend({required Map<String, dynamic> txData}) {
-    // TODO: implement confirmSend,
-    // NOTE FROM DETHERMINAL: I couldnt write this function because I dont have any tezos to test with
-    throw UnimplementedError();
+  Future<Map<String, dynamic>> prepareSend({required String address, required Amount amount, Map<String, dynamic>? args}) async {
+    try {
+      if (amount.decimals != coin.decimals) {
+        throw Exception("Amount decimals do not match coin decimals!");
+      }
+      var fee = int.parse((await estimateFeeFor(amount, (args!["feeRate"] as FeeRateType).index)).raw.toString());
+      Map<String, dynamic> txData = {
+        "fee": fee,
+        "address": address,
+        "recipientAmt": amount,
+      };
+      return Future.value(txData);
+    } catch (e) {
+      return Future.error(e);
+    }
+  }
+
+  @override
+  Future<String> confirmSend({required Map<String, dynamic> txData}) async {
+    try {
+      final node = getCurrentNode().host + getCurrentNode().port.toString();
+      final int amountInMicroTez = ((int.parse((txData["recipientAmt"] as Amount).raw.toString()) * 1000000)).round();
+      final int feeInMicroTez = int.parse(txData["fee"].toString());
+      final String destinationAddress = txData["address"] as String;
+      final String sourceAddress = await currentReceivingAddress;
+      return Future.value(""); // TODO: return tx hash
+    } catch (e) {
+      Logging.instance.log(e.toString(), level: LogLevel.Error);
+      return Future.error(e);
+    }
   }
 
   @override
@@ -114,13 +149,14 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
     if (mneString == null) {
       throw Exception("No mnemonic found!");
     }
-    return Future.value(Keystore.fromMnemonic(mneString).address);
+    return Future.value((Keystore.fromMnemonic(mneString)).address);
   }
 
   @override
   Future<Amount> estimateFeeFor(Amount amount, int feeRate) {
-    // TODO: implement estimateFeeFor
-    throw UnimplementedError();
+    return Future.value(
+      Amount(rawValue: BigInt.parse(100000.toString()), fractionDigits: coin.decimals),
+    );
   }
 
   @override
@@ -130,13 +166,22 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   }
 
   @override
-  // TODO: implement fees
-  Future<FeeObject> get fees => throw UnimplementedError();
+  Future<FeeObject> get fees async {
+    // TODO: Change this to get fees from node and fix numberOfBlocks
+    return FeeObject(
+        numberOfBlocksFast: 1,
+        numberOfBlocksAverage: 1,
+        numberOfBlocksSlow: 1,
+        fast: 1000000,
+        medium: 100000,
+        slow: 10000,
+    );
+  }
 
   @override
   Future<void> fullRescan(int maxUnusedAddressGap, int maxNumberOfIndexesToCheck) {
-    // TODO: implement fullRescan
-    throw UnimplementedError();
+    refresh();
+    return Future.value();
   }
 
   @override
@@ -215,13 +260,6 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   @override
   Future<String?> get mnemonicString => _secureStore.read(key: '${_walletId}_mnemonic');
 
-  @override
-  Future<Map<String, dynamic>> prepareSend({required String address, required Amount amount, Map<String, dynamic>? args}) {
-    // TODO: implement prepareSend
-    // NOTE FROM DETHERMINAL: I couldnt write this function because I dont have any tezos to test with
-    throw UnimplementedError();
-  }
-
   @override
   Future<void> recoverFromMnemonic({required String mnemonic, String? mnemonicPassphrase, required int maxUnusedAddressGap, required int maxNumberOfIndexesToCheck, required int height}) async {
     if ((await mnemonicString) != null ||
@@ -267,9 +305,66 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
     await updateCachedBalance(_balance!);
   }
 
+  Future<void> updateTransactions() async {
+    var api = "https://api.mainnet.tzkt.io/v1/accounts/${await currentReceivingAddress}/balance_history"; // TODO: Can we use current node instead of this?
+    var returnedTxs = await get(Uri.parse(api)).then((value) => value.body);
+    Logging.instance.log(
+        "Transactions for ${await currentReceivingAddress}: $returnedTxs",
+        level: LogLevel.Info);
+    List<Tuple2<Transaction, Address>> txs = [];
+    Object? jsonTxs = jsonDecode(returnedTxs);
+    if (jsonTxs == null) {
+      await db.addNewTransactionData(txs, walletId);
+    } else {
+      for (var tx in jsonTxs as List) {
+        var theTx = Transaction(
+            walletId: walletId,
+            txid: "",
+            timestamp: DateTime.parse(tx["timestamp"].toString()).toUtc().millisecondsSinceEpoch ~/ 1000,
+            type: TransactionType.unknown,
+            subType: TransactionSubType.none,
+            amount: int.parse(tx["balance"].toString()),
+            amountString: Amount(
+                rawValue: BigInt.parse(tx["balance"].toString()),
+                fractionDigits: 6
+            ).toJsonString(),
+            fee: 0,
+            height: int.parse(tx["level"].toString()),
+            isCancelled: false,
+            isLelantus: false,
+            slateId: "",
+            otherData: "",
+            inputs: [],
+            outputs: [],
+            nonce: 0
+        );
+        var theAddress = Address(
+            walletId: walletId,
+            value: await currentReceivingAddress,
+            publicKey: [], // TODO: Add public key
+            derivationIndex: 0,
+            derivationPath: null,
+            type: AddressType.unknown,
+            subType: AddressSubType.unknown,
+        );
+        txs.add(Tuple2(theTx, theAddress));
+      }
+      await db.addNewTransactionData(txs, walletId);
+    }
+  }
+
+  Future<void> updateChainHeight() async {
+    var api = "https://api.tzkt.io/v1/blocks/count"; // TODO: Can we use current node instead of this?
+    var returnedHeight = await get(Uri.parse(api)).then((value) => value.body);
+    final int intHeight = int.parse(returnedHeight.toString());
+    await updateCachedChainHeight(intHeight);
+  }
+
   @override
   Future<void> refresh() {
+    updateChainHeight();
     updateBalance();
+    updateTransactions();
     return Future.value();
   }
 
@@ -277,16 +372,17 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   int get storedChainHeight => getCachedChainHeight();
 
   @override
-  Future<bool> testNetworkConnection() {
-    // TODO: implement testNetworkConnection
-    throw UnimplementedError();
+  Future<bool> testNetworkConnection() async{
+    try {
+      await get(Uri.parse("https://api.mainnet.tzkt.io/v1/accounts/${await currentReceivingAddress}/balance"));
+      return true;
+    } catch (e) {
+      return false;
+    }
   }
 
   @override
-  // TODO: implement transactions
-  Future<List<Transaction>> get transactions async {
-    // TODO: Maybe we can use this -> https://api.tzkt.io/#operation/Accounts_GetBalanceHistory
-  }
+  Future<List<Transaction>> get transactions => db.getTransactions(walletId).findAll();
 
   @override
   Future<void> updateNode(bool shouldRefresh) async {
diff --git a/lib/utilities/constants.dart b/lib/utilities/constants.dart
index f23c1827a..1a285cc41 100644
--- a/lib/utilities/constants.dart
+++ b/lib/utilities/constants.dart
@@ -167,7 +167,6 @@ abstract class Constants {
         break;
       case Coin.banano:
         values.addAll([24, 12]);
-        break;
       case Coin.tezos:
         values.addAll([24, 12]);
 
diff --git a/lib/utilities/default_nodes.dart b/lib/utilities/default_nodes.dart
index 05e192f77..ac2edb482 100644
--- a/lib/utilities/default_nodes.dart
+++ b/lib/utilities/default_nodes.dart
@@ -183,7 +183,7 @@ abstract class DefaultNodes {
   );
 
   static NodeModel get tezos => NodeModel( // TODO: Change this to original one
-      host: "https://mainnet.api.tez.ie",
+      host: "mainnet.api.tez.ie",
       port: 443,
       name: defaultName,
       id: _nodeId(Coin.tezos),

From 45af21dc270a2814a4ca953d76dac1adcbdaed53 Mon Sep 17 00:00:00 2001
From: likho <likhojiba@gmail.com>
Date: Wed, 19 Jul 2023 16:37:54 +0200
Subject: [PATCH 05/39] Fix merge conflicts with staging

---
 .../manage_nodes_views/add_edit_node_view.dart                 | 1 +
 .../manage_nodes_views/node_details_view.dart                  | 1 +
 lib/services/coins/tezos/tezos_wallet.dart                     | 3 ++-
 lib/utilities/amount/amount_unit.dart                          | 2 ++
 lib/widgets/node_card.dart                                     | 1 +
 lib/widgets/node_options_sheet.dart                            | 1 +
 6 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
index c2543088d..5702c9740 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
@@ -196,6 +196,7 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
 
       case Coin.nano:
       case Coin.banano:
+      case Coin.tezos:
       //TODO: check network/node
     }
 
diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
index fa69871cb..3e10b9240 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
@@ -172,6 +172,7 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> {
 
       case Coin.nano:
       case Coin.banano:
+      case Coin.tezos:
       //TODO: check network/node
     }
 
diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart
index 9048c1d04..e5576741c 100644
--- a/lib/services/coins/tezos/tezos_wallet.dart
+++ b/lib/services/coins/tezos/tezos_wallet.dart
@@ -336,7 +336,8 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
             otherData: "",
             inputs: [],
             outputs: [],
-            nonce: 0
+            nonce: 0,
+            numberOfMessages: null,
         );
         var theAddress = Address(
             walletId: walletId,
diff --git a/lib/utilities/amount/amount_unit.dart b/lib/utilities/amount/amount_unit.dart
index 0c0600d7a..fd2366dd4 100644
--- a/lib/utilities/amount/amount_unit.dart
+++ b/lib/utilities/amount/amount_unit.dart
@@ -50,6 +50,7 @@ enum AmountUnit {
       case Coin.dogecoin:
       case Coin.eCash:
       case Coin.epicCash:
+      case Coin.tezos:
         return AmountUnit.values.sublist(0, 4);
 
       case Coin.monero:
@@ -62,6 +63,7 @@ enum AmountUnit {
       case Coin.nano:
       case Coin.banano:
         return AmountUnit.values;
+
     }
   }
 }
diff --git a/lib/widgets/node_card.dart b/lib/widgets/node_card.dart
index 9214e3e0a..3f4384ffc 100644
--- a/lib/widgets/node_card.dart
+++ b/lib/widgets/node_card.dart
@@ -194,6 +194,7 @@ class _NodeCardState extends ConsumerState<NodeCard> {
 
       case Coin.nano:
       case Coin.banano:
+      case Coin.tezos:
       //TODO: check network/node
     }
 
diff --git a/lib/widgets/node_options_sheet.dart b/lib/widgets/node_options_sheet.dart
index 16e87581c..faebd95e3 100644
--- a/lib/widgets/node_options_sheet.dart
+++ b/lib/widgets/node_options_sheet.dart
@@ -177,6 +177,7 @@ class NodeOptionsSheet extends ConsumerWidget {
 
       case Coin.nano:
       case Coin.banano:
+      case Coin.tezos:
       //TODO: check network/node
     }
 

From c8d0ecf28dc10ee2f63dcc47c84e205acf0daf5b Mon Sep 17 00:00:00 2001
From: ryleedavis <rylee@cypherstack.com>
Date: Thu, 27 Jul 2023 11:11:11 -0600
Subject: [PATCH 06/39] remove changes to ThemeAssets v1

---
 lib/models/isar/stack_theme.dart    | 9 ---------
 lib/themes/coin_image_provider.dart | 4 ----
 2 files changed, 13 deletions(-)

diff --git a/lib/models/isar/stack_theme.dart b/lib/models/isar/stack_theme.dart
index ea449a497..32878366a 100644
--- a/lib/models/isar/stack_theme.dart
+++ b/lib/models/isar/stack_theme.dart
@@ -1921,7 +1921,6 @@ class ThemeAssets implements IThemeAssets {
   late final String wownero;
   late final String namecoin;
   late final String particl;
-  late final String tezos;
   late final String bitcoinImage;
   late final String bitcoincashImage;
   late final String dogecoinImage;
@@ -1933,7 +1932,6 @@ class ThemeAssets implements IThemeAssets {
   late final String wowneroImage;
   late final String namecoinImage;
   late final String particlImage;
-  late final String tezosImage;
   late final String bitcoinImageSecondary;
   late final String bitcoincashImageSecondary;
   late final String dogecoinImageSecondary;
@@ -1945,7 +1943,6 @@ class ThemeAssets implements IThemeAssets {
   late final String wowneroImageSecondary;
   late final String namecoinImageSecondary;
   late final String particlImageSecondary;
-  late final String tezosImageSecondary;
   @override
   late final String? loadingGif;
   @override
@@ -1991,8 +1988,6 @@ class ThemeAssets implements IThemeAssets {
       ..wownero = "$themeId/assets/${json["wownero"] as String}"
       ..namecoin = "$themeId/assets/${json["namecoin"] as String}"
       ..particl = "$themeId/assets/${json["particl"] as String}"
-      ..tezos =
-          "$themeId/assets/${json["bitcoin"] as String}"
       ..bitcoinImage = "$themeId/assets/${json["bitcoin_image"] as String}"
       ..bitcoincashImage =
           "$themeId/assets/${json["bitcoincash_image"] as String}"
@@ -2005,8 +2000,6 @@ class ThemeAssets implements IThemeAssets {
       ..wowneroImage = "$themeId/assets/${json["wownero_image"] as String}"
       ..namecoinImage = "$themeId/assets/${json["namecoin_image"] as String}"
       ..particlImage = "$themeId/assets/${json["particl_image"] as String}"
-      ..tezosImage =
-          "$themeId/assets/${json["bitcoin_image"] as String}"
       ..bitcoinImageSecondary =
           "$themeId/assets/${json["bitcoin_image_secondary"] as String}"
       ..bitcoincashImageSecondary =
@@ -2029,8 +2022,6 @@ class ThemeAssets implements IThemeAssets {
           "$themeId/assets/${json["namecoin_image_secondary"] as String}"
       ..particlImageSecondary =
           "$themeId/assets/${json["particl_image_secondary"] as String}"
-      ..tezosImageSecondary =
-          "$themeId/assets/${json["bitcoin_image_secondary"] as String}" // TODO: change to tezos
       ..loadingGif = json["loading_gif"] is String
           ? "$themeId/assets/${json["loading_gif"] as String}"
           : null
diff --git a/lib/themes/coin_image_provider.dart b/lib/themes/coin_image_provider.dart
index d72e7b778..6ca839fb9 100644
--- a/lib/themes/coin_image_provider.dart
+++ b/lib/themes/coin_image_provider.dart
@@ -41,8 +41,6 @@ final coinImageProvider = Provider.family<String, Coin>((ref, coin) {
         return assets.namecoinImage;
       case Coin.particl:
         return assets.particlImage;
-      case Coin.tezos:
-        return assets.tezosImage;
       case Coin.bitcoinTestNet:
         return assets.bitcoinImage;
       case Coin.bitcoincashTestnet:
@@ -91,8 +89,6 @@ final coinImageSecondaryProvider = Provider.family<String, Coin>((ref, coin) {
         return assets.namecoinImageSecondary;
       case Coin.particl:
         return assets.particlImageSecondary;
-      case Coin.tezos:
-        return assets.tezosImageSecondary;
       case Coin.bitcoinTestNet:
         return assets.bitcoinImageSecondary;
       case Coin.bitcoincashTestnet:

From 2ee65b584ea21d59f44d01884afb2cf9fe296068 Mon Sep 17 00:00:00 2001
From: detherminal <76167420+detherminal@users.noreply.github.com>
Date: Thu, 27 Jul 2023 23:15:49 +0300
Subject: [PATCH 07/39] fix: fetch from nodes instead of tzkt

---
 lib/services/coins/tezos/tezos_wallet.dart | 13 +++++++------
 lib/utilities/default_nodes.dart           |  4 ++--
 2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart
index e5576741c..38631a071 100644
--- a/lib/services/coins/tezos/tezos_wallet.dart
+++ b/lib/services/coins/tezos/tezos_wallet.dart
@@ -292,8 +292,8 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   }
 
   Future<void> updateBalance() async {
-    var api = "https://api.mainnet.tzkt.io/v1/accounts/${await currentReceivingAddress}/balance"; // TODO: Can we use current node instead of this?
-    var theBalance = await get(Uri.parse(api)).then((value) => value.body);
+    var api = "${getCurrentNode().host}:${getCurrentNode().port}/chains/main/blocks/head/context/contracts/${await currentReceivingAddress}/balance";
+    var theBalance = (await get(Uri.parse(api)).then((value) => value.body)).substring(1, (await get(Uri.parse(api)).then((value) => value.body)).length - 2);
     Logging.instance.log("Balance for ${await currentReceivingAddress}: $theBalance", level: LogLevel.Info);
     var balanceInAmount = Amount(rawValue: BigInt.parse(theBalance.toString()), fractionDigits: 6);
     _balance = Balance(
@@ -355,9 +355,10 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   }
 
   Future<void> updateChainHeight() async {
-    var api = "https://api.tzkt.io/v1/blocks/count"; // TODO: Can we use current node instead of this?
-    var returnedHeight = await get(Uri.parse(api)).then((value) => value.body);
-    final int intHeight = int.parse(returnedHeight.toString());
+    var api = "${getCurrentNode().host}:${getCurrentNode().port}/chains/main/blocks/head/header/shell";
+    var jsonParsedResponse = jsonDecode(await get(Uri.parse(api)).then((value) => value.body));
+    final int intHeight = int.parse(jsonParsedResponse["level"].toString());
+    Logging.instance.log("Chain height: $intHeight", level: LogLevel.Info);
     await updateCachedChainHeight(intHeight);
   }
 
@@ -375,7 +376,7 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   @override
   Future<bool> testNetworkConnection() async{
     try {
-      await get(Uri.parse("https://api.mainnet.tzkt.io/v1/accounts/${await currentReceivingAddress}/balance"));
+      await get(Uri.parse("${getCurrentNode().host}:${getCurrentNode().port}/chains/main/blocks/head/header/shell"));
       return true;
     } catch (e) {
       return false;
diff --git a/lib/utilities/default_nodes.dart b/lib/utilities/default_nodes.dart
index ac2edb482..22f274d62 100644
--- a/lib/utilities/default_nodes.dart
+++ b/lib/utilities/default_nodes.dart
@@ -182,8 +182,8 @@ abstract class DefaultNodes {
       isDown: false
   );
 
-  static NodeModel get tezos => NodeModel( // TODO: Change this to original one
-      host: "mainnet.api.tez.ie",
+  static NodeModel get tezos => NodeModel( // TODO: Change this to stack wallet one
+      host: "https://mainnet.api.tez.ie",
       port: 443,
       name: defaultName,
       id: _nodeId(Coin.tezos),

From 3077465e81e017c524b61b1ea9afcda3c1bb01fc Mon Sep 17 00:00:00 2001
From: detherminal <76167420+detherminal@users.noreply.github.com>
Date: Fri, 28 Jul 2023 13:39:07 +0300
Subject: [PATCH 08/39] xtz: update api and add price

---
 lib/services/coins/tezos/tezos_wallet.dart | 87 +++++++++++-----------
 lib/services/price.dart                    |  2 +-
 2 files changed, 45 insertions(+), 44 deletions(-)

diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart
index 38631a071..8faa15427 100644
--- a/lib/services/coins/tezos/tezos_wallet.dart
+++ b/lib/services/coins/tezos/tezos_wallet.dart
@@ -306,52 +306,53 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   }
 
   Future<void> updateTransactions() async {
-    var api = "https://api.mainnet.tzkt.io/v1/accounts/${await currentReceivingAddress}/balance_history"; // TODO: Can we use current node instead of this?
-    var returnedTxs = await get(Uri.parse(api)).then((value) => value.body);
-    Logging.instance.log(
-        "Transactions for ${await currentReceivingAddress}: $returnedTxs",
-        level: LogLevel.Info);
+    // TODO: Use node RPC instead of tzstats API
+    var api = "https://api.tzstats.com/tables/op?address=${await currentReceivingAddress}";
+    var jsonResponse = jsonDecode(await get(Uri.parse(api)).then((value) => value.body));
     List<Tuple2<Transaction, Address>> txs = [];
-    Object? jsonTxs = jsonDecode(returnedTxs);
-    if (jsonTxs == null) {
-      await db.addNewTransactionData(txs, walletId);
-    } else {
-      for (var tx in jsonTxs as List) {
-        var theTx = Transaction(
-            walletId: walletId,
-            txid: "",
-            timestamp: DateTime.parse(tx["timestamp"].toString()).toUtc().millisecondsSinceEpoch ~/ 1000,
-            type: TransactionType.unknown,
-            subType: TransactionSubType.none,
-            amount: int.parse(tx["balance"].toString()),
-            amountString: Amount(
-                rawValue: BigInt.parse(tx["balance"].toString()),
-                fractionDigits: 6
-            ).toJsonString(),
-            fee: 0,
-            height: int.parse(tx["level"].toString()),
-            isCancelled: false,
-            isLelantus: false,
-            slateId: "",
-            otherData: "",
-            inputs: [],
-            outputs: [],
-            nonce: 0,
-            numberOfMessages: null,
-        );
-        var theAddress = Address(
-            walletId: walletId,
-            value: await currentReceivingAddress,
-            publicKey: [], // TODO: Add public key
-            derivationIndex: 0,
-            derivationPath: null,
-            type: AddressType.unknown,
-            subType: AddressSubType.unknown,
-        );
-        txs.add(Tuple2(theTx, theAddress));
+    for (var tx in jsonResponse as List) {
+      var txApi = "https://api.tzstats.com/explorer/op/${tx["hash"]}";
+      var txJsonResponse = jsonDecode(await get(Uri.parse(txApi)).then((value) => value.body))[0];
+      TransactionType txType;
+      if (txJsonResponse["sender"] == (await currentReceivingAddress)) {
+        txType = TransactionType.outgoing;
+      } else {
+        txType = TransactionType.incoming;
       }
-      await db.addNewTransactionData(txs, walletId);
+      var theTx = Transaction(
+          walletId: walletId,
+          txid: txJsonResponse["hash"].toString(),
+          timestamp: DateTime.parse(txJsonResponse["time"].toString()).toUtc().millisecondsSinceEpoch ~/ 1000,
+          type: txType,
+          subType: TransactionSubType.none,
+          amount: (float.parse(txJsonResponse["volume"].toString()) * 1000000).toInt(),
+          amountString: Amount(
+              rawValue: BigInt.parse((float.parse(txJsonResponse["volume"].toString()) * 1000000).toString()),
+              fractionDigits: 6
+          ).toJsonString(),
+          fee: (float.parse(txJsonResponse["fee"].toString()) * 1000000).toInt(),
+          height: int.parse(txJsonResponse["height"].toString()),
+          isCancelled: false,
+          isLelantus: false,
+          slateId: "",
+          otherData: "",
+          inputs: [],
+          outputs: [],
+          nonce: 0,
+          numberOfMessages: null,
+      );
+      var theAddress = Address(
+          walletId: walletId,
+          value: txJsonResponse["receiver"].toString(),
+          publicKey: [], // TODO: Add public key
+          derivationIndex: 0,
+          derivationPath: null,
+          type: AddressType.unknown,
+          subType: AddressSubType.unknown,
+      );
+      txs.add(Tuple2(theTx, theAddress));
     }
+    await db.addNewTransactionData(txs, walletId);
   }
 
   Future<void> updateChainHeight() async {
diff --git a/lib/services/price.dart b/lib/services/price.dart
index 24d929062..e9cbacc96 100644
--- a/lib/services/price.dart
+++ b/lib/services/price.dart
@@ -100,7 +100,7 @@ class PriceAPI {
           Uri.parse("https://api.coingecko.com/api/v3/coins/markets?vs_currency"
               "=${baseCurrency.toLowerCase()}"
               "&ids=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin,"
-              "bitcoin-cash,namecoin,wownero,ethereum,particl,nano,banano"
+              "bitcoin-cash,namecoin,wownero,ethereum,particl,nano,banano,tezos"
               "&order=market_cap_desc&per_page=50&page=1&sparkline=false");
 
       final coinGeckoResponse = await client.get(

From 5c06d9dc596288a8166fca43e2aac25d25cbcd88 Mon Sep 17 00:00:00 2001
From: ryleedavis <rylee@cypherstack.com>
Date: Fri, 28 Jul 2023 10:32:50 -0600
Subject: [PATCH 09/39] format adjustments + remove tezos from themeAssetsv1

---
 lib/services/coins/tezos/tezos_wallet.dart | 202 ++++++++++++---------
 lib/themes/coin_icon_provider.dart         |   2 -
 lib/utilities/default_nodes.dart           |  10 +-
 3 files changed, 126 insertions(+), 88 deletions(-)

diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart
index 8faa15427..4f66df22e 100644
--- a/lib/services/coins/tezos/tezos_wallet.dart
+++ b/lib/services/coins/tezos/tezos_wallet.dart
@@ -1,33 +1,30 @@
 import 'dart:async';
 import 'dart:convert';
-import 'dart:ffi';
 
 import 'package:http/http.dart';
 import 'package:isar/isar.dart';
+import 'package:stackwallet/db/isar/main_db.dart';
 import 'package:stackwallet/models/balance.dart';
 import 'package:stackwallet/models/isar/models/blockchain_data/address.dart';
 import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart';
 import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart';
+import 'package:stackwallet/models/node_model.dart';
 import 'package:stackwallet/models/paymint/fee_object_model.dart';
 import 'package:stackwallet/services/coins/coin_service.dart';
+import 'package:stackwallet/services/mixins/wallet_cache.dart';
+import 'package:stackwallet/services/mixins/wallet_db.dart';
 import 'package:stackwallet/services/node_service.dart';
+import 'package:stackwallet/services/transaction_notification_tracker.dart';
 import 'package:stackwallet/utilities/amount/amount.dart';
-import 'package:stackwallet/utilities/enums/coin_enum.dart';
 import 'package:stackwallet/utilities/default_nodes.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
 import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
-
+import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/prefs.dart';
 import 'package:tezart/tezart.dart';
 import 'package:tuple/tuple.dart';
 
-import '../../../db/isar/main_db.dart';
-import '../../../models/node_model.dart';
-import '../../../utilities/flutter_secure_storage_interface.dart';
-import '../../../utilities/logger.dart';
-import '../../../utilities/prefs.dart';
-import '../../mixins/wallet_cache.dart';
-import '../../mixins/wallet_db.dart';
-import '../../transaction_notification_tracker.dart';
-
 const int MINIMUM_CONFIRMATIONS = 1;
 
 class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
@@ -51,7 +48,10 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   NodeModel? _xtzNode;
 
   NodeModel getCurrentNode() {
-    return _xtzNode ?? NodeService(secureStorageInterface: _secureStore).getPrimaryNodeFor(coin: Coin.tezos) ?? DefaultNodes.getNodeFor(Coin.tezos);
+    return _xtzNode ??
+        NodeService(secureStorageInterface: _secureStore)
+            .getPrimaryNodeFor(coin: Coin.tezos) ??
+        DefaultNodes.getNodeFor(Coin.tezos);
   }
 
   Future<Keystore> getKeystore() async {
@@ -111,12 +111,18 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   Balance? _balance;
 
   @override
-  Future<Map<String, dynamic>> prepareSend({required String address, required Amount amount, Map<String, dynamic>? args}) async {
+  Future<Map<String, dynamic>> prepareSend(
+      {required String address,
+      required Amount amount,
+      Map<String, dynamic>? args}) async {
     try {
       if (amount.decimals != coin.decimals) {
         throw Exception("Amount decimals do not match coin decimals!");
       }
-      var fee = int.parse((await estimateFeeFor(amount, (args!["feeRate"] as FeeRateType).index)).raw.toString());
+      var fee = int.parse((await estimateFeeFor(
+              amount, (args!["feeRate"] as FeeRateType).index))
+          .raw
+          .toString());
       Map<String, dynamic> txData = {
         "fee": fee,
         "address": address,
@@ -132,7 +138,10 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   Future<String> confirmSend({required Map<String, dynamic> txData}) async {
     try {
       final node = getCurrentNode().host + getCurrentNode().port.toString();
-      final int amountInMicroTez = ((int.parse((txData["recipientAmt"] as Amount).raw.toString()) * 1000000)).round();
+      final int amountInMicroTez =
+          ((int.parse((txData["recipientAmt"] as Amount).raw.toString()) *
+                  1000000))
+              .round();
       final int feeInMicroTez = int.parse(txData["fee"].toString());
       final String destinationAddress = txData["address"] as String;
       final String sourceAddress = await currentReceivingAddress;
@@ -155,7 +164,9 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   @override
   Future<Amount> estimateFeeFor(Amount amount, int feeRate) {
     return Future.value(
-      Amount(rawValue: BigInt.parse(100000.toString()), fractionDigits: coin.decimals),
+      Amount(
+          rawValue: BigInt.parse(100000.toString()),
+          fractionDigits: coin.decimals),
     );
   }
 
@@ -169,17 +180,18 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   Future<FeeObject> get fees async {
     // TODO: Change this to get fees from node and fix numberOfBlocks
     return FeeObject(
-        numberOfBlocksFast: 1,
-        numberOfBlocksAverage: 1,
-        numberOfBlocksSlow: 1,
-        fast: 1000000,
-        medium: 100000,
-        slow: 10000,
+      numberOfBlocksFast: 1,
+      numberOfBlocksAverage: 1,
+      numberOfBlocksSlow: 1,
+      fast: 1000000,
+      medium: 100000,
+      slow: 10000,
     );
   }
 
   @override
-  Future<void> fullRescan(int maxUnusedAddressGap, int maxNumberOfIndexesToCheck) {
+  Future<void> fullRescan(
+      int maxUnusedAddressGap, int maxNumberOfIndexesToCheck) {
     refresh();
     return Future.value();
   }
@@ -212,13 +224,13 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
     );
 
     final address = Address(
-        walletId: walletId,
-        value: newKeystore.address,
-        publicKey: [], // TODO: Add public key
-        derivationIndex: 0,
-        derivationPath: null,
-        type: AddressType.unknown,
-        subType: AddressSubType.unknown,
+      walletId: walletId,
+      value: newKeystore.address,
+      publicKey: [], // TODO: Add public key
+      derivationIndex: 0,
+      derivationPath: null,
+      type: AddressType.unknown,
+      subType: AddressSubType.unknown,
     );
 
     await db.putAddress(address);
@@ -255,13 +267,20 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   }
 
   @override
-  Future<String?> get mnemonicPassphrase => _secureStore.read(key: '${_walletId}_mnemonicPassphrase');
+  Future<String?> get mnemonicPassphrase =>
+      _secureStore.read(key: '${_walletId}_mnemonicPassphrase');
 
   @override
-  Future<String?> get mnemonicString => _secureStore.read(key: '${_walletId}_mnemonic');
+  Future<String?> get mnemonicString =>
+      _secureStore.read(key: '${_walletId}_mnemonic');
 
   @override
-  Future<void> recoverFromMnemonic({required String mnemonic, String? mnemonicPassphrase, required int maxUnusedAddressGap, required int maxNumberOfIndexesToCheck, required int height}) async {
+  Future<void> recoverFromMnemonic(
+      {required String mnemonic,
+      String? mnemonicPassphrase,
+      required int maxUnusedAddressGap,
+      required int maxNumberOfIndexesToCheck,
+      required int height}) async {
     if ((await mnemonicString) != null ||
         (await this.mnemonicPassphrase) != null) {
       throw Exception("Attempted to overwrite mnemonic on restore!");
@@ -274,13 +293,13 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
     );
 
     final address = Address(
-        walletId: walletId,
-        value: Keystore.fromMnemonic(mnemonic).address,
-        publicKey: [], // TODO: Add public key
-        derivationIndex: 0,
-        derivationPath: null,
-        type: AddressType.unknown,
-        subType: AddressSubType.unknown,
+      walletId: walletId,
+      value: Keystore.fromMnemonic(mnemonic).address,
+      publicKey: [], // TODO: Add public key
+      derivationIndex: 0,
+      derivationPath: null,
+      type: AddressType.unknown,
+      subType: AddressSubType.unknown,
     );
 
     await db.putAddress(address);
@@ -292,10 +311,16 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   }
 
   Future<void> updateBalance() async {
-    var api = "${getCurrentNode().host}:${getCurrentNode().port}/chains/main/blocks/head/context/contracts/${await currentReceivingAddress}/balance";
-    var theBalance = (await get(Uri.parse(api)).then((value) => value.body)).substring(1, (await get(Uri.parse(api)).then((value) => value.body)).length - 2);
-    Logging.instance.log("Balance for ${await currentReceivingAddress}: $theBalance", level: LogLevel.Info);
-    var balanceInAmount = Amount(rawValue: BigInt.parse(theBalance.toString()), fractionDigits: 6);
+    var api =
+        "${getCurrentNode().host}:${getCurrentNode().port}/chains/main/blocks/head/context/contracts/${await currentReceivingAddress}/balance";
+    var theBalance = (await get(Uri.parse(api)).then((value) => value.body))
+        .substring(1,
+            (await get(Uri.parse(api)).then((value) => value.body)).length - 2);
+    Logging.instance.log(
+        "Balance for ${await currentReceivingAddress}: $theBalance",
+        level: LogLevel.Info);
+    var balanceInAmount = Amount(
+        rawValue: BigInt.parse(theBalance.toString()), fractionDigits: 6);
     _balance = Balance(
       total: balanceInAmount,
       spendable: balanceInAmount,
@@ -307,12 +332,15 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
   Future<void> updateTransactions() async {
     // TODO: Use node RPC instead of tzstats API
-    var api = "https://api.tzstats.com/tables/op?address=${await currentReceivingAddress}";
-    var jsonResponse = jsonDecode(await get(Uri.parse(api)).then((value) => value.body));
+    var api =
+        "https://api.tzstats.com/tables/op?address=${await currentReceivingAddress}";
+    var jsonResponse =
+        jsonDecode(await get(Uri.parse(api)).then((value) => value.body));
     List<Tuple2<Transaction, Address>> txs = [];
     for (var tx in jsonResponse as List) {
       var txApi = "https://api.tzstats.com/explorer/op/${tx["hash"]}";
-      var txJsonResponse = jsonDecode(await get(Uri.parse(txApi)).then((value) => value.body))[0];
+      var txJsonResponse = jsonDecode(
+          await get(Uri.parse(txApi)).then((value) => value.body))[0];
       TransactionType txType;
       if (txJsonResponse["sender"] == (await currentReceivingAddress)) {
         txType = TransactionType.outgoing;
@@ -320,35 +348,41 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
         txType = TransactionType.incoming;
       }
       var theTx = Transaction(
-          walletId: walletId,
-          txid: txJsonResponse["hash"].toString(),
-          timestamp: DateTime.parse(txJsonResponse["time"].toString()).toUtc().millisecondsSinceEpoch ~/ 1000,
-          type: txType,
-          subType: TransactionSubType.none,
-          amount: (float.parse(txJsonResponse["volume"].toString()) * 1000000).toInt(),
-          amountString: Amount(
-              rawValue: BigInt.parse((float.parse(txJsonResponse["volume"].toString()) * 1000000).toString()),
-              fractionDigits: 6
-          ).toJsonString(),
-          fee: (float.parse(txJsonResponse["fee"].toString()) * 1000000).toInt(),
-          height: int.parse(txJsonResponse["height"].toString()),
-          isCancelled: false,
-          isLelantus: false,
-          slateId: "",
-          otherData: "",
-          inputs: [],
-          outputs: [],
-          nonce: 0,
-          numberOfMessages: null,
+        walletId: walletId,
+        txid: txJsonResponse["hash"].toString(),
+        timestamp: DateTime.parse(txJsonResponse["time"].toString())
+                .toUtc()
+                .millisecondsSinceEpoch ~/
+            1000,
+        type: txType,
+        subType: TransactionSubType.none,
+        amount: (float.parse(txJsonResponse["volume"].toString()) * 1000000)
+            .toInt(),
+        amountString: Amount(
+                rawValue: BigInt.parse(
+                    (float.parse(txJsonResponse["volume"].toString()) * 1000000)
+                        .toString()),
+                fractionDigits: 6)
+            .toJsonString(),
+        fee: (float.parse(txJsonResponse["fee"].toString()) * 1000000).toInt(),
+        height: int.parse(txJsonResponse["height"].toString()),
+        isCancelled: false,
+        isLelantus: false,
+        slateId: "",
+        otherData: "",
+        inputs: [],
+        outputs: [],
+        nonce: 0,
+        numberOfMessages: null,
       );
       var theAddress = Address(
-          walletId: walletId,
-          value: txJsonResponse["receiver"].toString(),
-          publicKey: [], // TODO: Add public key
-          derivationIndex: 0,
-          derivationPath: null,
-          type: AddressType.unknown,
-          subType: AddressSubType.unknown,
+        walletId: walletId,
+        value: txJsonResponse["receiver"].toString(),
+        publicKey: [], // TODO: Add public key
+        derivationIndex: 0,
+        derivationPath: null,
+        type: AddressType.unknown,
+        subType: AddressSubType.unknown,
       );
       txs.add(Tuple2(theTx, theAddress));
     }
@@ -356,8 +390,10 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   }
 
   Future<void> updateChainHeight() async {
-    var api = "${getCurrentNode().host}:${getCurrentNode().port}/chains/main/blocks/head/header/shell";
-    var jsonParsedResponse = jsonDecode(await get(Uri.parse(api)).then((value) => value.body));
+    var api =
+        "${getCurrentNode().host}:${getCurrentNode().port}/chains/main/blocks/head/header/shell";
+    var jsonParsedResponse =
+        jsonDecode(await get(Uri.parse(api)).then((value) => value.body));
     final int intHeight = int.parse(jsonParsedResponse["level"].toString());
     Logging.instance.log("Chain height: $intHeight", level: LogLevel.Info);
     await updateCachedChainHeight(intHeight);
@@ -375,9 +411,10 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   int get storedChainHeight => getCachedChainHeight();
 
   @override
-  Future<bool> testNetworkConnection() async{
+  Future<bool> testNetworkConnection() async {
     try {
-      await get(Uri.parse("${getCurrentNode().host}:${getCurrentNode().port}/chains/main/blocks/head/header/shell"));
+      await get(Uri.parse(
+          "${getCurrentNode().host}:${getCurrentNode().port}/chains/main/blocks/head/header/shell"));
       return true;
     } catch (e) {
       return false;
@@ -385,11 +422,14 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   }
 
   @override
-  Future<List<Transaction>> get transactions => db.getTransactions(walletId).findAll();
+  Future<List<Transaction>> get transactions =>
+      db.getTransactions(walletId).findAll();
 
   @override
   Future<void> updateNode(bool shouldRefresh) async {
-    _xtzNode = NodeService(secureStorageInterface: _secureStore).getPrimaryNodeFor(coin: coin) ?? DefaultNodes.getNodeFor(coin);
+    _xtzNode = NodeService(secureStorageInterface: _secureStore)
+            .getPrimaryNodeFor(coin: coin) ??
+        DefaultNodes.getNodeFor(coin);
 
     if (shouldRefresh) {
       await refresh();
diff --git a/lib/themes/coin_icon_provider.dart b/lib/themes/coin_icon_provider.dart
index acbfaed3f..9bd3990bb 100644
--- a/lib/themes/coin_icon_provider.dart
+++ b/lib/themes/coin_icon_provider.dart
@@ -43,8 +43,6 @@ final coinIconProvider = Provider.family<String, Coin>((ref, coin) {
         return assets.namecoin;
       case Coin.particl:
         return assets.particl;
-      case Coin.tezos:
-        return assets.tezos;
       case Coin.ethereum:
         return assets.ethereum;
       default:
diff --git a/lib/utilities/default_nodes.dart b/lib/utilities/default_nodes.dart
index 22f274d62..87b7849f4 100644
--- a/lib/utilities/default_nodes.dart
+++ b/lib/utilities/default_nodes.dart
@@ -179,10 +179,10 @@ abstract class DefaultNodes {
       enabled: true,
       coinName: Coin.particl.name,
       isFailover: true,
-      isDown: false
-  );
+      isDown: false);
 
-  static NodeModel get tezos => NodeModel( // TODO: Change this to stack wallet one
+  static NodeModel get tezos => NodeModel(
+      // TODO: Change this to stack wallet one
       host: "https://mainnet.api.tez.ie",
       port: 443,
       name: defaultName,
@@ -191,8 +191,7 @@ abstract class DefaultNodes {
       enabled: true,
       coinName: Coin.tezos.name,
       isFailover: true,
-      isDown: false
-  );
+      isDown: false);
 
   static NodeModel get nano => NodeModel(
       host: "https://rainstorm.city/api",
@@ -318,6 +317,7 @@ abstract class DefaultNodes {
 
       case Coin.banano:
         return banano;
+
       case Coin.tezos:
         return tezos;
 

From 724f6193d7f95e4f19eea89166af0f414d9a21b8 Mon Sep 17 00:00:00 2001
From: ryleedavis <rylee@cypherstack.com>
Date: Fri, 28 Jul 2023 10:50:05 -0600
Subject: [PATCH 10/39] merge conflicts

---
 .../manage_nodes_views/add_edit_node_view.dart       |  2 +-
 .../manage_nodes_views/node_details_view.dart        |  2 +-
 lib/services/price.dart                              | 12 ++++++------
 lib/utilities/constants.dart                         |  3 ++-
 lib/widgets/node_options_sheet.dart                  |  2 +-
 5 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
index eb100b8cd..781a566ef 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
@@ -199,7 +199,7 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
       case Coin.stellar:
       case Coin.stellarTestnet:
         throw UnimplementedError();
-        //TODO: check network/node
+      //TODO: check network/node
       case Coin.tezos:
       //TODO: check network/node
     }
diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
index ee9cf02e5..31a9c6717 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
@@ -176,7 +176,7 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> {
       case Coin.stellar:
       case Coin.stellarTestnet:
         throw UnimplementedError();
-        //TODO: check network/node
+      //TODO: check network/node
     }
 
     if (testPassed) {
diff --git a/lib/services/price.dart b/lib/services/price.dart
index 38f560244..c6f28673f 100644
--- a/lib/services/price.dart
+++ b/lib/services/price.dart
@@ -96,12 +96,12 @@ class PriceAPI {
     }
     Map<Coin, Tuple2<Decimal, double>> result = {};
     try {
-      final uri =
-          Uri.parse("https://api.coingecko.com/api/v3/coins/markets?vs_currency"
-              "=${baseCurrency.toLowerCase()}"
-              "&ids=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin,"
-              "bitcoin-cash,namecoin,wownero,ethereum,particl,nano,banano,stellar,tezos"
-              "&order=market_cap_desc&per_page=50&page=1&sparkline=false");
+      final uri = Uri.parse(
+          "https://api.coingecko.com/api/v3/coins/markets?vs_currency"
+          "=${baseCurrency.toLowerCase()}"
+          "&ids=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin,"
+          "bitcoin-cash,namecoin,wownero,ethereum,particl,nano,banano,stellar,tezos"
+          "&order=market_cap_desc&per_page=50&page=1&sparkline=false");
 
       final coinGeckoResponse = await client.get(
         uri,
diff --git a/lib/utilities/constants.dart b/lib/utilities/constants.dart
index b1e2e6b31..1253e08f1 100644
--- a/lib/utilities/constants.dart
+++ b/lib/utilities/constants.dart
@@ -42,7 +42,8 @@ abstract class Constants {
       BigInt.parse("1000000000000000000000000000000"); // 1*10^30
   static final BigInt _satsPerCoinBanano =
       BigInt.parse("100000000000000000000000000000"); // 1*10^29
-  static final BigInt _satsPerCoinStellar = BigInt.from(10000000); // https://developers.stellar.org/docs/fundamentals-and-concepts/stellar-data-structures/assets#amount-precision
+  static final BigInt _satsPerCoinStellar = BigInt.from(
+      10000000); // https://developers.stellar.org/docs/fundamentals-and-concepts/stellar-data-structures/assets#amount-precision
   static final BigInt _satsPerCoin = BigInt.from(100000000);
   static final BigInt _satsPerCoinTezos = BigInt.from(1000000);
   static const int _decimalPlaces = 8;
diff --git a/lib/widgets/node_options_sheet.dart b/lib/widgets/node_options_sheet.dart
index 9f7802536..953ac78a1 100644
--- a/lib/widgets/node_options_sheet.dart
+++ b/lib/widgets/node_options_sheet.dart
@@ -181,7 +181,7 @@ class NodeOptionsSheet extends ConsumerWidget {
       case Coin.stellar:
       case Coin.stellarTestnet:
         throw UnimplementedError();
-        //TODO: check network/node
+      //TODO: check network/node
     }
 
     if (testPassed) {

From 68f3bc8731e215d906ce2ad57dfca5814f86275e Mon Sep 17 00:00:00 2001
From: detherminal <76167420+detherminal@users.noreply.github.com>
Date: Fri, 28 Jul 2023 22:15:34 +0300
Subject: [PATCH 11/39] fix dependency conflict

---
 pubspec.lock | 72 ++++++++++++++++++++++++++++++++++++++++++++++------
 pubspec.yaml |  2 ++
 2 files changed, 66 insertions(+), 8 deletions(-)

diff --git a/pubspec.lock b/pubspec.lock
index cfdf7a710..111b58d75 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -25,6 +25,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.12.30"
+  ansicolor:
+    dependency: transitive
+    description:
+      name: ansicolor
+      sha256: "607f8fa9786f392043f169898923e6c59b4518242b68b8862eb8a8b7d9c30b4a"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.0.1"
   archive:
     dependency: "direct main"
     description:
@@ -298,10 +306,10 @@ packages:
     dependency: "direct main"
     description:
       name: crypto
-      sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
+      sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67
       url: "https://pub.dev"
     source: hosted
-    version: "3.0.3"
+    version: "3.0.2"
   cryptography:
     dependency: transitive
     description:
@@ -451,13 +459,13 @@ packages:
     source: hosted
     version: "0.6.0"
   dio:
-    dependency: transitive
+    dependency: "direct overridden"
     description:
       name: dio
-      sha256: "3866d67f93523161b643187af65f5ac08bc991a5bcdaf41a2d587fe4ccb49993"
+      sha256: "7d328c4d898a61efc3cd93655a0955858e29a0aa647f0f9e02d59b3bb275e2e8"
       url: "https://pub.dev"
     source: hosted
-    version: "5.3.0"
+    version: "4.0.6"
   dropdown_button2:
     dependency: "direct main"
     description:
@@ -942,6 +950,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "3.0.2"
+  json_serializable:
+    dependency: transitive
+    description:
+      name: json_serializable
+      sha256: aa1f5a8912615733e0fdc7a02af03308933c93235bdc8d50d0b0c8a8ccb0b969
+      url: "https://pub.dev"
+    source: hosted
+    version: "6.7.1"
   keyboard_dismisser:
     dependency: "direct main"
     description:
@@ -1005,6 +1021,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.2.0"
+  memoize:
+    dependency: transitive
+    description:
+      name: memoize
+      sha256: "51481d328c86cbdc59711369179bac88551ca0556569249be5317e66fc796cac"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.0.0"
   meta:
     dependency: transitive
     description:
@@ -1230,13 +1254,13 @@ packages:
     source: hosted
     version: "5.4.0"
   pinenacl:
-    dependency: transitive
+    dependency: "direct overridden"
     description:
       name: pinenacl
-      sha256: "3a5503637587d635647c93ea9a8fecf48a420cc7deebe6f1fc85c2a5637ab327"
+      sha256: e5fb0bce1717b7f136f35ee98b5c02b3e6383211f8a77ca882fa7812232a07b9
       url: "https://pub.dev"
     source: hosted
-    version: "0.5.1"
+    version: "0.3.4"
   platform:
     dependency: transitive
     description:
@@ -1269,6 +1293,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.5.1"
+  pretty_dio_logger:
+    dependency: transitive
+    description:
+      name: pretty_dio_logger
+      sha256: "00b80053063935cf9a6190da344c5373b9d0e92da4c944c878ff2fbef0ef6dc2"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.3.1"
   process:
     dependency: transitive
     description:
@@ -1317,6 +1349,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "4.1.0"
+  quiver:
+    dependency: transitive
+    description:
+      name: quiver
+      sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.2.1"
   rational:
     dependency: transitive
     description:
@@ -1325,6 +1365,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.2.2"
+  retry:
+    dependency: transitive
+    description:
+      name: retry
+      sha256: "822e118d5b3aafed083109c72d5f484c6dc66707885e07c0fbcb8b986bba7efc"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.1.2"
   riverpod:
     dependency: transitive
     description:
@@ -1547,6 +1595,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.5.1"
+  tezart:
+    dependency: "direct main"
+    description:
+      name: tezart
+      sha256: "35d526f2e6ca250c64461ebfb4fa9f64b6599fab8c4242c8e89ae27d4ac2e15a"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.0.5"
   time:
     dependency: transitive
     description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 506d6d431..4e4a6755e 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -202,6 +202,8 @@ dependency_overrides:
 
   crypto: 3.0.2
   analyzer: ^5.2.0
+  pinenacl: ^0.3.3
+  dio : ^4.0.0
 # For information on the generic Dart part of this file, see the
 # following page: https://dart.dev/tools/pub/pubspec
 

From f4688bd041974d25219734df285ba2bd679d6ed7 Mon Sep 17 00:00:00 2001
From: detherminal <76167420+detherminal@users.noreply.github.com>
Date: Fri, 28 Jul 2023 22:16:04 +0300
Subject: [PATCH 12/39] xtz: filter other operations

---
 lib/services/coins/tezos/tezos_wallet.dart | 101 +++++++++++----------
 1 file changed, 51 insertions(+), 50 deletions(-)

diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart
index 4f66df22e..9fa8e499f 100644
--- a/lib/services/coins/tezos/tezos_wallet.dart
+++ b/lib/services/coins/tezos/tezos_wallet.dart
@@ -332,60 +332,61 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
   Future<void> updateTransactions() async {
     // TODO: Use node RPC instead of tzstats API
-    var api =
-        "https://api.tzstats.com/tables/op?address=${await currentReceivingAddress}";
-    var jsonResponse =
-        jsonDecode(await get(Uri.parse(api)).then((value) => value.body));
+    var api = "https://api.tzstats.com/tables/op?address=${await currentReceivingAddress}";
+    var jsonResponse = jsonDecode(await get(Uri.parse(api)).then((value) => value.body));
     List<Tuple2<Transaction, Address>> txs = [];
     for (var tx in jsonResponse as List) {
-      var txApi = "https://api.tzstats.com/explorer/op/${tx["hash"]}";
-      var txJsonResponse = jsonDecode(
-          await get(Uri.parse(txApi)).then((value) => value.body))[0];
-      TransactionType txType;
-      if (txJsonResponse["sender"] == (await currentReceivingAddress)) {
-        txType = TransactionType.outgoing;
-      } else {
-        txType = TransactionType.incoming;
+      if (tx[1] == "transaction") {
+        var txApi = "https://api.tzstats.com/explorer/op/${tx[2]}";
+        var txJsonResponse = jsonDecode(await get(Uri.parse(txApi)).then((value) => value.body));
+        // Check if list is larger than 1 (if it is, it's a batch transaction)
+        if (!((txJsonResponse as List).length > 1)) {
+          for (var (opJson as Map) in txJsonResponse) {
+            if (opJson.containsKey("volume")) { // This is to check if transaction is a token transfer
+              TransactionType txType;
+              if (opJson["sender"] == (await currentReceivingAddress)) {
+                txType = TransactionType.outgoing;
+              } else {
+                txType = TransactionType.incoming;
+              }
+              var theTx = Transaction(
+                walletId: walletId,
+                txid: opJson["hash"].toString(),
+                timestamp: DateTime.parse(opJson["time"].toString()).toUtc().millisecondsSinceEpoch ~/ 1000,
+                type: txType,
+                subType: TransactionSubType.none,
+                amount: (float.parse(opJson["volume"].toString()) * 1000000).toInt(),
+                amountString: Amount(
+                    rawValue: BigInt.parse((float.parse(opJson["volume"].toString()) * 1000000).toInt().toString()),
+                    fractionDigits: 6
+                ).toJsonString(),
+                fee: (float.parse(opJson["fee"].toString()) * 1000000).toInt(),
+                height: int.parse(opJson["height"].toString()),
+                isCancelled: false,
+                isLelantus: false,
+                slateId: "",
+                otherData: "",
+                inputs: [],
+                outputs: [],
+                nonce: 0,
+                numberOfMessages: null,
+              );
+              var theAddress = Address(
+                walletId: walletId,
+                value: opJson["receiver"].toString(),
+                publicKey: [], // TODO: Add public key
+                derivationIndex: 0,
+                derivationPath: null,
+                type: AddressType.unknown,
+                subType: AddressSubType.unknown,
+              );
+              txs.add(Tuple2(theTx, theAddress));
+            }
+          }
+        }
       }
-      var theTx = Transaction(
-        walletId: walletId,
-        txid: txJsonResponse["hash"].toString(),
-        timestamp: DateTime.parse(txJsonResponse["time"].toString())
-                .toUtc()
-                .millisecondsSinceEpoch ~/
-            1000,
-        type: txType,
-        subType: TransactionSubType.none,
-        amount: (float.parse(txJsonResponse["volume"].toString()) * 1000000)
-            .toInt(),
-        amountString: Amount(
-                rawValue: BigInt.parse(
-                    (float.parse(txJsonResponse["volume"].toString()) * 1000000)
-                        .toString()),
-                fractionDigits: 6)
-            .toJsonString(),
-        fee: (float.parse(txJsonResponse["fee"].toString()) * 1000000).toInt(),
-        height: int.parse(txJsonResponse["height"].toString()),
-        isCancelled: false,
-        isLelantus: false,
-        slateId: "",
-        otherData: "",
-        inputs: [],
-        outputs: [],
-        nonce: 0,
-        numberOfMessages: null,
-      );
-      var theAddress = Address(
-        walletId: walletId,
-        value: txJsonResponse["receiver"].toString(),
-        publicKey: [], // TODO: Add public key
-        derivationIndex: 0,
-        derivationPath: null,
-        type: AddressType.unknown,
-        subType: AddressSubType.unknown,
-      );
-      txs.add(Tuple2(theTx, theAddress));
     }
+    Logging.instance.log("Transactions: $txs", level: LogLevel.Info);
     await db.addNewTransactionData(txs, walletId);
   }
 

From a1ef84fbe64f5e815bdfd24e4854a189720f1589 Mon Sep 17 00:00:00 2001
From: detherminal <76167420+detherminal@users.noreply.github.com>
Date: Fri, 28 Jul 2023 23:00:14 +0300
Subject: [PATCH 13/39] fix stellarTestNet and dependency problems

---
 .../add_edit_node_view.dart                   |  5 +++-
 .../manage_nodes_views/node_details_view.dart |  2 +-
 lib/services/coins/coin_service.dart          |  9 ++++++++
 lib/themes/color_theme.dart                   |  2 +-
 lib/themes/stack_colors.dart                  |  2 +-
 lib/utilities/address_utils.dart              |  2 +-
 lib/utilities/amount/amount_unit.dart         |  2 +-
 lib/utilities/block_explorers.dart            |  2 +-
 lib/utilities/constants.dart                  | 10 ++++----
 lib/utilities/default_nodes.dart              |  6 ++---
 lib/utilities/enums/coin_enum.dart            | 23 +++++++++++--------
 .../enums/derive_path_type_enum.dart          |  2 +-
 lib/widgets/node_card.dart                    |  2 +-
 lib/widgets/node_options_sheet.dart           |  2 +-
 pubspec.lock                                  | 10 ++++----
 pubspec.yaml                                  |  3 +--
 16 files changed, 49 insertions(+), 35 deletions(-)

diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
index 781a566ef..4bd42f70b 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
@@ -197,7 +197,7 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
       case Coin.nano:
       case Coin.banano:
       case Coin.stellar:
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         throw UnimplementedError();
       //TODO: check network/node
       case Coin.tezos:
@@ -732,11 +732,14 @@ class _NodeFormState extends ConsumerState<NodeForm> {
       case Coin.namecoin:
       case Coin.bitcoincash:
       case Coin.particl:
+      case Coin.stellar:
+      case Coin.tezos:
       case Coin.bitcoinTestNet:
       case Coin.litecoinTestNet:
       case Coin.bitcoincashTestnet:
       case Coin.firoTestNet:
       case Coin.dogecoinTestNet:
+      case Coin.stellarTestNet:
       case Coin.epicCash:
       case Coin.nano:
       case Coin.banano:
diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
index 31a9c6717..d22af6e25 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
@@ -174,7 +174,7 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> {
       case Coin.banano:
       case Coin.tezos:
       case Coin.stellar:
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         throw UnimplementedError();
       //TODO: check network/node
     }
diff --git a/lib/services/coins/coin_service.dart b/lib/services/coins/coin_service.dart
index 394ff5fc1..9ee397e0d 100644
--- a/lib/services/coins/coin_service.dart
+++ b/lib/services/coins/coin_service.dart
@@ -229,6 +229,15 @@ abstract class CoinServiceAPI {
           tracker: tracker,
         );
 
+      case Coin.stellarTestNet:
+        return StellarWallet(
+          walletId: walletId,
+          walletName: walletName,
+          coin: coin,
+          secureStore: secureStorageInterface,
+          tracker: tracker,
+        );
+
       case Coin.tezos:
         return TezosWallet(
           walletId: walletId,
diff --git a/lib/themes/color_theme.dart b/lib/themes/color_theme.dart
index abec28d4e..0e6816dd8 100644
--- a/lib/themes/color_theme.dart
+++ b/lib/themes/color_theme.dart
@@ -65,7 +65,7 @@ class CoinThemeColorDefault {
       case Coin.particl:
         return particl;
       case Coin.stellar:
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         return stellar;
       case Coin.nano:
         return nano;
diff --git a/lib/themes/stack_colors.dart b/lib/themes/stack_colors.dart
index cbec0077a..fde5219cf 100644
--- a/lib/themes/stack_colors.dart
+++ b/lib/themes/stack_colors.dart
@@ -1708,7 +1708,7 @@ class StackColors extends ThemeExtension<StackColors> {
       case Coin.particl:
         return _coin.particl;
       case Coin.stellar:
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         return _coin.stellar;
       case Coin.nano:
         return _coin.nano;
diff --git a/lib/utilities/address_utils.dart b/lib/utilities/address_utils.dart
index 3fa895282..b4974d8c6 100644
--- a/lib/utilities/address_utils.dart
+++ b/lib/utilities/address_utils.dart
@@ -143,7 +143,7 @@ class AddressUtils {
         return Address.validateAddress(address, firoTestNetwork);
       case Coin.dogecoinTestNet:
         return Address.validateAddress(address, dogecointestnet);
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         return RegExp(r"^[G][A-Z0-9]{55}$").hasMatch(address);
     }
   }
diff --git a/lib/utilities/amount/amount_unit.dart b/lib/utilities/amount/amount_unit.dart
index 6a646fd11..00055a0fe 100644
--- a/lib/utilities/amount/amount_unit.dart
+++ b/lib/utilities/amount/amount_unit.dart
@@ -51,7 +51,7 @@ enum AmountUnit {
       case Coin.eCash:
       case Coin.epicCash:
       case Coin.stellar: // TODO: check if this is correct
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
       case Coin.tezos:
         return AmountUnit.values.sublist(0, 4);
 
diff --git a/lib/utilities/block_explorers.dart b/lib/utilities/block_explorers.dart
index bb4ac06fb..ddc055fb1 100644
--- a/lib/utilities/block_explorers.dart
+++ b/lib/utilities/block_explorers.dart
@@ -60,7 +60,7 @@ Uri getDefaultBlockExplorerUrlFor({
       return Uri.parse("https://www.nanolooker.com/block/$txid");
     case Coin.banano:
       return Uri.parse("https://www.bananolooker.com/block/$txid");
-    case Coin.stellarTestnet:
+    case Coin.stellarTestNet:
       return Uri.parse("https://testnet.stellarchain.io/transactions/$txid");
     case Coin.tezos:
       return Uri.parse("https://tzstats.com/$txid");
diff --git a/lib/utilities/constants.dart b/lib/utilities/constants.dart
index 1253e08f1..1bd3a5a50 100644
--- a/lib/utilities/constants.dart
+++ b/lib/utilities/constants.dart
@@ -102,7 +102,7 @@ abstract class Constants {
         return _satsPerCoinECash;
 
       case Coin.stellar:
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         return _satsPerCoinStellar;
 
       case Coin.tezos:
@@ -146,7 +146,7 @@ abstract class Constants {
         return _decimalPlacesECash;
 
       case Coin.stellar:
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         return _decimalPlacesStellar;
 
       case Coin.tezos:
@@ -174,7 +174,7 @@ abstract class Constants {
       case Coin.particl:
       case Coin.nano:
       case Coin.stellar:
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         values.addAll([24, 12]);
         break;
       case Coin.banano:
@@ -238,7 +238,7 @@ abstract class Constants {
         return 1;
 
       case Coin.stellar:
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         return 5;
 
       case Coin.tezos:
@@ -271,7 +271,7 @@ abstract class Constants {
       case Coin.nano:
       case Coin.banano:
       case Coin.stellar:
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
       case Coin.tezos:
         return 24;
 
diff --git a/lib/utilities/default_nodes.dart b/lib/utilities/default_nodes.dart
index 7a4daf2f2..7fed3d7fd 100644
--- a/lib/utilities/default_nodes.dart
+++ b/lib/utilities/default_nodes.dart
@@ -292,10 +292,10 @@ abstract class DefaultNodes {
     host: "https://horizon-testnet.stellar.org/",
     port: 50022,
     name: defaultName,
-    id: _nodeId(Coin.stellarTestnet),
+    id: _nodeId(Coin.stellarTestNet),
     useSSL: true,
     enabled: true,
-    coinName: Coin.stellarTestnet.name,
+    coinName: Coin.stellarTestNet.name,
     isFailover: true,
     isDown: false,
   );
@@ -365,7 +365,7 @@ abstract class DefaultNodes {
       case Coin.dogecoinTestNet:
         return dogecoinTestnet;
 
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         return stellarTestnet;
     }
   }
diff --git a/lib/utilities/enums/coin_enum.dart b/lib/utilities/enums/coin_enum.dart
index b62e4ea67..2e5062b6d 100644
--- a/lib/utilities/enums/coin_enum.dart
+++ b/lib/utilities/enums/coin_enum.dart
@@ -60,9 +60,10 @@ enum Coin {
   dogecoinTestNet,
   firoTestNet,
   litecoinTestNet,
+  stellarTestNet,
 }
 
-final int kTestNetCoinCount = 4; // Util.isDesktop ? 5 : 4;
+final int kTestNetCoinCount = 5; // Util.isDesktop ? 5 : 4;
 // remove firotestnet for now
 
 extension CoinExt on Coin {
@@ -110,6 +111,8 @@ extension CoinExt on Coin {
         return "tFiro";
       case Coin.dogecoinTestNet:
         return "tDogecoin";
+      case Coin.stellarTestNet:
+        return "tStellar";
     }
   }
 
@@ -157,7 +160,7 @@ extension CoinExt on Coin {
         return "tFIRO";
       case Coin.dogecoinTestNet:
         return "tDOGE";
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         return "tXLM";
     }
   }
@@ -207,7 +210,7 @@ extension CoinExt on Coin {
         return "firo";
       case Coin.dogecoinTestNet:
         return "dogecoin";
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         return "stellar";
     }
   }
@@ -237,7 +240,7 @@ extension CoinExt on Coin {
       case Coin.nano:
       case Coin.banano:
       case Coin.stellar:
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         return false;
     }
   }
@@ -267,7 +270,7 @@ extension CoinExt on Coin {
       case Coin.nano:
       case Coin.banano:
       case Coin.stellar:
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         return false;
     }
   }
@@ -297,7 +300,7 @@ extension CoinExt on Coin {
       case Coin.litecoinTestNet:
       case Coin.bitcoincashTestnet:
       case Coin.firoTestNet:
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         return true;
     }
   }
@@ -337,7 +340,7 @@ extension CoinExt on Coin {
       case Coin.firoTestNet:
         return Coin.firo;
 
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         return Coin.stellar;
     }
   }
@@ -380,7 +383,7 @@ extension CoinExt on Coin {
         return particl.MINIMUM_CONFIRMATIONS;
 
       case Coin.stellar:
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         return xlm.MINIMUM_CONFIRMATIONS;
 
       case Coin.tezos:
@@ -500,7 +503,7 @@ Coin coinFromPrettyName(String name) {
     case "Stellar Testnet":
     case "stellarTestnet":
     case "tStellar":
-      return Coin.stellarTestnet;
+      return Coin.stellarTestNet;
 
     default:
       throw ArgumentError.value(
@@ -556,7 +559,7 @@ Coin coinFromTickerCaseInsensitive(String ticker) {
     case "ban":
       return Coin.banano;
     case "txlm":
-      return Coin.stellarTestnet;
+      return Coin.stellarTestNet;
     default:
       throw ArgumentError.value(
           ticker, "name", "No Coin enum value with that ticker");
diff --git a/lib/utilities/enums/derive_path_type_enum.dart b/lib/utilities/enums/derive_path_type_enum.dart
index 5b94f41f6..f3c456f67 100644
--- a/lib/utilities/enums/derive_path_type_enum.dart
+++ b/lib/utilities/enums/derive_path_type_enum.dart
@@ -50,7 +50,7 @@ extension DerivePathTypeExt on DerivePathType {
       case Coin.nano:
       case Coin.banano:
       case Coin.stellar:
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
       case Coin.tezos: // TODO: Is this true?
         throw UnsupportedError(
             "$coin does not use bitcoin style derivation paths");
diff --git a/lib/widgets/node_card.dart b/lib/widgets/node_card.dart
index 661af4190..8d4c29ac2 100644
--- a/lib/widgets/node_card.dart
+++ b/lib/widgets/node_card.dart
@@ -196,7 +196,7 @@ class _NodeCardState extends ConsumerState<NodeCard> {
       case Coin.banano:
       case Coin.tezos:
       case Coin.stellar:
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         throw UnimplementedError();
         //TODO: check network/node
     }
diff --git a/lib/widgets/node_options_sheet.dart b/lib/widgets/node_options_sheet.dart
index 953ac78a1..63fd2b13e 100644
--- a/lib/widgets/node_options_sheet.dart
+++ b/lib/widgets/node_options_sheet.dart
@@ -179,7 +179,7 @@ class NodeOptionsSheet extends ConsumerWidget {
       case Coin.banano:
       case Coin.tezos:
       case Coin.stellar:
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         throw UnimplementedError();
       //TODO: check network/node
     }
diff --git a/pubspec.lock b/pubspec.lock
index 111b58d75..c01aca249 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -459,7 +459,7 @@ packages:
     source: hosted
     version: "0.6.0"
   dio:
-    dependency: "direct overridden"
+    dependency: transitive
     description:
       name: dio
       sha256: "7d328c4d898a61efc3cd93655a0955858e29a0aa647f0f9e02d59b3bb275e2e8"
@@ -1297,10 +1297,10 @@ packages:
     dependency: transitive
     description:
       name: pretty_dio_logger
-      sha256: "00b80053063935cf9a6190da344c5373b9d0e92da4c944c878ff2fbef0ef6dc2"
+      sha256: "948f7eeb36e7aa0760b51c1a8e3331d4b21e36fabd39efca81f585ed93893544"
       url: "https://pub.dev"
     source: hosted
-    version: "1.3.1"
+    version: "1.2.0-beta-1"
   process:
     dependency: transitive
     description:
@@ -1519,10 +1519,10 @@ packages:
     dependency: "direct main"
     description:
       name: stellar_flutter_sdk
-      sha256: "7a9b7dc76018bbd0b9c828045cf0e26e07ec44208fb1a1733273de2390205475"
+      sha256: "4c55b1b6dfbde7f89bba59a422754280715fa3b5726cff5e7eeaed454d2c4b89"
       url: "https://pub.dev"
     source: hosted
-    version: "1.6.0"
+    version: "1.5.3"
   stream_channel:
     dependency: transitive
     description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 4e4a6755e..e3fa11745 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -138,7 +138,7 @@ dependencies:
   desktop_drop: ^0.4.1
   nanodart: ^2.0.0
   basic_utils: ^5.5.4
-  stellar_flutter_sdk: ^1.6.0
+  stellar_flutter_sdk: ^1.5.3
   tezart: ^2.0.5
 
 dev_dependencies:
@@ -203,7 +203,6 @@ dependency_overrides:
   crypto: 3.0.2
   analyzer: ^5.2.0
   pinenacl: ^0.3.3
-  dio : ^4.0.0
 # For information on the generic Dart part of this file, see the
 # following page: https://dart.dev/tools/pub/pubspec
 

From 182a8cc73252fc9799c2d131ea7a7168599f5026 Mon Sep 17 00:00:00 2001
From: detherminal <76167420+detherminal@users.noreply.github.com>
Date: Sun, 6 Aug 2023 00:16:19 +0300
Subject: [PATCH 14/39] implement fees and sending?

---
 lib/services/coins/tezos/tezos_wallet.dart | 66 +++++++++++++++++-----
 1 file changed, 51 insertions(+), 15 deletions(-)

diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart
index 9fa8e499f..e62a5afb0 100644
--- a/lib/services/coins/tezos/tezos_wallet.dart
+++ b/lib/services/coins/tezos/tezos_wallet.dart
@@ -144,8 +144,13 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
               .round();
       final int feeInMicroTez = int.parse(txData["fee"].toString());
       final String destinationAddress = txData["address"] as String;
-      final String sourceAddress = await currentReceivingAddress;
-      return Future.value(""); // TODO: return tx hash
+      final secretKey = Keystore.fromMnemonic((await mnemonicString)!).secretKey;
+      Logging.instance.log(secretKey, level: LogLevel.Info);
+      final sourceKeyStore = Keystore.fromSecretKey(secretKey);
+      final client = TezartClient("${getCurrentNode().host}:${getCurrentNode().port}");
+      final operation = await client.transferOperation(source: sourceKeyStore, destination: destinationAddress, amount: amountInMicroTez, customFee: feeInMicroTez);
+      await operation.executeAndMonitor(); // This line gives an error
+      return Future.value("");
     } catch (e) {
       Logging.instance.log(e.toString(), level: LogLevel.Error);
       return Future.error(e);
@@ -162,12 +167,29 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   }
 
   @override
-  Future<Amount> estimateFeeFor(Amount amount, int feeRate) {
-    return Future.value(
-      Amount(
-          rawValue: BigInt.parse(100000.toString()),
-          fractionDigits: coin.decimals),
-    );
+  Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
+    // TODO: Check if this is correct
+    var api = "https://api.tzstats.com/series/op?start_date=today&collapse=10d";
+    var response = jsonDecode((await get(Uri.parse(api))).body)[0];
+    double totalFees = response[4] as double;
+    int totalTxs = response[8] as int;
+    int feePerTx = (totalFees / totalTxs * 1000000).floor();
+    int estimatedFee = 0;
+    Logging.instance.log("feePerTx:$feePerTx", level: LogLevel.Info);
+    Logging.instance.log("feeRate:$feeRate", level: LogLevel.Info);
+    switch (feeRate) {
+      case 0:
+        estimatedFee = feePerTx * 2;
+      case 1:
+        estimatedFee = feePerTx;
+      case 2:
+      case 3:
+        estimatedFee = (feePerTx / 2).floor();
+      default:
+        estimatedFee = feeRate;
+    }
+    Logging.instance.log("estimatedFee:$estimatedFee", level: LogLevel.Info);
+    return Amount(rawValue: BigInt.from(estimatedFee), fractionDigits: 6);
   }
 
   @override
@@ -178,14 +200,21 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
   @override
   Future<FeeObject> get fees async {
-    // TODO: Change this to get fees from node and fix numberOfBlocks
+    // TODO: Check if this is correct
+    var api = "https://api.tzstats.com/series/op?start_date=today&collapse=10d";
+    var response = jsonDecode((await get(Uri.parse(api))).body);
+    double totalFees = response[0][4] as double;
+    int totalTxs = response[0][8] as int;
+    int feePerTx = (totalFees / totalTxs * 1000000).floor();
+    Logging.instance.log("feePerTx:$feePerTx", level: LogLevel.Info);
+    // TODO: fix numberOfBlocks
     return FeeObject(
-      numberOfBlocksFast: 1,
-      numberOfBlocksAverage: 1,
-      numberOfBlocksSlow: 1,
-      fast: 1000000,
-      medium: 100000,
-      slow: 10000,
+      numberOfBlocksFast: 3,
+      numberOfBlocksAverage: 10,
+      numberOfBlocksSlow: 30,
+      fast: (feePerTx * 2),
+      medium: feePerTx,
+      slow: (feePerTx / 2).floor(),
     );
   }
 
@@ -213,6 +242,13 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
   @override
   Future<void> initializeNew() async {
+    if ((await mnemonicString) != null || (await mnemonicPassphrase) != null) {
+      throw Exception(
+          "Attempted to overwrite mnemonic on generate new wallet!");
+    }
+
+    await _prefs.init();
+
     var newKeystore = Keystore.random();
     await _secureStore.write(
       key: '${_walletId}_mnemonic',

From d785a2ef839bde2019faee65f407fc653ac1b5b1 Mon Sep 17 00:00:00 2001
From: likho <likhojiba@gmail.com>
Date: Mon, 14 Aug 2023 10:14:47 +0200
Subject: [PATCH 15/39] Fix error with Stellar pretty name not found

---
 lib/utilities/enums/coin_enum.dart | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/utilities/enums/coin_enum.dart b/lib/utilities/enums/coin_enum.dart
index 2e5062b6d..8db5d4843 100644
--- a/lib/utilities/enums/coin_enum.dart
+++ b/lib/utilities/enums/coin_enum.dart
@@ -502,6 +502,7 @@ Coin coinFromPrettyName(String name) {
 
     case "Stellar Testnet":
     case "stellarTestnet":
+    case "stellarTestNet":
     case "tStellar":
       return Coin.stellarTestNet;
 

From a6d39418584cb884d4ba43a353d57af4d1cb1f2b Mon Sep 17 00:00:00 2001
From: likho <likhojiba@gmail.com>
Date: Mon, 14 Aug 2023 16:36:27 +0200
Subject: [PATCH 16/39] Fix send and refactoring

---
 lib/services/coins/tezos/tezos_wallet.dart | 92 ++++++++++++++--------
 1 file changed, 58 insertions(+), 34 deletions(-)

diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart
index e62a5afb0..3ecc94eb8 100644
--- a/lib/services/coins/tezos/tezos_wallet.dart
+++ b/lib/services/coins/tezos/tezos_wallet.dart
@@ -1,6 +1,7 @@
 import 'dart:async';
 import 'dart:convert';
 
+import 'package:decimal/decimal.dart';
 import 'package:http/http.dart';
 import 'package:isar/isar.dart';
 import 'package:stackwallet/db/isar/main_db.dart';
@@ -137,18 +138,26 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   @override
   Future<String> confirmSend({required Map<String, dynamic> txData}) async {
     try {
-      final node = getCurrentNode().host + getCurrentNode().port.toString();
-      final int amountInMicroTez =
-          ((int.parse((txData["recipientAmt"] as Amount).raw.toString()) *
-                  1000000))
-              .round();
+
+      final amount = txData["recipientAmt"] as Amount;
+      final amountInMicroTez =
+          amount.decimal * Decimal.fromInt(1000000);
+      final microtezToInt = int.parse(amountInMicroTez.toString());
+
       final int feeInMicroTez = int.parse(txData["fee"].toString());
       final String destinationAddress = txData["address"] as String;
       final secretKey = Keystore.fromMnemonic((await mnemonicString)!).secretKey;
       Logging.instance.log(secretKey, level: LogLevel.Info);
       final sourceKeyStore = Keystore.fromSecretKey(secretKey);
-      final client = TezartClient("${getCurrentNode().host}:${getCurrentNode().port}");
-      final operation = await client.transferOperation(source: sourceKeyStore, destination: destinationAddress, amount: amountInMicroTez, customFee: feeInMicroTez);
+      final client = TezartClient(getCurrentNode().host);
+      //TODO - Update gas Limit
+      final operation = await client.transferOperation(
+          source: sourceKeyStore,
+          destination: destinationAddress,
+          amount: microtezToInt,
+          customFee: feeInMicroTez,
+          customGasLimit: 400
+      );
       await operation.executeAndMonitor(); // This line gives an error
       return Future.value("");
     } catch (e) {
@@ -189,7 +198,7 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
         estimatedFee = feeRate;
     }
     Logging.instance.log("estimatedFee:$estimatedFee", level: LogLevel.Info);
-    return Amount(rawValue: BigInt.from(estimatedFee), fractionDigits: 6);
+    return Amount(rawValue: BigInt.from(estimatedFee), fractionDigits: coin.decimals);
   }
 
   @override
@@ -347,33 +356,43 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   }
 
   Future<void> updateBalance() async {
-    var api =
-        "${getCurrentNode().host}:${getCurrentNode().port}/chains/main/blocks/head/context/contracts/${await currentReceivingAddress}/balance";
-    var theBalance = (await get(Uri.parse(api)).then((value) => value.body))
-        .substring(1,
-            (await get(Uri.parse(api)).then((value) => value.body)).length - 2);
-    Logging.instance.log(
-        "Balance for ${await currentReceivingAddress}: $theBalance",
-        level: LogLevel.Info);
-    var balanceInAmount = Amount(
-        rawValue: BigInt.parse(theBalance.toString()), fractionDigits: 6);
-    _balance = Balance(
-      total: balanceInAmount,
-      spendable: balanceInAmount,
-      blockedTotal: Amount(rawValue: BigInt.parse("0"), fractionDigits: 6),
-      pendingSpendable: Amount(rawValue: BigInt.parse("0"), fractionDigits: 6),
-    );
-    await updateCachedBalance(_balance!);
+
+    try {
+      var api =
+          "${getCurrentNode().host}/chains/main/blocks/head/context/contracts/${await currentReceivingAddress}/balance";
+      var theBalance = (await get(Uri.parse(api)).then((value) => value.body))
+          .substring(1,
+          (await get(Uri.parse(api)).then((value) => value.body)).length - 2);
+      Logging.instance.log(
+          "Balance for ${await currentReceivingAddress}: $theBalance",
+          level: LogLevel.Info);
+      var balanceInAmount = Amount(
+          rawValue: BigInt.parse(theBalance.toString()), fractionDigits: coin.decimals);
+      _balance = Balance(
+        total: balanceInAmount,
+        spendable: balanceInAmount,
+        blockedTotal: Amount(rawValue: BigInt.parse("0"), fractionDigits: coin.decimals),
+        pendingSpendable: Amount(rawValue: BigInt.parse("0"), fractionDigits: coin.decimals),
+      );
+      await updateCachedBalance(_balance!);
+    } catch (e, s) {
+      Logging.instance.log("ERROR GETTING BALANCE ${e.toString()}", level: LogLevel.Error);
+    }
+
   }
 
   Future<void> updateTransactions() async {
+
     // TODO: Use node RPC instead of tzstats API
     var api = "https://api.tzstats.com/tables/op?address=${await currentReceivingAddress}";
     var jsonResponse = jsonDecode(await get(Uri.parse(api)).then((value) => value.body));
+
     List<Tuple2<Transaction, Address>> txs = [];
+
     for (var tx in jsonResponse as List) {
+
       if (tx[1] == "transaction") {
-        var txApi = "https://api.tzstats.com/explorer/op/${tx[2]}";
+        var txApi = "https://api.tzstats.com/explorer/op/${tx[0]}"; //Get transactions by Unique Id, this way we will only get txs
         var txJsonResponse = jsonDecode(await get(Uri.parse(txApi)).then((value) => value.body));
         // Check if list is larger than 1 (if it is, it's a batch transaction)
         if (!((txJsonResponse as List).length > 1)) {
@@ -394,7 +413,7 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
                 amount: (float.parse(opJson["volume"].toString()) * 1000000).toInt(),
                 amountString: Amount(
                     rawValue: BigInt.parse((float.parse(opJson["volume"].toString()) * 1000000).toInt().toString()),
-                    fractionDigits: 6
+                    fractionDigits: coin.decimals
                 ).toJsonString(),
                 fee: (float.parse(opJson["fee"].toString()) * 1000000).toInt(),
                 height: int.parse(opJson["height"].toString()),
@@ -427,13 +446,18 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   }
 
   Future<void> updateChainHeight() async {
-    var api =
-        "${getCurrentNode().host}:${getCurrentNode().port}/chains/main/blocks/head/header/shell";
-    var jsonParsedResponse =
-        jsonDecode(await get(Uri.parse(api)).then((value) => value.body));
-    final int intHeight = int.parse(jsonParsedResponse["level"].toString());
-    Logging.instance.log("Chain height: $intHeight", level: LogLevel.Info);
-    await updateCachedChainHeight(intHeight);
+    try {
+      var api =
+          "${getCurrentNode().host}/chains/main/blocks/head/header/shell";
+      var jsonParsedResponse =
+      jsonDecode(await get(Uri.parse(api)).then((value) => value.body));
+      final int intHeight = int.parse(jsonParsedResponse["level"].toString());
+      Logging.instance.log("Chain height: $intHeight", level: LogLevel.Info);
+      await updateCachedChainHeight(intHeight);
+    } catch (e, s) {
+      Logging.instance.log("GET CHAIN HEIGHT ERROR ${e.toString()}", level: LogLevel.Error);
+    }
+
   }
 
   @override

From 373637701c980eb165b671d9746de64eac599fc1 Mon Sep 17 00:00:00 2001
From: ryleedavis <rylee@cypherstack.com>
Date: Mon, 14 Aug 2023 16:53:44 -0600
Subject: [PATCH 17/39] Fix tezos network status

---
 lib/services/coins/tezos/tezos_wallet.dart | 123 +++++++++++++++------
 1 file changed, 91 insertions(+), 32 deletions(-)

diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart
index 3ecc94eb8..e60d353dc 100644
--- a/lib/services/coins/tezos/tezos_wallet.dart
+++ b/lib/services/coins/tezos/tezos_wallet.dart
@@ -12,11 +12,14 @@ import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart';
 import 'package:stackwallet/models/node_model.dart';
 import 'package:stackwallet/models/paymint/fee_object_model.dart';
 import 'package:stackwallet/services/coins/coin_service.dart';
+import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
+import 'package:stackwallet/services/event_bus/global_event_bus.dart';
 import 'package:stackwallet/services/mixins/wallet_cache.dart';
 import 'package:stackwallet/services/mixins/wallet_db.dart';
 import 'package:stackwallet/services/node_service.dart';
 import 'package:stackwallet/services/transaction_notification_tracker.dart';
 import 'package:stackwallet/utilities/amount/amount.dart';
+import 'package:stackwallet/utilities/constants.dart';
 import 'package:stackwallet/utilities/default_nodes.dart';
 import 'package:stackwallet/utilities/enums/coin_enum.dart';
 import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
@@ -90,6 +93,7 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
   Timer? timer;
   bool _shouldAutoSync = false;
+  Timer? _networkAliveTimer;
 
   @override
   bool get shouldAutoSync => _shouldAutoSync;
@@ -101,12 +105,55 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
       if (!shouldAutoSync) {
         timer?.cancel();
         timer = null;
+        stopNetworkAlivePinging();
       } else {
+        startNetworkAlivePinging();
         refresh();
       }
     }
   }
 
+  void startNetworkAlivePinging() {
+    // call once on start right away
+    _periodicPingCheck();
+
+    // then periodically check
+    _networkAliveTimer = Timer.periodic(
+      Constants.networkAliveTimerDuration,
+      (_) async {
+        _periodicPingCheck();
+      },
+    );
+  }
+
+  void stopNetworkAlivePinging() {
+    _networkAliveTimer?.cancel();
+    _networkAliveTimer = null;
+  }
+
+  void _periodicPingCheck() async {
+    bool hasNetwork = await testNetworkConnection();
+
+    if (_isConnected != hasNetwork) {
+      NodeConnectionStatus status = hasNetwork
+          ? NodeConnectionStatus.connected
+          : NodeConnectionStatus.disconnected;
+
+      GlobalEventBus.instance.fire(
+        NodeConnectionStatusChangedEvent(
+          status,
+          walletId,
+          coin,
+        ),
+      );
+
+      _isConnected = hasNetwork;
+      if (hasNetwork) {
+        unawaited(refresh());
+      }
+    }
+  }
+
   @override
   Balance get balance => _balance ??= getCachedBalance();
   Balance? _balance;
@@ -138,15 +185,14 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   @override
   Future<String> confirmSend({required Map<String, dynamic> txData}) async {
     try {
-
       final amount = txData["recipientAmt"] as Amount;
-      final amountInMicroTez =
-          amount.decimal * Decimal.fromInt(1000000);
+      final amountInMicroTez = amount.decimal * Decimal.fromInt(1000000);
       final microtezToInt = int.parse(amountInMicroTez.toString());
 
       final int feeInMicroTez = int.parse(txData["fee"].toString());
       final String destinationAddress = txData["address"] as String;
-      final secretKey = Keystore.fromMnemonic((await mnemonicString)!).secretKey;
+      final secretKey =
+          Keystore.fromMnemonic((await mnemonicString)!).secretKey;
       Logging.instance.log(secretKey, level: LogLevel.Info);
       final sourceKeyStore = Keystore.fromSecretKey(secretKey);
       final client = TezartClient(getCurrentNode().host);
@@ -156,8 +202,7 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
           destination: destinationAddress,
           amount: microtezToInt,
           customFee: feeInMicroTez,
-          customGasLimit: 400
-      );
+          customGasLimit: 400);
       await operation.executeAndMonitor(); // This line gives an error
       return Future.value("");
     } catch (e) {
@@ -198,7 +243,8 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
         estimatedFee = feeRate;
     }
     Logging.instance.log("estimatedFee:$estimatedFee", level: LogLevel.Info);
-    return Amount(rawValue: BigInt.from(estimatedFee), fractionDigits: coin.decimals);
+    return Amount(
+        rawValue: BigInt.from(estimatedFee), fractionDigits: coin.decimals);
   }
 
   @override
@@ -356,48 +402,55 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   }
 
   Future<void> updateBalance() async {
-
     try {
       var api =
           "${getCurrentNode().host}/chains/main/blocks/head/context/contracts/${await currentReceivingAddress}/balance";
       var theBalance = (await get(Uri.parse(api)).then((value) => value.body))
-          .substring(1,
-          (await get(Uri.parse(api)).then((value) => value.body)).length - 2);
+          .substring(
+              1,
+              (await get(Uri.parse(api)).then((value) => value.body)).length -
+                  2);
       Logging.instance.log(
           "Balance for ${await currentReceivingAddress}: $theBalance",
           level: LogLevel.Info);
       var balanceInAmount = Amount(
-          rawValue: BigInt.parse(theBalance.toString()), fractionDigits: coin.decimals);
+          rawValue: BigInt.parse(theBalance.toString()),
+          fractionDigits: coin.decimals);
       _balance = Balance(
         total: balanceInAmount,
         spendable: balanceInAmount,
-        blockedTotal: Amount(rawValue: BigInt.parse("0"), fractionDigits: coin.decimals),
-        pendingSpendable: Amount(rawValue: BigInt.parse("0"), fractionDigits: coin.decimals),
+        blockedTotal:
+            Amount(rawValue: BigInt.parse("0"), fractionDigits: coin.decimals),
+        pendingSpendable:
+            Amount(rawValue: BigInt.parse("0"), fractionDigits: coin.decimals),
       );
       await updateCachedBalance(_balance!);
     } catch (e, s) {
-      Logging.instance.log("ERROR GETTING BALANCE ${e.toString()}", level: LogLevel.Error);
+      Logging.instance
+          .log("ERROR GETTING BALANCE ${e.toString()}", level: LogLevel.Error);
     }
-
   }
 
   Future<void> updateTransactions() async {
-
     // TODO: Use node RPC instead of tzstats API
-    var api = "https://api.tzstats.com/tables/op?address=${await currentReceivingAddress}";
-    var jsonResponse = jsonDecode(await get(Uri.parse(api)).then((value) => value.body));
+    var api =
+        "https://api.tzstats.com/tables/op?address=${await currentReceivingAddress}";
+    var jsonResponse =
+        jsonDecode(await get(Uri.parse(api)).then((value) => value.body));
 
     List<Tuple2<Transaction, Address>> txs = [];
 
     for (var tx in jsonResponse as List) {
-
       if (tx[1] == "transaction") {
-        var txApi = "https://api.tzstats.com/explorer/op/${tx[0]}"; //Get transactions by Unique Id, this way we will only get txs
-        var txJsonResponse = jsonDecode(await get(Uri.parse(txApi)).then((value) => value.body));
+        var txApi =
+            "https://api.tzstats.com/explorer/op/${tx[0]}"; //Get transactions by Unique Id, this way we will only get txs
+        var txJsonResponse =
+            jsonDecode(await get(Uri.parse(txApi)).then((value) => value.body));
         // Check if list is larger than 1 (if it is, it's a batch transaction)
         if (!((txJsonResponse as List).length > 1)) {
           for (var (opJson as Map) in txJsonResponse) {
-            if (opJson.containsKey("volume")) { // This is to check if transaction is a token transfer
+            if (opJson.containsKey("volume")) {
+              // This is to check if transaction is a token transfer
               TransactionType txType;
               if (opJson["sender"] == (await currentReceivingAddress)) {
                 txType = TransactionType.outgoing;
@@ -407,14 +460,21 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
               var theTx = Transaction(
                 walletId: walletId,
                 txid: opJson["hash"].toString(),
-                timestamp: DateTime.parse(opJson["time"].toString()).toUtc().millisecondsSinceEpoch ~/ 1000,
+                timestamp: DateTime.parse(opJson["time"].toString())
+                        .toUtc()
+                        .millisecondsSinceEpoch ~/
+                    1000,
                 type: txType,
                 subType: TransactionSubType.none,
-                amount: (float.parse(opJson["volume"].toString()) * 1000000).toInt(),
+                amount: (float.parse(opJson["volume"].toString()) * 1000000)
+                    .toInt(),
                 amountString: Amount(
-                    rawValue: BigInt.parse((float.parse(opJson["volume"].toString()) * 1000000).toInt().toString()),
-                    fractionDigits: coin.decimals
-                ).toJsonString(),
+                        rawValue: BigInt.parse(
+                            (float.parse(opJson["volume"].toString()) * 1000000)
+                                .toInt()
+                                .toString()),
+                        fractionDigits: coin.decimals)
+                    .toJsonString(),
                 fee: (float.parse(opJson["fee"].toString()) * 1000000).toInt(),
                 height: int.parse(opJson["height"].toString()),
                 isCancelled: false,
@@ -447,17 +507,16 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
   Future<void> updateChainHeight() async {
     try {
-      var api =
-          "${getCurrentNode().host}/chains/main/blocks/head/header/shell";
+      var api = "${getCurrentNode().host}/chains/main/blocks/head/header/shell";
       var jsonParsedResponse =
-      jsonDecode(await get(Uri.parse(api)).then((value) => value.body));
+          jsonDecode(await get(Uri.parse(api)).then((value) => value.body));
       final int intHeight = int.parse(jsonParsedResponse["level"].toString());
       Logging.instance.log("Chain height: $intHeight", level: LogLevel.Info);
       await updateCachedChainHeight(intHeight);
     } catch (e, s) {
-      Logging.instance.log("GET CHAIN HEIGHT ERROR ${e.toString()}", level: LogLevel.Error);
+      Logging.instance
+          .log("GET CHAIN HEIGHT ERROR ${e.toString()}", level: LogLevel.Error);
     }
-
   }
 
   @override

From 520ceabf7993e41ef50023c3fb58c4c7f4450284 Mon Sep 17 00:00:00 2001
From: likho <likhojiba@gmail.com>
Date: Tue, 15 Aug 2023 15:28:53 +0200
Subject: [PATCH 18/39] Clean up and refactor

---
 lib/services/coins/tezos/tezos_wallet.dart | 31 +++++++++++-----------
 1 file changed, 15 insertions(+), 16 deletions(-)

diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart
index e60d353dc..f33b619d0 100644
--- a/lib/services/coins/tezos/tezos_wallet.dart
+++ b/lib/services/coins/tezos/tezos_wallet.dart
@@ -185,14 +185,16 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   @override
   Future<String> confirmSend({required Map<String, dynamic> txData}) async {
     try {
+
       final amount = txData["recipientAmt"] as Amount;
-      final amountInMicroTez = amount.decimal * Decimal.fromInt(1000000);
+      final amountInMicroTez =
+          amount.decimal * Decimal.fromInt(1000000);
       final microtezToInt = int.parse(amountInMicroTez.toString());
 
       final int feeInMicroTez = int.parse(txData["fee"].toString());
       final String destinationAddress = txData["address"] as String;
-      final secretKey =
-          Keystore.fromMnemonic((await mnemonicString)!).secretKey;
+      final secretKey = Keystore.fromMnemonic((await mnemonicString)!)
+          .secretKey;
       Logging.instance.log(secretKey, level: LogLevel.Info);
       final sourceKeyStore = Keystore.fromSecretKey(secretKey);
       final client = TezartClient(getCurrentNode().host);
@@ -202,7 +204,9 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
           destination: destinationAddress,
           amount: microtezToInt,
           customFee: feeInMicroTez,
-          customGasLimit: 400);
+          customGasLimit: feeInMicroTez
+      );
+
       await operation.executeAndMonitor(); // This line gives an error
       return Future.value("");
     } catch (e) {
@@ -403,18 +407,12 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
   Future<void> updateBalance() async {
     try {
-      var api =
-          "${getCurrentNode().host}/chains/main/blocks/head/context/contracts/${await currentReceivingAddress}/balance";
-      var theBalance = (await get(Uri.parse(api)).then((value) => value.body))
-          .substring(
-              1,
-              (await get(Uri.parse(api)).then((value) => value.body)).length -
-                  2);
-      Logging.instance.log(
-          "Balance for ${await currentReceivingAddress}: $theBalance",
-          level: LogLevel.Info);
-      var balanceInAmount = Amount(
-          rawValue: BigInt.parse(theBalance.toString()),
+      final client = TezartClient(getCurrentNode().host);
+      final thisBalance = await client.getBalance(
+          address: await currentReceivingAddress
+      );
+      Amount balanceInAmount = Amount(
+          rawValue: BigInt.parse(thisBalance.toString()),
           fractionDigits: coin.decimals);
       _balance = Balance(
         total: balanceInAmount,
@@ -507,6 +505,7 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
   Future<void> updateChainHeight() async {
     try {
+      final client = TezartClient(getCurrentNode().host);
       var api = "${getCurrentNode().host}/chains/main/blocks/head/header/shell";
       var jsonParsedResponse =
           jsonDecode(await get(Uri.parse(api)).then((value) => value.body));

From 6047c433afd59d5da917a6f5466872bb16dd6bf0 Mon Sep 17 00:00:00 2001
From: ryleedavis <rylee@cypherstack.com>
Date: Tue, 15 Aug 2023 08:18:39 -0600
Subject: [PATCH 19/39] add tezos coin images

---
 assets/default_themes/dark.zip  | Bin 659201 -> 660115 bytes
 assets/default_themes/light.zip | Bin 607092 -> 608006 bytes
 2 files changed, 0 insertions(+), 0 deletions(-)

diff --git a/assets/default_themes/dark.zip b/assets/default_themes/dark.zip
index fe11a5463f8ae50dad10e51a2f664cbdcc55a25c..4ec1a415b80e284ff31ae47e778ea38513befae8 100644
GIT binary patch
delta 6136
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
N9t7f_MR<=w{157-N-F>W

delta 5217
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

diff --git a/assets/default_themes/light.zip b/assets/default_themes/light.zip
index 1453d6ba0606fba827105cb4a76af4df5b6b78dc..f9910e94b9ae11dd260a8b7e5707fe37702e1b63 100644
GIT binary patch
delta 6186
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
SvofFz6mS8678ZU71OEd^yF+XM

delta 5463
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


From 0a77dad7ec84295eed1b6b31ca3424f88e26c8f3 Mon Sep 17 00:00:00 2001
From: likho <likhojiba@gmail.com>
Date: Tue, 15 Aug 2023 16:49:28 +0200
Subject: [PATCH 20/39] Refactor Update transactions call

---
 lib/services/coins/tezos/tezos_wallet.dart | 123 ++++++++++-----------
 1 file changed, 57 insertions(+), 66 deletions(-)

diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart
index f33b619d0..c628253d8 100644
--- a/lib/services/coins/tezos/tezos_wallet.dart
+++ b/lib/services/coins/tezos/tezos_wallet.dart
@@ -198,7 +198,7 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
       Logging.instance.log(secretKey, level: LogLevel.Info);
       final sourceKeyStore = Keystore.fromSecretKey(secretKey);
       final client = TezartClient(getCurrentNode().host);
-      //TODO - Update gas Limit
+
       final operation = await client.transferOperation(
           source: sourceKeyStore,
           destination: destinationAddress,
@@ -431,72 +431,64 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
   Future<void> updateTransactions() async {
     // TODO: Use node RPC instead of tzstats API
-    var api =
-        "https://api.tzstats.com/tables/op?address=${await currentReceivingAddress}";
-    var jsonResponse =
-        jsonDecode(await get(Uri.parse(api)).then((value) => value.body));
-
+    String transactionsCall = "https://api.mainnet.tzkt.io/v1/accounts/${await currentReceivingAddress}/operations";
+    var response = jsonDecode(await get(Uri.parse(transactionsCall)).then((value) => value.body));
     List<Tuple2<Transaction, Address>> txs = [];
-
-    for (var tx in jsonResponse as List) {
-      if (tx[1] == "transaction") {
-        var txApi =
-            "https://api.tzstats.com/explorer/op/${tx[0]}"; //Get transactions by Unique Id, this way we will only get txs
-        var txJsonResponse =
-            jsonDecode(await get(Uri.parse(txApi)).then((value) => value.body));
-        // Check if list is larger than 1 (if it is, it's a batch transaction)
-        if (!((txJsonResponse as List).length > 1)) {
-          for (var (opJson as Map) in txJsonResponse) {
-            if (opJson.containsKey("volume")) {
-              // This is to check if transaction is a token transfer
-              TransactionType txType;
-              if (opJson["sender"] == (await currentReceivingAddress)) {
-                txType = TransactionType.outgoing;
-              } else {
-                txType = TransactionType.incoming;
-              }
-              var theTx = Transaction(
-                walletId: walletId,
-                txid: opJson["hash"].toString(),
-                timestamp: DateTime.parse(opJson["time"].toString())
-                        .toUtc()
-                        .millisecondsSinceEpoch ~/
-                    1000,
-                type: txType,
-                subType: TransactionSubType.none,
-                amount: (float.parse(opJson["volume"].toString()) * 1000000)
-                    .toInt(),
-                amountString: Amount(
-                        rawValue: BigInt.parse(
-                            (float.parse(opJson["volume"].toString()) * 1000000)
-                                .toInt()
-                                .toString()),
-                        fractionDigits: coin.decimals)
-                    .toJsonString(),
-                fee: (float.parse(opJson["fee"].toString()) * 1000000).toInt(),
-                height: int.parse(opJson["height"].toString()),
-                isCancelled: false,
-                isLelantus: false,
-                slateId: "",
-                otherData: "",
-                inputs: [],
-                outputs: [],
-                nonce: 0,
-                numberOfMessages: null,
-              );
-              var theAddress = Address(
-                walletId: walletId,
-                value: opJson["receiver"].toString(),
-                publicKey: [], // TODO: Add public key
-                derivationIndex: 0,
-                derivationPath: null,
-                type: AddressType.unknown,
-                subType: AddressSubType.unknown,
-              );
-              txs.add(Tuple2(theTx, theAddress));
-            }
-          }
+    for (var tx in response as List) {
+      if (tx["type"] == "transaction") {
+        TransactionType txType;
+        if (tx["sender"]["address"] == (await currentReceivingAddress)) {
+          txType = TransactionType.outgoing;
+        } else {
+          txType = TransactionType.incoming;
         }
+
+        final amount = tx["amount"] as int;
+        final fee = tx["bakerFee"] as int;
+        final amountInMicroTez =
+            amount / 1000000;
+
+        final feeInMicroTez =
+            fee / 1000000;
+
+        var theTx = Transaction(
+          walletId: walletId,
+          txid: tx["hash"].toString(),
+          timestamp: DateTime.parse(tx["timestamp"].toString())
+              .toUtc()
+              .millisecondsSinceEpoch ~/
+              1000,
+          type: txType,
+          subType: TransactionSubType.none,
+          amount: tx["amount"] as int,
+          amountString: Amount(
+              rawValue: BigInt.parse(
+                  (tx["amount"] as int)
+                      .toInt()
+                      .toString()),
+              fractionDigits: coin.decimals)
+              .toJsonString(),
+          fee: tx["bakerFee"] as int,
+          height: int.parse(tx["level"].toString()),
+          isCancelled: false,
+          isLelantus: false,
+          slateId: "",
+          otherData: "",
+          inputs: [],
+          outputs: [],
+          nonce: 0,
+          numberOfMessages: null,
+        );
+        var theAddress = Address(
+          walletId: walletId,
+          value: tx["target"]["address"].toString(),
+          publicKey: [], // TODO: Add public key
+          derivationIndex: 0,
+          derivationPath: null,
+          type: AddressType.unknown,
+          subType: AddressSubType.unknown,
+        );
+        txs.add(Tuple2(theTx, theAddress));
       }
     }
     Logging.instance.log("Transactions: $txs", level: LogLevel.Info);
@@ -505,7 +497,6 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
   Future<void> updateChainHeight() async {
     try {
-      final client = TezartClient(getCurrentNode().host);
       var api = "${getCurrentNode().host}/chains/main/blocks/head/header/shell";
       var jsonParsedResponse =
           jsonDecode(await get(Uri.parse(api)).then((value) => value.body));

From e3fb83a61fdc8af4a49479fcd54e17881259c670 Mon Sep 17 00:00:00 2001
From: likho <likhojiba@gmail.com>
Date: Tue, 15 Aug 2023 18:01:51 +0200
Subject: [PATCH 21/39] Send all

---
 lib/services/coins/tezos/tezos_wallet.dart | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)

diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart
index c628253d8..857f62f12 100644
--- a/lib/services/coins/tezos/tezos_wallet.dart
+++ b/lib/services/coins/tezos/tezos_wallet.dart
@@ -195,14 +195,20 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
       final String destinationAddress = txData["address"] as String;
       final secretKey = Keystore.fromMnemonic((await mnemonicString)!)
           .secretKey;
+
       Logging.instance.log(secretKey, level: LogLevel.Info);
       final sourceKeyStore = Keystore.fromSecretKey(secretKey);
       final client = TezartClient(getCurrentNode().host);
 
+      int? sendAmount = microtezToInt;
+      if (balance.spendable == txData["recipientAmt"] as Amount) {
+         sendAmount = microtezToInt - feeInMicroTez;
+      }
+
       final operation = await client.transferOperation(
           source: sourceKeyStore,
           destination: destinationAddress,
-          amount: microtezToInt,
+          amount: sendAmount,
           customFee: feeInMicroTez,
           customGasLimit: feeInMicroTez
       );
@@ -430,7 +436,6 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   }
 
   Future<void> updateTransactions() async {
-    // TODO: Use node RPC instead of tzstats API
     String transactionsCall = "https://api.mainnet.tzkt.io/v1/accounts/${await currentReceivingAddress}/operations";
     var response = jsonDecode(await get(Uri.parse(transactionsCall)).then((value) => value.body));
     List<Tuple2<Transaction, Address>> txs = [];
@@ -443,14 +448,6 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
           txType = TransactionType.incoming;
         }
 
-        final amount = tx["amount"] as int;
-        final fee = tx["bakerFee"] as int;
-        final amountInMicroTez =
-            amount / 1000000;
-
-        final feeInMicroTez =
-            fee / 1000000;
-
         var theTx = Transaction(
           walletId: walletId,
           txid: tx["hash"].toString(),

From e8d5c3ad8b865fbe7e21dcd4c58951b98e2e715b Mon Sep 17 00:00:00 2001
From: likho <likhojiba@gmail.com>
Date: Wed, 16 Aug 2023 14:46:21 +0200
Subject: [PATCH 22/39] Return tx id when sending, implement updateSentTx

---
 lib/services/coins/tezos/tezos_wallet.dart | 64 +++++++++++++++++-----
 1 file changed, 50 insertions(+), 14 deletions(-)

diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart
index 857f62f12..56e08ba8b 100644
--- a/lib/services/coins/tezos/tezos_wallet.dart
+++ b/lib/services/coins/tezos/tezos_wallet.dart
@@ -30,6 +30,7 @@ import 'package:tezart/tezart.dart';
 import 'package:tuple/tuple.dart';
 
 const int MINIMUM_CONFIRMATIONS = 1;
+const int _gasLimit = 10200;
 
 class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   TezosWallet({
@@ -201,8 +202,15 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
       final client = TezartClient(getCurrentNode().host);
 
       int? sendAmount = microtezToInt;
+      int gasLimit = _gasLimit;
+      int thisFee = feeInMicroTez;
+
       if (balance.spendable == txData["recipientAmt"] as Amount) {
-         sendAmount = microtezToInt - feeInMicroTez;
+        //Fee guides for emptying a tz account
+        // https://github.com/TezTech/eztz/blob/master/PROTO_004_FEES.md
+         thisFee = thisFee + 32;
+         sendAmount = microtezToInt - thisFee;
+         gasLimit = _gasLimit + 320;
       }
 
       final operation = await client.transferOperation(
@@ -210,11 +218,10 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
           destination: destinationAddress,
           amount: sendAmount,
           customFee: feeInMicroTez,
-          customGasLimit: feeInMicroTez
+          customGasLimit: gasLimit
       );
-
-      await operation.executeAndMonitor(); // This line gives an error
-      return Future.value("");
+      await operation.executeAndMonitor();
+      return operation.result.id as String;
     } catch (e) {
       Logging.instance.log(e.toString(), level: LogLevel.Error);
       return Future.error(e);
@@ -413,12 +420,11 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
   Future<void> updateBalance() async {
     try {
-      final client = TezartClient(getCurrentNode().host);
-      final thisBalance = await client.getBalance(
-          address: await currentReceivingAddress
-      );
+      String balanceCall = "https://api.mainnet.tzkt.io/v1/accounts/"
+          "${await currentReceivingAddress}/balance";
+      var response = jsonDecode(await get(Uri.parse(balanceCall)).then((value) => value.body));
       Amount balanceInAmount = Amount(
-          rawValue: BigInt.parse(thisBalance.toString()),
+          rawValue: BigInt.parse(response.toString()),
           fractionDigits: coin.decimals);
       _balance = Balance(
         total: balanceInAmount,
@@ -436,7 +442,8 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   }
 
   Future<void> updateTransactions() async {
-    String transactionsCall = "https://api.mainnet.tzkt.io/v1/accounts/${await currentReceivingAddress}/operations";
+    String transactionsCall = "https://api.mainnet.tzkt.io/v1/accounts/"
+        "${await currentReceivingAddress}/operations";
     var response = jsonDecode(await get(Uri.parse(transactionsCall)).then((value) => value.body));
     List<Tuple2<Transaction, Address>> txs = [];
     for (var tx in response as List) {
@@ -544,9 +551,38 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   }
 
   @override
-  Future<void> updateSentCachedTxData(Map<String, dynamic> txData) {
-    // TODO: implement updateSentCachedTxData
-    throw UnimplementedError();
+  Future<void> updateSentCachedTxData(Map<String, dynamic> txData) async {
+    final transaction = Transaction(
+      walletId: walletId,
+      txid: txData["txid"] as String,
+      timestamp: DateTime.now().millisecondsSinceEpoch ~/ 1000,
+      type: TransactionType.outgoing,
+      subType: TransactionSubType.none,
+      // precision may be lost here hence the following amountString
+      amount: (txData["recipientAmt"] as Amount).raw.toInt(),
+      amountString: (txData["recipientAmt"] as Amount).toJsonString(),
+      fee: txData["fee"] as int,
+      height: null,
+      isCancelled: false,
+      isLelantus: false,
+      otherData: null,
+      slateId: null,
+      nonce: null,
+      inputs: [],
+      outputs: [],
+      numberOfMessages: null,
+    );
+
+    final address = txData["address"] is String
+          ? await db.getAddress(walletId, txData["address"] as String)
+          : null;
+
+    await db.addNewTransactionData(
+        [
+        Tuple2(transaction, address),
+        ],
+        walletId,
+    );
   }
 
   @override

From 444860da53ad13a87137e79c8985eefa120d0343 Mon Sep 17 00:00:00 2001
From: likho <likhojiba@gmail.com>
Date: Wed, 16 Aug 2023 15:17:58 +0200
Subject: [PATCH 23/39] Return just one value for fees since endpoint returns
 only one value for fees

---
 lib/services/coins/tezos/tezos_wallet.dart | 35 +++++++---------------
 1 file changed, 11 insertions(+), 24 deletions(-)

diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart
index 56e08ba8b..1fb192190 100644
--- a/lib/services/coins/tezos/tezos_wallet.dart
+++ b/lib/services/coins/tezos/tezos_wallet.dart
@@ -239,29 +239,17 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
   @override
   Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
-    // TODO: Check if this is correct
-    var api = "https://api.tzstats.com/series/op?start_date=today&collapse=10d";
+
+    var api = "https://api.tzstats.com/series/op?start_date=today&collapse=1d";
     var response = jsonDecode((await get(Uri.parse(api))).body)[0];
     double totalFees = response[4] as double;
     int totalTxs = response[8] as int;
     int feePerTx = (totalFees / totalTxs * 1000000).floor();
-    int estimatedFee = 0;
-    Logging.instance.log("feePerTx:$feePerTx", level: LogLevel.Info);
-    Logging.instance.log("feeRate:$feeRate", level: LogLevel.Info);
-    switch (feeRate) {
-      case 0:
-        estimatedFee = feePerTx * 2;
-      case 1:
-        estimatedFee = feePerTx;
-      case 2:
-      case 3:
-        estimatedFee = (feePerTx / 2).floor();
-      default:
-        estimatedFee = feeRate;
-    }
-    Logging.instance.log("estimatedFee:$estimatedFee", level: LogLevel.Info);
+
     return Amount(
-        rawValue: BigInt.from(estimatedFee), fractionDigits: coin.decimals);
+      rawValue: BigInt.from(feePerTx),
+      fractionDigits: coin.decimals,
+    );
   }
 
   @override
@@ -272,21 +260,20 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
   @override
   Future<FeeObject> get fees async {
-    // TODO: Check if this is correct
     var api = "https://api.tzstats.com/series/op?start_date=today&collapse=10d";
     var response = jsonDecode((await get(Uri.parse(api))).body);
     double totalFees = response[0][4] as double;
     int totalTxs = response[0][8] as int;
     int feePerTx = (totalFees / totalTxs * 1000000).floor();
     Logging.instance.log("feePerTx:$feePerTx", level: LogLevel.Info);
-    // TODO: fix numberOfBlocks
+    // TODO: fix numberOfBlocks - Since there is only one fee no need to set blocks
     return FeeObject(
-      numberOfBlocksFast: 3,
+      numberOfBlocksFast: 10,
       numberOfBlocksAverage: 10,
-      numberOfBlocksSlow: 30,
-      fast: (feePerTx * 2),
+      numberOfBlocksSlow: 10,
+      fast: feePerTx,
       medium: feePerTx,
-      slow: (feePerTx / 2).floor(),
+      slow: feePerTx,
     );
   }
 

From 2732b2fe7170edee191ee156bfd712ea3ca94281 Mon Sep 17 00:00:00 2001
From: likho <likhojiba@gmail.com>
Date: Tue, 22 Aug 2023 18:33:24 +0200
Subject: [PATCH 24/39] WIP: XLM fixes and refactor

---
 .../add_edit_node_view.dart                   |  9 ++-
 .../coins/stellar/stellar_wallet.dart         | 66 +++++++------------
 .../test_stellar_node_connection.dart         | 22 +++++++
 3 files changed, 54 insertions(+), 43 deletions(-)
 create mode 100644 lib/utilities/test_stellar_node_connection.dart

diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
index 56b008093..af6256d23 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
@@ -27,6 +27,7 @@ import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
 import 'package:stackwallet/utilities/logger.dart';
 import 'package:stackwallet/utilities/test_epic_box_connection.dart';
 import 'package:stackwallet/utilities/test_monero_node_connection.dart';
+import 'package:stackwallet/utilities/test_stellar_node_connection.dart';
 import 'package:stackwallet/utilities/text_styles.dart';
 import 'package:stackwallet/utilities/util.dart';
 import 'package:stackwallet/widgets/background.dart';
@@ -194,10 +195,14 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
           // await client.getSyncStatus();
         } catch (_) {}
 
-      case Coin.nano:
-      case Coin.banano:
       case Coin.stellar:
       case Coin.stellarTestnet:
+        try {
+          testPassed = await testStellarNodeConnection(formData.host!);
+        } catch(_) {}
+      case Coin.nano:
+      case Coin.banano:
+
         throw UnimplementedError();
         //TODO: check network/node
     }
diff --git a/lib/services/coins/stellar/stellar_wallet.dart b/lib/services/coins/stellar/stellar_wallet.dart
index c4c92373f..6fecb6eb3 100644
--- a/lib/services/coins/stellar/stellar_wallet.dart
+++ b/lib/services/coins/stellar/stellar_wallet.dart
@@ -1,5 +1,7 @@
 import 'dart:async';
+import 'dart:convert';
 
+import 'package:decimal/decimal.dart';
 import 'package:http/http.dart' as http;
 import 'package:isar/isar.dart';
 import 'package:stackwallet/db/isar/main_db.dart';
@@ -37,6 +39,7 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
   late StellarSDK stellarSdk;
   late Network stellarNetwork;
 
+
   StellarWallet({
     required String walletId,
     required String walletName,
@@ -53,20 +56,28 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
     initCache(walletId, coin);
     initWalletDB(mockableOverride: mockableOverride);
 
-    if (coin.name == "stellarTestnet") {
+
+    if (coin.isTestNet) {
       stellarSdk = StellarSDK.TESTNET;
       stellarNetwork = Network.TESTNET;
     } else {
       stellarSdk = StellarSDK.PUBLIC;
       stellarNetwork = Network.PUBLIC;
     }
+
+    _updateNode();
+  }
+
+  void _updateNode() {
+    _xlmNode = NodeService(secureStorageInterface: _secureStore)
+        .getPrimaryNodeFor(coin: coin) ??
+        DefaultNodes.getNodeFor(coin);
+    stellarSdk = StellarSDK("${_xlmNode!.host}:${_xlmNode!.port}");
   }
 
   late final TransactionNotificationTracker txTracker;
   late SecureStorageInterface _secureStore;
 
-  // final StellarSDK stellarSdk = StellarSDK.PUBLIC;
-
   @override
   bool get isFavorite => _isFavorite ??= getCachedIsFavorite();
   bool? _isFavorite;
@@ -232,32 +243,14 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
       (await _currentReceivingAddress)?.value ?? await getAddressSW();
 
   Future<int> getBaseFee() async {
-    // final nodeURI = Uri.parse("${getCurrentNode().host}:${getCurrentNode().port}");
-    final nodeURI = Uri.parse(getCurrentNode().host);
-    final httpClient = http.Client();
-    FeeStatsResponse fsp =
-        await FeeStatsRequestBuilder(httpClient, nodeURI).execute();
-    return int.parse(fsp.lastLedgerBaseFee);
+    var fees = await stellarSdk.feeStats.execute();
+    return int.parse(fees.lastLedgerBaseFee);
   }
 
   @override
   Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
     var baseFee = await getBaseFee();
-    int fee = 100;
-    switch (feeRate) {
-      case 0:
-        fee = baseFee * 10;
-      case 1:
-      case 2:
-        fee = baseFee * 50;
-      case 3:
-        fee = baseFee * 100;
-      case 4:
-        fee = baseFee * 200;
-      default:
-        fee = baseFee * 50;
-    }
-    return Amount(rawValue: BigInt.from(fee), fractionDigits: coin.decimals);
+    return Amount(rawValue: BigInt.from(baseFee), fractionDigits: coin.decimals);
   }
 
   @override
@@ -285,20 +278,13 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
   @override
   Future<FeeObject> get fees async {
-    // final nodeURI = Uri.parse("${getCurrentNode().host}:${getCurrentNode().port}");
-    final nodeURI = Uri.parse(getCurrentNode().host);
-
-    final httpClient = http.Client();
-    FeeStatsResponse fsp =
-        await FeeStatsRequestBuilder(httpClient, nodeURI).execute();
-
     return FeeObject(
-        numberOfBlocksFast: 0,
-        numberOfBlocksAverage: 0,
-        numberOfBlocksSlow: 0,
-        fast: int.parse(fsp.lastLedgerBaseFee) * 100,
-        medium: int.parse(fsp.lastLedgerBaseFee) * 50,
-        slow: int.parse(fsp.lastLedgerBaseFee) * 10);
+        numberOfBlocksFast: 10,
+        numberOfBlocksAverage: 10,
+        numberOfBlocksSlow: 10,
+        fast: 1,
+        medium: 1,
+        slow: 1);
   }
 
   @override
@@ -399,6 +385,7 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
       {required String address,
       required Amount amount,
       Map<String, dynamic>? args}) async {
+
     try {
       final feeRate = args?["feeRate"];
       var fee = 1000;
@@ -750,10 +737,7 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
   @override
   Future<void> updateNode(bool shouldRefresh) async {
-    _xlmNode = NodeService(secureStorageInterface: _secureStore)
-            .getPrimaryNodeFor(coin: coin) ??
-        DefaultNodes.getNodeFor(coin);
-
+    _updateNode();
     if (shouldRefresh) {
       unawaited(refresh());
     }
diff --git a/lib/utilities/test_stellar_node_connection.dart b/lib/utilities/test_stellar_node_connection.dart
new file mode 100644
index 000000000..12e1e8dc9
--- /dev/null
+++ b/lib/utilities/test_stellar_node_connection.dart
@@ -0,0 +1,22 @@
+import 'dart:convert';
+
+import 'package:http/http.dart' as http;
+
+Future<bool> testStellarNodeConnection(String host) async {
+
+  final client = http.Client();
+  Uri uri = Uri.parse(host);
+  final response = await client.get(
+    uri,
+    headers: {'Content-Type': 'application/json'},
+  ).timeout(const Duration(milliseconds: 2000),
+      onTimeout: () async => http.Response('Error', 408));
+
+  final json = jsonDecode(response.body);
+
+  if (response.statusCode == 200 && json["horizon_version"] != null) {
+    return true;
+  } else {
+    return false;
+  }
+}
\ No newline at end of file

From 961b687e274c010e9373ad107b39c81de6dab3de Mon Sep 17 00:00:00 2001
From: likho <likhojiba@gmail.com>
Date: Wed, 23 Aug 2023 15:13:17 +0200
Subject: [PATCH 25/39] Test node connection when updating and node and show
 error codes on send fail instead of generic error

---
 .../coins/stellar/stellar_wallet.dart         | 25 ++++++++-----------
 .../test_stellar_node_connection.dart         | 18 ++++++++++---
 lib/widgets/node_card.dart                    | 12 +++++++--
 3 files changed, 35 insertions(+), 20 deletions(-)

diff --git a/lib/services/coins/stellar/stellar_wallet.dart b/lib/services/coins/stellar/stellar_wallet.dart
index 6fecb6eb3..c53e34f59 100644
--- a/lib/services/coins/stellar/stellar_wallet.dart
+++ b/lib/services/coins/stellar/stellar_wallet.dart
@@ -58,10 +58,8 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
 
     if (coin.isTestNet) {
-      stellarSdk = StellarSDK.TESTNET;
       stellarNetwork = Network.TESTNET;
     } else {
-      stellarSdk = StellarSDK.PUBLIC;
       stellarNetwork = Network.PUBLIC;
     }
 
@@ -217,10 +215,12 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
     transaction.sign(senderKeyPair, stellarNetwork);
     try {
       SubmitTransactionResponse response =
-          await stellarSdk.submitTransaction(transaction);
-
+          await stellarSdk.submitTransaction(transaction).onError((error, stackTrace) => throw (error.toString()));
       if (!response.success) {
-        throw ("Unable to send transaction");
+        throw (
+            "${response.extras?.resultCodes?.transactionResultCode}"
+                " ::: ${response.extras?.resultCodes?.operationsResultCodes}"
+        );
       }
       return response.hash!;
     } catch (e, s) {
@@ -278,13 +278,15 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
   @override
   Future<FeeObject> get fees async {
+
+    int fee = await getBaseFee();
     return FeeObject(
         numberOfBlocksFast: 10,
         numberOfBlocksAverage: 10,
         numberOfBlocksSlow: 10,
-        fast: 1,
-        medium: 1,
-        slow: 1);
+        fast: fee,
+        medium: fee,
+        slow: fee);
   }
 
   @override
@@ -482,13 +484,6 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
         if (response is PaymentOperationResponse) {
           PaymentOperationResponse por = response;
 
-          Logging.instance.log(
-              "ALL TRANSACTIONS IS ${por.transactionSuccessful}",
-              level: LogLevel.Info);
-
-          Logging.instance.log("THIS TX HASH IS ${por.transactionHash}",
-              level: LogLevel.Info);
-
           SWTransaction.TransactionType type;
           if (por.sourceAccount == await getAddressSW()) {
             type = SWTransaction.TransactionType.outgoing;
diff --git a/lib/utilities/test_stellar_node_connection.dart b/lib/utilities/test_stellar_node_connection.dart
index 12e1e8dc9..504a81efe 100644
--- a/lib/utilities/test_stellar_node_connection.dart
+++ b/lib/utilities/test_stellar_node_connection.dart
@@ -1,6 +1,7 @@
 import 'dart:convert';
 
 import 'package:http/http.dart' as http;
+import 'package:stellar_flutter_sdk/stellar_flutter_sdk.dart';
 
 Future<bool> testStellarNodeConnection(String host) async {
 
@@ -12,10 +13,21 @@ Future<bool> testStellarNodeConnection(String host) async {
   ).timeout(const Duration(milliseconds: 2000),
       onTimeout: () async => http.Response('Error', 408));
 
-  final json = jsonDecode(response.body);
+  if (response.statusCode == 200) {
+    //Get chain height for sdk
+    StellarSDK stellarSdk = StellarSDK(host);
+    final height = await stellarSdk.ledgers
+        .order(RequestBuilderOrder.DESC)
+        .limit(1)
+        .execute()
+        .then((value) => value.records!.first.sequence)
+        .onError((error, stackTrace) => throw ("Error getting chain height"));
 
-  if (response.statusCode == 200 && json["horizon_version"] != null) {
-    return true;
+    if (height > 0) {
+        return true;
+    } else {
+      return false;
+    }
   } else {
     return false;
   }
diff --git a/lib/widgets/node_card.dart b/lib/widgets/node_card.dart
index 57482119c..59e3663b5 100644
--- a/lib/widgets/node_card.dart
+++ b/lib/widgets/node_card.dart
@@ -29,6 +29,7 @@ import 'package:stackwallet/utilities/logger.dart';
 import 'package:stackwallet/utilities/test_epic_box_connection.dart';
 import 'package:stackwallet/utilities/test_eth_node_connection.dart';
 import 'package:stackwallet/utilities/test_monero_node_connection.dart';
+import 'package:stackwallet/utilities/test_stellar_node_connection.dart';
 import 'package:stackwallet/utilities/text_styles.dart';
 import 'package:stackwallet/utilities/util.dart';
 import 'package:stackwallet/widgets/conditional_parent.dart';
@@ -192,10 +193,17 @@ class _NodeCardState extends ConsumerState<NodeCard> {
         }
         break;
 
-      case Coin.nano:
-      case Coin.banano:
       case Coin.stellar:
       case Coin.stellarTestnet:
+        try {
+          testPassed = await testStellarNodeConnection(node.host);
+        } catch(_) {
+          testPassed = false;
+        }
+        break;
+
+      case Coin.nano:
+      case Coin.banano:
         throw UnimplementedError();
         //TODO: check network/node
     }

From 4729789f9aa9d27c2c6d773ec665a51d819a2940 Mon Sep 17 00:00:00 2001
From: likho <likhojiba@gmail.com>
Date: Wed, 23 Aug 2023 16:59:00 +0200
Subject: [PATCH 26/39] Add break statements to case, add test connection to
 node_card and include port when testing node connection

---
 .../manage_nodes_views/add_edit_node_view.dart       |  5 ++++-
 .../manage_nodes_views/node_details_view.dart        | 12 ++++++++++--
 lib/utilities/test_stellar_node_connection.dart      |  4 ++--
 lib/widgets/node_card.dart                           |  2 +-
 4 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
index af6256d23..692e34633 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
@@ -194,12 +194,15 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
         try {
           // await client.getSyncStatus();
         } catch (_) {}
+        break;
 
       case Coin.stellar:
       case Coin.stellarTestnet:
         try {
-          testPassed = await testStellarNodeConnection(formData.host!);
+          testPassed = await testStellarNodeConnection(formData.host!, formData.port!);
         } catch(_) {}
+        break;
+
       case Coin.nano:
       case Coin.banano:
 
diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
index 59ff1efad..3354ca396 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
@@ -26,6 +26,7 @@ import 'package:stackwallet/utilities/logger.dart';
 import 'package:stackwallet/utilities/test_epic_box_connection.dart';
 import 'package:stackwallet/utilities/test_eth_node_connection.dart';
 import 'package:stackwallet/utilities/test_monero_node_connection.dart';
+import 'package:stackwallet/utilities/test_stellar_node_connection.dart';
 import 'package:stackwallet/utilities/text_styles.dart';
 import 'package:stackwallet/utilities/util.dart';
 import 'package:stackwallet/widgets/background.dart';
@@ -170,10 +171,17 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> {
         }
         break;
 
-      case Coin.nano:
-      case Coin.banano:
       case Coin.stellar:
       case Coin.stellarTestnet:
+      try {
+        testPassed = await testStellarNodeConnection(node!.host, node.port);
+      } catch(_) {
+        testPassed = false;
+      }
+        break;
+      case Coin.nano:
+      case Coin.banano:
+
         throw UnimplementedError();
         //TODO: check network/node
     }
diff --git a/lib/utilities/test_stellar_node_connection.dart b/lib/utilities/test_stellar_node_connection.dart
index 504a81efe..683d946c9 100644
--- a/lib/utilities/test_stellar_node_connection.dart
+++ b/lib/utilities/test_stellar_node_connection.dart
@@ -3,10 +3,10 @@ import 'dart:convert';
 import 'package:http/http.dart' as http;
 import 'package:stellar_flutter_sdk/stellar_flutter_sdk.dart';
 
-Future<bool> testStellarNodeConnection(String host) async {
+Future<bool> testStellarNodeConnection(String host, int port) async {
 
   final client = http.Client();
-  Uri uri = Uri.parse(host);
+  Uri uri = Uri.parse("$host:$port");
   final response = await client.get(
     uri,
     headers: {'Content-Type': 'application/json'},
diff --git a/lib/widgets/node_card.dart b/lib/widgets/node_card.dart
index 59e3663b5..81fe62357 100644
--- a/lib/widgets/node_card.dart
+++ b/lib/widgets/node_card.dart
@@ -196,7 +196,7 @@ class _NodeCardState extends ConsumerState<NodeCard> {
       case Coin.stellar:
       case Coin.stellarTestnet:
         try {
-          testPassed = await testStellarNodeConnection(node.host);
+          testPassed = await testStellarNodeConnection(node.host, node.port);
         } catch(_) {
           testPassed = false;
         }

From 89aa4e2a327dec3a8b70e747545b076f216af725 Mon Sep 17 00:00:00 2001
From: ryleedavis <rylee@cypherstack.com>
Date: Wed, 23 Aug 2023 10:48:28 -0600
Subject: [PATCH 27/39] tezos images

---
 assets/default_themes/dark.zip  | Bin 660115 -> 676128 bytes
 assets/default_themes/light.zip | Bin 608006 -> 624020 bytes
 2 files changed, 0 insertions(+), 0 deletions(-)

diff --git a/assets/default_themes/dark.zip b/assets/default_themes/dark.zip
index 4ec1a415b80e284ff31ae47e778ea38513befae8..eb20d7e6e6279c6c6ca50a76aef686d968861b47 100644
GIT binary patch
delta 21204
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
Ai~s-t

delta 5065
zcmb7|c|26#|Hp^H+!<@K8;lBt?Ar`kn(S*NvPPtA#V4XLQT9a04WY7AsAwcxg_Pw(
z$(o&yJ)sDt-<@O_-@kq{k9%ic=lOoW&-<MBxik0N`wtH#WFL%^K-h%#IT?laC0qnJ
zZtIKhkUZclKb+xq)<J~rrpc3!($rhupV7nVXm=QM05Is~rL=Z3K>?7Y&*6UMv>liS
z<ZMA`Y`GHcTM!$<e}X3%6e(;qKZ`87mb@j1EIL$)56G%;it61Hvbvf|U3#6Y6a?Tp
zhGZ4$4qpl+E5bCq-Hfa(RB1dxvTFWBbGDkSu!*#%FO$`Mdb*(P-i031-H0c%5;cTN
zOhOcJbgKn~TG*aV0Or{U(j34vn86?!K!*NRSfA53=zu<<$>jmv%K!#YOAb)kawJB|
z0siC}B_b7p0bVluVhV6<GkSACeOsAY01i}S%L+^2)wT+;0&=&Nlnv0o?Z;*h(80-m
zf{uWk30c`Z1<bcuc^Tlg?I&6eSW$zYWB?7aIiD=RM+M%f0Py6d)(SwImaNdVz&aIz
zGzZW@<bMr(+m6Rw4@7L|nAZR(Z1+6=4zOn+N73&D)>+8PZ~{o*j<PrfG@T~1Iz6O4
z4OxjABbB$6yBRWZy9a~?Qh7Uy?kS|%w#u|dx@~91Zi_sy&D8CYE89%f0ePHi#|6Lx
zmN+8Gi<vm*hzw{Vuxc<{{8<ywDP9H!L%}exOXr+DoF!cUx!`Gjf)R!ogJx*!@bROE
zQPE7oVX!}^IV<bfOdM-ahQ0Lk#2hz39IF&kPxrOZ?%kiJJ;oxUfroK_m{QeV8thUy
z{eDOvR~VS8F?~L7Ud*D$+_&dT4WTCB*V<y3u64(!rVIAh2_-8iTj@Z5U6$2_*EMX~
z%Ry}O2-AC#(B*w{BfZPnu$x#j#Y>PBU1;#rR1CP{HL$WCh<@3A%j`wDIF4bwJ%~5w
z%K?E&tg9sT)996#-)XSySsc?VGlr#UPH)%5^9Se6M0yRp(eV0Pdsi1w03mf>_@Yuo
zCRg{Zm-NCveEG)v&ZTClua*@_$$2D%U2Ca8r#$z%Eb;B9-JswR!%icHI>vprx4}%m
zIjvU`!M%l6BFdP9{qym4v{8LbpwPZdB?dm1nv6QWjY3b&*f~6idNJ$5{GfM9z{Pa1
zU^K$Y!y<B`MtqFhHDy*xUWhR2%9AOy#uZvLQ}p>X+e4MN=HS9m6Vo_jtdyEvxFds8
zck*c)!}9JPoZe@|_nPYHFOl(5I*IBbq0t>*<V*?+kp-=<s{<<-yIg%#a<%ThP2baL
z*XC8)*z?iIyGq(%%CGYBy_EKIW*<d#E_1#~pY6`PW^+z4^1i-V?-J`IA?N|Om{#+d
z*aK=0h$(jk@5ZGV<Y)!4>3E0q6$x7&Swy!FFxj@>;aaQI?a2(Is!<fYDkn9$?)xl;
z_=Lx=;KJ)*p9(KUF~%aly=!@?$4gI+_Kw)n<TUZ$7AF=J7Tz2;=!_eQY7EDH5G=`F
z((}1tlA-0|-j>W4&B6EnP&%Q?XGlvg%%pm3wz5i~Kq)*0E&YUdU^FSpmcUL&_gVy<
zE-P+#f;bcW8v8xMc=Dw0!<e!fdK;K~+i}LkUyt*pyB;0AfEG_NoGK}H;aI{XGhY2|
zOl$Kkguj4y8IdTdG^}tl)4$fc75--6U**`Fifxumnh~dFZrI9|(D%p^ct;1={3pjY
zxEi{dXwEd(x|#&Japw`sh`bh`4I&RH=V4-6b;bQ<+~-T9DxAXqIcecq1@pp1UU_S%
zkWjVPsXgtLM6ZWSc_jv$aX<9AVZ3;0OkV!+7YR;xu{P(2KR9Xnh<kTDDHysp&Z*+u
z-8@WN&U{_FT{Co%srk!dDd9;SNP9R<z`XTUhTFr&@Nz=l1tlxr?pqmscuu*sh(@Qt
zz`Q}t8sj%|^bS<BxsCxIIBDm1(T6&)0_z^E+UG0Pz4cw@{#`T*Nx|!#_J4h6@|wOO
z!92iA<Be(iz&Qs+L(`c{0(I$hVix%Iw3_~Nahg7?&dsf{f#yqiTS0>Sywbqgan};l
zrQrrIG#{(Nyi(!$4B83hf&7aO(UZ$(_$K3K!+n_88)uKM+!yK#pAIQ3OpSE3!3t$L
zxM7A3tl`MKexB0unW*W{63U`Jrjp+~l)4SQHL5y9*k1;*HdOOO>jz|~#-2Y$eDz4>
z2zz-}s$BXvIojL}WMv!SI3`?v&(T1_UO&{qSR5>IlphvuLT7?aPQqnBd{bl*;^xDg
z*5-I@(z|ZGxK5<qKdLI^vrvZca_i(d?{v}6ANGvrpPsrOM0;F`_7#UVrepXwLxUO(
zKSR=gPSJZ<J9|S}dpj?b)U0YG=Uw@!6qSkCk9QPZj;?5n^UH{0Bt&AZMe5w!hs78l
zD%w2F*OV5};T5EBF?o15@>2052~Q-B<GUrp%Cq|pgAeeMC@TE^GsC93G<f9{;gK6h
zt~9L`tQ;>EP|USoak)6i99ZT%&fjuvB2u<XlG7LUvyv*g)-_gDDyMu&<-({Ki|NSw
zDuv*0UP=y@L|51498ZF0OlQ(hEud(T*{YG)|9SRQ#pee}wboaWEVj{8EIx2%ZSELO
zoz4+tI-lv`8T08#T2Gb2rrui|{@y;4oQg8u)qCUq?dZ*63;)j!6PtN(=*pA%CbMO}
z+fl7lJ^8|xs`w<AvOPo<w<OM=PjiB`yxyGh7I^=&)W<vF$o`Er!Yg!^JR6_?8bPs{
z<qhm{R}?mx+KBc6mHFko=C(ULXRJJ|t$fEz16saZGHS$eEQ+f)`i#`RPr>v~^lRe@
z9TT$kOfK))8}TL%Q$rt@t(ZD!HzN839>x7~l9lc4xEH_@{*vBj)m^80kM#I4me4Q0
zwBwggB$Znq)XTgiB1WKAj|(cQVagSJL>P)HI&2YyKC5=YY>4x%=Yp`;C5F@5I%06+
z>pV#@OZ!E$t29cYa(_7ScB%f#UB^}vwVMa_|5)}Ze>?NNxri$)OPGsKR>5oVuEKmO
zJS%)rOE~#=3->WK?dGQJ>XF&UwU>v{H7lz%ykDJvzBBaKIDA-^Q0pO7p5{K-I@mM+
ztMqqO)rZN|>Y4GuJd@@_Lk*_yRwrQBvU=om@(+gvpYRLK9}|MZ;_Iq%;%~S1T~kbR
zZGgq;46T_N^1$Nc>^en}S4D3OO;MX8e{*u;smo=}Wj1EV<EV=r?%X3V!*r;@V!hV+
zDw{o2+-WvzeYM;R1e1F;0^i!tj@|h$;%b(mZ3p)Yh69>6%H$tKtH?%&*l{)sRx}$J
z0zA4R&Rjf)ENl<*oVpyS#N&TQ^*~Hz18dTv)w01gD|r>Rg4kXMCaXdY{12-aN$Ss+
z<^(;u92h*s`q}<F`BZ4=ae&*TwY+6QZGpyZCI&%v{ZW1vHqi`1F?V_q@5bBS;i<LZ
zNS=`?+{l#G$j9$>X7cq3KJ_2V>Jz@#x7lSAZzDM$gx*Z#Gre6a5OL_#@2T;BQhvOV
z7Mfxf9#5?A3>H~>gUz$cap%rEmBQbs_RHI;NwuEUsag5c(=$!De$zAhxRymnJ#2lv
zqmk0MjH9mN_YV&G3WOGK2VME^tPXmm)oI3A+|235!rY^!n0k&?8Hua)#aXL&<Z9v@
z?#kJ#Pk$Yebkj>5)wg9*)G=UIV-0eSvN_*(^pi7tb*$9#hTdRy2wTGQA``9AN>vL@
zk)PZ&#YewR7x;0N3H*av7tVYU9A8GCuOuv|bnN1-aI?U$=>aTZ%;(1=^|Opc-K!O0
z3%CgLX0$nWu6UzbyZ*?75Iw=NtN(tz8pQoO<q9SyL&+L$(S4}>MA*?Q7owA@<jU$l
zy_Q}!L}jFMom!g_8}t{ycUM`Q$F3#yV+?IV{?AeL+`)@Uj)26EsBq<*R%3|umkSmW
zR*t+OJ^7N?74Fbv7qf{o5`tD&?M?I%z{i`m912M2HVm9pL}_f@xPj8DC@xS(35DC)
zf&ufDP^w!ulO!7q$b>~5+u6bedSOwTJH5EbTOhC>i#oD%4@3%q1|!r_{GdG!I%&2b
z_U;UZ0n2eH9_j{3&;bV-e#N2KD6yC_gmvGMF#>c|M(v@rc?j9SXI!bkg-3L}VDJBM
zRuzapM^lqH8njQPW~cNICvorle|fFS?i|)hyngNv=LJ37;k){GI|A{SZt%_i&rHL2
z#UCW`J2ij#5mg$BDZs%23z|*Wl20_dT<cY#;rp_K!>TAL%A}RlAku%6M9|<xHOidP
zV6Ga9AMPYUM+$s+rzaZZf~o=kTKfm_f_K#r6vIJ-8c?C&X-0_6oC0^1gp0h_^VC4`
z!p*)Rz~Q4PK9)cC^gDKbo0Zo-3dMT-*9LTz1Gp%2sU>l#l|M0L{s+;3I6O2;_PyW`
zWCvctqbQ~a4L-u7_^B1xH}N!{a$%rB{$mjK=iJ0L$98)slJF?kCcbY8P?QA?0-6xc
z=h?((t$<y92a&KPdJ|V_?k>O*39ATf;#E6<VqK%bb6ODA*|&*vw05U9K*Be?H!)g!
zcW^Up2oL&f;(KMgQ+r3kC;T=sLI=f4IkTTMAiQ#A6Vu89yXvo^17VwhO?*WMwQE{R
zNH{+jY|}yQs+f>2L>^!N8}~K9y0r`5{2{rg3ta}KVE{N^2khUO5e9_oL1o5AfC74`
z1C+#-L;|A01w9ly*z}IFMi}rD3HO5}OtH!_pr$@VCh|ZBeUuPo$j1<Y#}@)%%M`#*
ziI@!_CsPJ6!vI=t1$sz|p<}@7Bur!>VTz$+z#k++#ZDr8prsj-kut8cA%v5-z+l7O
zmvJ|Vbn%b~A1HAONwG{Ypn(yDv3w+q24k&v$1Nw}Tz(Q}2Ql_YTJVbzWxX)qL1W0K
z9YeO^rc5oFguC{UF%8&ijG{=N3tTfs?W0yZ0P>rlIClQ<qd^N3sN@j`z{@6-g+n`%
ro&b>ldj38E*m@#R8m#dZ`TuwxV4_b;NAkr&?;<W3?B7-B{|xqj!e)jN

diff --git a/assets/default_themes/light.zip b/assets/default_themes/light.zip
index f9910e94b9ae11dd260a8b7e5707fe37702e1b63..0048f661c07352a30f7fc39f5236a439c9ca58aa 100644
GIT binary patch
delta 20882
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

delta 4946
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


From 467f57c74e1f3902acf221d1903b24dc7be33c82 Mon Sep 17 00:00:00 2001
From: ryleedavis <rylee@cypherstack.com>
Date: Wed, 23 Aug 2023 10:59:13 -0600
Subject: [PATCH 28/39] resolve merge conflicts

---
 .../manage_nodes_views/add_edit_node_view.dart   |  9 +++++----
 .../manage_nodes_views/node_details_view.dart    | 16 ++++++++--------
 lib/utilities/enums/coin_enum.dart               |  3 ++-
 lib/widgets/node_card.dart                       |  5 +++--
 4 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
index c4c10a618..5ae04920d 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
@@ -196,10 +196,11 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
         } catch (_) {}
         break;
       case Coin.stellar:
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         try {
-          testPassed = await testStellarNodeConnection(formData.host!, formData.port!);
-        } catch(_) {}
+          testPassed =
+              await testStellarNodeConnection(formData.host!, formData.port!);
+        } catch (_) {}
         break;
 
       case Coin.nano:
@@ -749,7 +750,7 @@ class _NodeFormState extends ConsumerState<NodeForm> {
       case Coin.banano:
       case Coin.eCash:
       case Coin.stellar:
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
         return false;
 
       case Coin.ethereum:
diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
index 0b339469e..d306260d6 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
@@ -26,6 +26,7 @@ import 'package:stackwallet/utilities/logger.dart';
 import 'package:stackwallet/utilities/test_epic_box_connection.dart';
 import 'package:stackwallet/utilities/test_eth_node_connection.dart';
 import 'package:stackwallet/utilities/test_monero_node_connection.dart';
+import 'package:stackwallet/utilities/test_stellar_node_connection.dart';
 import 'package:stackwallet/utilities/text_styles.dart';
 import 'package:stackwallet/utilities/util.dart';
 import 'package:stackwallet/widgets/background.dart';
@@ -172,20 +173,19 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> {
 
       case Coin.nano:
       case Coin.banano:
-      case Coin.tezos:
       case Coin.stellar:
       case Coin.stellarTestNet:
-      try {
-        testPassed = await testStellarNodeConnection(node!.host, node.port);
-      } catch(_) {
-        testPassed = false;
-      }
+        try {
+          testPassed = await testStellarNodeConnection(node!.host, node.port);
+        } catch (_) {
+          testPassed = false;
+        }
         break;
       case Coin.nano:
       case Coin.banano:
-
+      case Coin.tezos:
         throw UnimplementedError();
-        //TODO: check network/node
+      //TODO: check network/node
     }
 
     if (testPassed) {
diff --git a/lib/utilities/enums/coin_enum.dart b/lib/utilities/enums/coin_enum.dart
index f4a4ca28f..b8af7f53c 100644
--- a/lib/utilities/enums/coin_enum.dart
+++ b/lib/utilities/enums/coin_enum.dart
@@ -262,7 +262,8 @@ extension CoinExt on Coin {
       case Coin.ethereum:
       case Coin.eCash:
       case Coin.stellar:
-      case Coin.stellarTestnet:
+      case Coin.stellarTestNet:
+      case Coin.tezos:
         return true;
 
       case Coin.epicCash:
diff --git a/lib/widgets/node_card.dart b/lib/widgets/node_card.dart
index a75b09c64..b63c21b93 100644
--- a/lib/widgets/node_card.dart
+++ b/lib/widgets/node_card.dart
@@ -29,6 +29,7 @@ import 'package:stackwallet/utilities/logger.dart';
 import 'package:stackwallet/utilities/test_epic_box_connection.dart';
 import 'package:stackwallet/utilities/test_eth_node_connection.dart';
 import 'package:stackwallet/utilities/test_monero_node_connection.dart';
+import 'package:stackwallet/utilities/test_stellar_node_connection.dart';
 import 'package:stackwallet/utilities/text_styles.dart';
 import 'package:stackwallet/utilities/util.dart';
 import 'package:stackwallet/widgets/conditional_parent.dart';
@@ -199,7 +200,7 @@ class _NodeCardState extends ConsumerState<NodeCard> {
       case Coin.stellarTestNet:
         try {
           testPassed = await testStellarNodeConnection(node.host, node.port);
-        } catch(_) {
+        } catch (_) {
           testPassed = false;
         }
         break;
@@ -207,7 +208,7 @@ class _NodeCardState extends ConsumerState<NodeCard> {
       case Coin.nano:
       case Coin.banano:
         throw UnimplementedError();
-        //TODO: check network/node
+      //TODO: check network/node
     }
 
     if (testPassed) {

From 02b67c2a2e0de3743550ea7f5664158ab93d0075 Mon Sep 17 00:00:00 2001
From: ryleedavis <rylee@cypherstack.com>
Date: Wed, 23 Aug 2023 11:08:32 -0600
Subject: [PATCH 29/39] add parameter to initializeNew for tezos

---
 lib/services/coins/tezos/tezos_wallet.dart | 50 +++++++++++-----------
 1 file changed, 24 insertions(+), 26 deletions(-)

diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart
index 1fb192190..6b0d10cc6 100644
--- a/lib/services/coins/tezos/tezos_wallet.dart
+++ b/lib/services/coins/tezos/tezos_wallet.dart
@@ -186,16 +186,14 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   @override
   Future<String> confirmSend({required Map<String, dynamic> txData}) async {
     try {
-
       final amount = txData["recipientAmt"] as Amount;
-      final amountInMicroTez =
-          amount.decimal * Decimal.fromInt(1000000);
+      final amountInMicroTez = amount.decimal * Decimal.fromInt(1000000);
       final microtezToInt = int.parse(amountInMicroTez.toString());
 
       final int feeInMicroTez = int.parse(txData["fee"].toString());
       final String destinationAddress = txData["address"] as String;
-      final secretKey = Keystore.fromMnemonic((await mnemonicString)!)
-          .secretKey;
+      final secretKey =
+          Keystore.fromMnemonic((await mnemonicString)!).secretKey;
 
       Logging.instance.log(secretKey, level: LogLevel.Info);
       final sourceKeyStore = Keystore.fromSecretKey(secretKey);
@@ -208,9 +206,9 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
       if (balance.spendable == txData["recipientAmt"] as Amount) {
         //Fee guides for emptying a tz account
         // https://github.com/TezTech/eztz/blob/master/PROTO_004_FEES.md
-         thisFee = thisFee + 32;
-         sendAmount = microtezToInt - thisFee;
-         gasLimit = _gasLimit + 320;
+        thisFee = thisFee + 32;
+        sendAmount = microtezToInt - thisFee;
+        gasLimit = _gasLimit + 320;
       }
 
       final operation = await client.transferOperation(
@@ -218,8 +216,7 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
           destination: destinationAddress,
           amount: sendAmount,
           customFee: feeInMicroTez,
-          customGasLimit: gasLimit
-      );
+          customGasLimit: gasLimit);
       await operation.executeAndMonitor();
       return operation.result.id as String;
     } catch (e) {
@@ -239,7 +236,6 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
   @override
   Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
-
     var api = "https://api.tzstats.com/series/op?start_date=today&collapse=1d";
     var response = jsonDecode((await get(Uri.parse(api))).body)[0];
     double totalFees = response[4] as double;
@@ -300,7 +296,9 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   }
 
   @override
-  Future<void> initializeNew() async {
+  Future<void> initializeNew(
+    ({String mnemonicPassphrase, int wordCount})? data,
+  ) async {
     if ((await mnemonicString) != null || (await mnemonicPassphrase) != null) {
       throw Exception(
           "Attempted to overwrite mnemonic on generate new wallet!");
@@ -409,7 +407,8 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
     try {
       String balanceCall = "https://api.mainnet.tzkt.io/v1/accounts/"
           "${await currentReceivingAddress}/balance";
-      var response = jsonDecode(await get(Uri.parse(balanceCall)).then((value) => value.body));
+      var response = jsonDecode(
+          await get(Uri.parse(balanceCall)).then((value) => value.body));
       Amount balanceInAmount = Amount(
           rawValue: BigInt.parse(response.toString()),
           fractionDigits: coin.decimals);
@@ -431,7 +430,8 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   Future<void> updateTransactions() async {
     String transactionsCall = "https://api.mainnet.tzkt.io/v1/accounts/"
         "${await currentReceivingAddress}/operations";
-    var response = jsonDecode(await get(Uri.parse(transactionsCall)).then((value) => value.body));
+    var response = jsonDecode(
+        await get(Uri.parse(transactionsCall)).then((value) => value.body));
     List<Tuple2<Transaction, Address>> txs = [];
     for (var tx in response as List) {
       if (tx["type"] == "transaction") {
@@ -446,18 +446,16 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
           walletId: walletId,
           txid: tx["hash"].toString(),
           timestamp: DateTime.parse(tx["timestamp"].toString())
-              .toUtc()
-              .millisecondsSinceEpoch ~/
+                  .toUtc()
+                  .millisecondsSinceEpoch ~/
               1000,
           type: txType,
           subType: TransactionSubType.none,
           amount: tx["amount"] as int,
           amountString: Amount(
-              rawValue: BigInt.parse(
-                  (tx["amount"] as int)
-                      .toInt()
-                      .toString()),
-              fractionDigits: coin.decimals)
+                  rawValue:
+                      BigInt.parse((tx["amount"] as int).toInt().toString()),
+                  fractionDigits: coin.decimals)
               .toJsonString(),
           fee: tx["bakerFee"] as int,
           height: int.parse(tx["level"].toString()),
@@ -561,14 +559,14 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
     );
 
     final address = txData["address"] is String
-          ? await db.getAddress(walletId, txData["address"] as String)
-          : null;
+        ? await db.getAddress(walletId, txData["address"] as String)
+        : null;
 
     await db.addNewTransactionData(
-        [
+      [
         Tuple2(transaction, address),
-        ],
-        walletId,
+      ],
+      walletId,
     );
   }
 

From 63ab0b09e897dc993b9c0fdbe1bfb74be4ea2835 Mon Sep 17 00:00:00 2001
From: julian <julian@cypherstack.com>
Date: Wed, 23 Aug 2023 11:29:10 -0600
Subject: [PATCH 30/39] revert enum name

---
 .../add_edit_node_view.dart                   |  4 +--
 .../manage_nodes_views/node_details_view.dart |  2 +-
 lib/services/coins/coin_service.dart          |  2 +-
 lib/themes/color_theme.dart                   |  2 +-
 lib/themes/stack_colors.dart                  |  2 +-
 lib/utilities/address_utils.dart              |  2 +-
 lib/utilities/amount/amount_unit.dart         |  2 +-
 lib/utilities/block_explorers.dart            |  2 +-
 lib/utilities/constants.dart                  | 10 ++++----
 lib/utilities/default_nodes.dart              | 25 +++++++++----------
 lib/utilities/enums/coin_enum.dart            | 24 +++++++++---------
 .../enums/derive_path_type_enum.dart          |  2 +-
 lib/widgets/node_card.dart                    |  2 +-
 lib/widgets/node_options_sheet.dart           |  2 +-
 14 files changed, 41 insertions(+), 42 deletions(-)

diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
index 5ae04920d..8a09a3d03 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
@@ -196,7 +196,7 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
         } catch (_) {}
         break;
       case Coin.stellar:
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         try {
           testPassed =
               await testStellarNodeConnection(formData.host!, formData.port!);
@@ -750,7 +750,7 @@ class _NodeFormState extends ConsumerState<NodeForm> {
       case Coin.banano:
       case Coin.eCash:
       case Coin.stellar:
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         return false;
 
       case Coin.ethereum:
diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
index d306260d6..de3a4b5e5 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
@@ -174,7 +174,7 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> {
       case Coin.nano:
       case Coin.banano:
       case Coin.stellar:
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         try {
           testPassed = await testStellarNodeConnection(node!.host, node.port);
         } catch (_) {
diff --git a/lib/services/coins/coin_service.dart b/lib/services/coins/coin_service.dart
index 72478b353..360372095 100644
--- a/lib/services/coins/coin_service.dart
+++ b/lib/services/coins/coin_service.dart
@@ -229,7 +229,7 @@ abstract class CoinServiceAPI {
           tracker: tracker,
         );
 
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         return StellarWallet(
           walletId: walletId,
           walletName: walletName,
diff --git a/lib/themes/color_theme.dart b/lib/themes/color_theme.dart
index 0e6816dd8..abec28d4e 100644
--- a/lib/themes/color_theme.dart
+++ b/lib/themes/color_theme.dart
@@ -65,7 +65,7 @@ class CoinThemeColorDefault {
       case Coin.particl:
         return particl;
       case Coin.stellar:
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         return stellar;
       case Coin.nano:
         return nano;
diff --git a/lib/themes/stack_colors.dart b/lib/themes/stack_colors.dart
index fde5219cf..cbec0077a 100644
--- a/lib/themes/stack_colors.dart
+++ b/lib/themes/stack_colors.dart
@@ -1708,7 +1708,7 @@ class StackColors extends ThemeExtension<StackColors> {
       case Coin.particl:
         return _coin.particl;
       case Coin.stellar:
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         return _coin.stellar;
       case Coin.nano:
         return _coin.nano;
diff --git a/lib/utilities/address_utils.dart b/lib/utilities/address_utils.dart
index b4974d8c6..3fa895282 100644
--- a/lib/utilities/address_utils.dart
+++ b/lib/utilities/address_utils.dart
@@ -143,7 +143,7 @@ class AddressUtils {
         return Address.validateAddress(address, firoTestNetwork);
       case Coin.dogecoinTestNet:
         return Address.validateAddress(address, dogecointestnet);
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         return RegExp(r"^[G][A-Z0-9]{55}$").hasMatch(address);
     }
   }
diff --git a/lib/utilities/amount/amount_unit.dart b/lib/utilities/amount/amount_unit.dart
index 00055a0fe..6a646fd11 100644
--- a/lib/utilities/amount/amount_unit.dart
+++ b/lib/utilities/amount/amount_unit.dart
@@ -51,7 +51,7 @@ enum AmountUnit {
       case Coin.eCash:
       case Coin.epicCash:
       case Coin.stellar: // TODO: check if this is correct
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
       case Coin.tezos:
         return AmountUnit.values.sublist(0, 4);
 
diff --git a/lib/utilities/block_explorers.dart b/lib/utilities/block_explorers.dart
index ddc055fb1..bb4ac06fb 100644
--- a/lib/utilities/block_explorers.dart
+++ b/lib/utilities/block_explorers.dart
@@ -60,7 +60,7 @@ Uri getDefaultBlockExplorerUrlFor({
       return Uri.parse("https://www.nanolooker.com/block/$txid");
     case Coin.banano:
       return Uri.parse("https://www.bananolooker.com/block/$txid");
-    case Coin.stellarTestNet:
+    case Coin.stellarTestnet:
       return Uri.parse("https://testnet.stellarchain.io/transactions/$txid");
     case Coin.tezos:
       return Uri.parse("https://tzstats.com/$txid");
diff --git a/lib/utilities/constants.dart b/lib/utilities/constants.dart
index 1bd3a5a50..1253e08f1 100644
--- a/lib/utilities/constants.dart
+++ b/lib/utilities/constants.dart
@@ -102,7 +102,7 @@ abstract class Constants {
         return _satsPerCoinECash;
 
       case Coin.stellar:
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         return _satsPerCoinStellar;
 
       case Coin.tezos:
@@ -146,7 +146,7 @@ abstract class Constants {
         return _decimalPlacesECash;
 
       case Coin.stellar:
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         return _decimalPlacesStellar;
 
       case Coin.tezos:
@@ -174,7 +174,7 @@ abstract class Constants {
       case Coin.particl:
       case Coin.nano:
       case Coin.stellar:
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         values.addAll([24, 12]);
         break;
       case Coin.banano:
@@ -238,7 +238,7 @@ abstract class Constants {
         return 1;
 
       case Coin.stellar:
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         return 5;
 
       case Coin.tezos:
@@ -271,7 +271,7 @@ abstract class Constants {
       case Coin.nano:
       case Coin.banano:
       case Coin.stellar:
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
       case Coin.tezos:
         return 24;
 
diff --git a/lib/utilities/default_nodes.dart b/lib/utilities/default_nodes.dart
index 7fed3d7fd..210959f65 100644
--- a/lib/utilities/default_nodes.dart
+++ b/lib/utilities/default_nodes.dart
@@ -191,8 +191,7 @@ abstract class DefaultNodes {
       enabled: true,
       coinName: Coin.stellar.name,
       isFailover: true,
-      isDown: false
-  );
+      isDown: false);
 
   static NodeModel get tezos => NodeModel(
       // TODO: Change this to stack wallet one
@@ -289,16 +288,16 @@ abstract class DefaultNodes {
       );
 
   static NodeModel get stellarTestnet => NodeModel(
-    host: "https://horizon-testnet.stellar.org/",
-    port: 50022,
-    name: defaultName,
-    id: _nodeId(Coin.stellarTestNet),
-    useSSL: true,
-    enabled: true,
-    coinName: Coin.stellarTestNet.name,
-    isFailover: true,
-    isDown: false,
-  );
+        host: "https://horizon-testnet.stellar.org/",
+        port: 50022,
+        name: defaultName,
+        id: _nodeId(Coin.stellarTestnet),
+        useSSL: true,
+        enabled: true,
+        coinName: Coin.stellarTestnet.name,
+        isFailover: true,
+        isDown: false,
+      );
 
   static NodeModel getNodeFor(Coin coin) {
     switch (coin) {
@@ -365,7 +364,7 @@ abstract class DefaultNodes {
       case Coin.dogecoinTestNet:
         return dogecoinTestnet;
 
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         return stellarTestnet;
     }
   }
diff --git a/lib/utilities/enums/coin_enum.dart b/lib/utilities/enums/coin_enum.dart
index b8af7f53c..f5a42e8da 100644
--- a/lib/utilities/enums/coin_enum.dart
+++ b/lib/utilities/enums/coin_enum.dart
@@ -60,7 +60,7 @@ enum Coin {
   dogecoinTestNet,
   firoTestNet,
   litecoinTestNet,
-  stellarTestNet,
+  stellarTestnet,
 }
 
 final int kTestNetCoinCount = 5; // Util.isDesktop ? 5 : 4;
@@ -111,7 +111,7 @@ extension CoinExt on Coin {
         return "tFiro";
       case Coin.dogecoinTestNet:
         return "tDogecoin";
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         return "tStellar";
     }
   }
@@ -160,7 +160,7 @@ extension CoinExt on Coin {
         return "tFIRO";
       case Coin.dogecoinTestNet:
         return "tDOGE";
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         return "tXLM";
     }
   }
@@ -210,7 +210,7 @@ extension CoinExt on Coin {
         return "firo";
       case Coin.dogecoinTestNet:
         return "dogecoin";
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         return "stellar";
     }
   }
@@ -240,7 +240,7 @@ extension CoinExt on Coin {
       case Coin.nano:
       case Coin.banano:
       case Coin.stellar:
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         return false;
     }
   }
@@ -262,7 +262,7 @@ extension CoinExt on Coin {
       case Coin.ethereum:
       case Coin.eCash:
       case Coin.stellar:
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
       case Coin.tezos:
         return true;
 
@@ -300,7 +300,7 @@ extension CoinExt on Coin {
       case Coin.nano:
       case Coin.banano:
       case Coin.stellar:
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         return false;
     }
   }
@@ -330,7 +330,7 @@ extension CoinExt on Coin {
       case Coin.litecoinTestNet:
       case Coin.bitcoincashTestnet:
       case Coin.firoTestNet:
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         return true;
     }
   }
@@ -370,7 +370,7 @@ extension CoinExt on Coin {
       case Coin.firoTestNet:
         return Coin.firo;
 
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         return Coin.stellar;
     }
   }
@@ -413,7 +413,7 @@ extension CoinExt on Coin {
         return particl.MINIMUM_CONFIRMATIONS;
 
       case Coin.stellar:
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         return xlm.MINIMUM_CONFIRMATIONS;
 
       case Coin.tezos:
@@ -534,7 +534,7 @@ Coin coinFromPrettyName(String name) {
     case "stellarTestnet":
     case "stellarTestNet":
     case "tStellar":
-      return Coin.stellarTestNet;
+      return Coin.stellarTestnet;
 
     default:
       throw ArgumentError.value(
@@ -590,7 +590,7 @@ Coin coinFromTickerCaseInsensitive(String ticker) {
     case "ban":
       return Coin.banano;
     case "txlm":
-      return Coin.stellarTestNet;
+      return Coin.stellarTestnet;
     default:
       throw ArgumentError.value(
           ticker, "name", "No Coin enum value with that ticker");
diff --git a/lib/utilities/enums/derive_path_type_enum.dart b/lib/utilities/enums/derive_path_type_enum.dart
index f3c456f67..5b94f41f6 100644
--- a/lib/utilities/enums/derive_path_type_enum.dart
+++ b/lib/utilities/enums/derive_path_type_enum.dart
@@ -50,7 +50,7 @@ extension DerivePathTypeExt on DerivePathType {
       case Coin.nano:
       case Coin.banano:
       case Coin.stellar:
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
       case Coin.tezos: // TODO: Is this true?
         throw UnsupportedError(
             "$coin does not use bitcoin style derivation paths");
diff --git a/lib/widgets/node_card.dart b/lib/widgets/node_card.dart
index b63c21b93..0f65fcfd5 100644
--- a/lib/widgets/node_card.dart
+++ b/lib/widgets/node_card.dart
@@ -197,7 +197,7 @@ class _NodeCardState extends ConsumerState<NodeCard> {
       case Coin.banano:
       case Coin.tezos:
       case Coin.stellar:
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         try {
           testPassed = await testStellarNodeConnection(node.host, node.port);
         } catch (_) {
diff --git a/lib/widgets/node_options_sheet.dart b/lib/widgets/node_options_sheet.dart
index 63fd2b13e..953ac78a1 100644
--- a/lib/widgets/node_options_sheet.dart
+++ b/lib/widgets/node_options_sheet.dart
@@ -179,7 +179,7 @@ class NodeOptionsSheet extends ConsumerWidget {
       case Coin.banano:
       case Coin.tezos:
       case Coin.stellar:
-      case Coin.stellarTestNet:
+      case Coin.stellarTestnet:
         throw UnimplementedError();
       //TODO: check network/node
     }

From 4de632bdb47d8ee11310bc57ae957c202caeb4cd Mon Sep 17 00:00:00 2001
From: julian <julian@cypherstack.com>
Date: Wed, 23 Aug 2023 11:35:04 -0600
Subject: [PATCH 31/39] fix switch statement logic

---
 .../manage_nodes_views/add_edit_node_view.dart            | 3 +--
 .../manage_nodes_views/node_details_view.dart             | 8 +++-----
 lib/widgets/node_card.dart                                | 7 ++-----
 3 files changed, 6 insertions(+), 12 deletions(-)

diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
index 8a09a3d03..2bb833fd1 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
@@ -205,9 +205,8 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
 
       case Coin.nano:
       case Coin.banano:
-        throw UnimplementedError();
-      //TODO: check network/node
       case Coin.tezos:
+        throw UnimplementedError();
       //TODO: check network/node
     }
 
diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
index de3a4b5e5..c05cbbca5 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
@@ -173,6 +173,9 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> {
 
       case Coin.nano:
       case Coin.banano:
+      case Coin.tezos:
+        throw UnimplementedError();
+      //TODO: check network/node
       case Coin.stellar:
       case Coin.stellarTestnet:
         try {
@@ -181,11 +184,6 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> {
           testPassed = false;
         }
         break;
-      case Coin.nano:
-      case Coin.banano:
-      case Coin.tezos:
-        throw UnimplementedError();
-      //TODO: check network/node
     }
 
     if (testPassed) {
diff --git a/lib/widgets/node_card.dart b/lib/widgets/node_card.dart
index 0f65fcfd5..44b8a696a 100644
--- a/lib/widgets/node_card.dart
+++ b/lib/widgets/node_card.dart
@@ -196,6 +196,8 @@ class _NodeCardState extends ConsumerState<NodeCard> {
       case Coin.nano:
       case Coin.banano:
       case Coin.tezos:
+        //TODO: check network/node
+        throw UnimplementedError();
       case Coin.stellar:
       case Coin.stellarTestnet:
         try {
@@ -204,11 +206,6 @@ class _NodeCardState extends ConsumerState<NodeCard> {
           testPassed = false;
         }
         break;
-
-      case Coin.nano:
-      case Coin.banano:
-        throw UnimplementedError();
-      //TODO: check network/node
     }
 
     if (testPassed) {

From 2e64d356294486af92b8b335085eded4f14aa0ed Mon Sep 17 00:00:00 2001
From: julian <julian@cypherstack.com>
Date: Wed, 23 Aug 2023 11:49:21 -0600
Subject: [PATCH 32/39] tezos does not used the bip39 lib directly. Do not show
 new wallet options. Needs more investigation

---
 lib/utilities/enums/coin_enum.dart | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/utilities/enums/coin_enum.dart b/lib/utilities/enums/coin_enum.dart
index f5a42e8da..77af4b4d1 100644
--- a/lib/utilities/enums/coin_enum.dart
+++ b/lib/utilities/enums/coin_enum.dart
@@ -263,7 +263,6 @@ extension CoinExt on Coin {
       case Coin.eCash:
       case Coin.stellar:
       case Coin.stellarTestnet:
-      case Coin.tezos:
         return true;
 
       case Coin.epicCash:
@@ -271,6 +270,7 @@ extension CoinExt on Coin {
       case Coin.wownero:
       case Coin.nano:
       case Coin.banano:
+      case Coin.tezos:
         return false;
     }
   }

From 19a6e0b8263d9c89e5af278891b8d44062ee8abe Mon Sep 17 00:00:00 2001
From: julian <julian@cypherstack.com>
Date: Wed, 23 Aug 2023 11:58:16 -0600
Subject: [PATCH 33/39] fix tezos refresh function

---
 lib/services/coins/tezos/tezos_wallet.dart | 68 ++++++++++++++++++++--
 1 file changed, 63 insertions(+), 5 deletions(-)

diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart
index 6b0d10cc6..bf0a8cf5d 100644
--- a/lib/services/coins/tezos/tezos_wallet.dart
+++ b/lib/services/coins/tezos/tezos_wallet.dart
@@ -13,6 +13,8 @@ import 'package:stackwallet/models/node_model.dart';
 import 'package:stackwallet/models/paymint/fee_object_model.dart';
 import 'package:stackwallet/services/coins/coin_service.dart';
 import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
+import 'package:stackwallet/services/event_bus/events/global/updated_in_background_event.dart';
+import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
 import 'package:stackwallet/services/event_bus/global_event_bus.dart';
 import 'package:stackwallet/services/mixins/wallet_cache.dart';
 import 'package:stackwallet/services/mixins/wallet_db.dart';
@@ -499,11 +501,67 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   }
 
   @override
-  Future<void> refresh() {
-    updateChainHeight();
-    updateBalance();
-    updateTransactions();
-    return Future.value();
+  Future<void> refresh() async {
+    if (refreshMutex) {
+      Logging.instance.log(
+        "$walletId $walletName refreshMutex denied",
+        level: LogLevel.Info,
+      );
+      return;
+    } else {
+      refreshMutex = true;
+    }
+
+    try {
+      GlobalEventBus.instance.fire(
+        WalletSyncStatusChangedEvent(
+          WalletSyncStatus.syncing,
+          walletId,
+          coin,
+        ),
+      );
+
+      await updateChainHeight();
+      await updateBalance();
+      await updateTransactions();
+      GlobalEventBus.instance.fire(
+        WalletSyncStatusChangedEvent(
+          WalletSyncStatus.synced,
+          walletId,
+          coin,
+        ),
+      );
+
+      if (shouldAutoSync) {
+        timer ??= Timer.periodic(const Duration(seconds: 30), (timer) async {
+          Logging.instance.log(
+              "Periodic refresh check for $walletId $walletName in object instance: $hashCode",
+              level: LogLevel.Info);
+
+          await refresh();
+          GlobalEventBus.instance.fire(
+            UpdatedInBackgroundEvent(
+              "New data found in $walletId $walletName in background!",
+              walletId,
+            ),
+          );
+        });
+      }
+    } catch (e, s) {
+      Logging.instance.log(
+        "Failed to refresh stellar wallet $walletId: '$walletName': $e\n$s",
+        level: LogLevel.Warning,
+      );
+      GlobalEventBus.instance.fire(
+        WalletSyncStatusChangedEvent(
+          WalletSyncStatus.unableToSync,
+          walletId,
+          coin,
+        ),
+      );
+    }
+
+    refreshMutex = false;
   }
 
   @override

From 31cac4b9502eb02b5ccc190d93dacd2e764d4cf5 Mon Sep 17 00:00:00 2001
From: julian <julian@cypherstack.com>
Date: Wed, 23 Aug 2023 14:12:11 -0600
Subject: [PATCH 34/39] code formatting

---
 .../coins/stellar/stellar_wallet.dart         | 35 +++++++++----------
 1 file changed, 16 insertions(+), 19 deletions(-)

diff --git a/lib/services/coins/stellar/stellar_wallet.dart b/lib/services/coins/stellar/stellar_wallet.dart
index a9f9d97df..c5ee3114b 100644
--- a/lib/services/coins/stellar/stellar_wallet.dart
+++ b/lib/services/coins/stellar/stellar_wallet.dart
@@ -1,6 +1,6 @@
 import 'dart:async';
+
 import 'package:bip39/bip39.dart' as bip39;
-import 'package:http/http.dart' as http;
 import 'package:isar/isar.dart';
 import 'package:stackwallet/db/isar/main_db.dart';
 import 'package:stackwallet/models/balance.dart' as SWBalance;
@@ -37,7 +37,6 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
   late StellarSDK stellarSdk;
   late Network stellarNetwork;
 
-
   StellarWallet({
     required String walletId,
     required String walletName,
@@ -54,7 +53,6 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
     initCache(walletId, coin);
     initWalletDB(mockableOverride: mockableOverride);
 
-
     if (coin.isTestNet) {
       stellarNetwork = Network.TESTNET;
     } else {
@@ -66,7 +64,7 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
   void _updateNode() {
     _xlmNode = NodeService(secureStorageInterface: _secureStore)
-        .getPrimaryNodeFor(coin: coin) ??
+            .getPrimaryNodeFor(coin: coin) ??
         DefaultNodes.getNodeFor(coin);
     stellarSdk = StellarSDK("${_xlmNode!.host}:${_xlmNode!.port}");
   }
@@ -212,13 +210,12 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
     }
     transaction.sign(senderKeyPair, stellarNetwork);
     try {
-      SubmitTransactionResponse response =
-          await stellarSdk.submitTransaction(transaction).onError((error, stackTrace) => throw (error.toString()));
+      SubmitTransactionResponse response = await stellarSdk
+          .submitTransaction(transaction)
+          .onError((error, stackTrace) => throw (error.toString()));
       if (!response.success) {
-        throw (
-            "${response.extras?.resultCodes?.transactionResultCode}"
-                " ::: ${response.extras?.resultCodes?.operationsResultCodes}"
-        );
+        throw ("${response.extras?.resultCodes?.transactionResultCode}"
+            " ::: ${response.extras?.resultCodes?.operationsResultCodes}");
       }
       return response.hash!;
     } catch (e, s) {
@@ -248,7 +245,8 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
   @override
   Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
     var baseFee = await getBaseFee();
-    return Amount(rawValue: BigInt.from(baseFee), fractionDigits: coin.decimals);
+    return Amount(
+        rawValue: BigInt.from(baseFee), fractionDigits: coin.decimals);
   }
 
   @override
@@ -276,7 +274,6 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
   @override
   Future<FeeObject> get fees async {
-
     int fee = await getBaseFee();
     return FeeObject(
         numberOfBlocksFast: 10,
@@ -402,7 +399,6 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
       {required String address,
       required Amount amount,
       Map<String, dynamic>? args}) async {
-
     try {
       final feeRate = args?["feeRate"];
       var fee = 1000;
@@ -433,12 +429,13 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
   }
 
   @override
-  Future<void> recoverFromMnemonic(
-      {required String mnemonic,
-      String? mnemonicPassphrase,
-      required int maxUnusedAddressGap,
-      required int maxNumberOfIndexesToCheck,
-      required int height}) async {
+  Future<void> recoverFromMnemonic({
+    required String mnemonic,
+    String? mnemonicPassphrase,
+    required int maxUnusedAddressGap,
+    required int maxNumberOfIndexesToCheck,
+    required int height,
+  }) async {
     if ((await mnemonicString) != null ||
         (await this.mnemonicPassphrase) != null) {
       throw Exception("Attempted to overwrite mnemonic on restore!");

From 4b5686d8a4c009146ec853ab3481c47d7bde41c9 Mon Sep 17 00:00:00 2001
From: julian <julian@cypherstack.com>
Date: Wed, 23 Aug 2023 14:31:34 -0600
Subject: [PATCH 35/39] handle stellar rescan properly

---
 .../coins/stellar/stellar_wallet.dart         | 173 ++++++++++++++----
 1 file changed, 133 insertions(+), 40 deletions(-)

diff --git a/lib/services/coins/stellar/stellar_wallet.dart b/lib/services/coins/stellar/stellar_wallet.dart
index c5ee3114b..fc77bfe72 100644
--- a/lib/services/coins/stellar/stellar_wallet.dart
+++ b/lib/services/coins/stellar/stellar_wallet.dart
@@ -28,6 +28,7 @@ import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
 import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
 import 'package:stackwallet/utilities/logger.dart';
 import 'package:stackwallet/utilities/prefs.dart';
+import 'package:stackwallet/utilities/test_stellar_node_connection.dart';
 import 'package:stellar_flutter_sdk/stellar_flutter_sdk.dart';
 import 'package:tuple/tuple.dart';
 
@@ -286,16 +287,65 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
 
   @override
   Future<void> fullRescan(
-      int maxUnusedAddressGap, int maxNumberOfIndexesToCheck) async {
-    await _prefs.init();
-    await updateTransactions();
-    await updateChainHeight();
-    await updateBalance();
+    int maxUnusedAddressGap,
+    int maxNumberOfIndexesToCheck,
+  ) async {
+    try {
+      Logging.instance.log("Starting full rescan!", level: LogLevel.Info);
+      longMutex = true;
+      GlobalEventBus.instance.fire(
+        WalletSyncStatusChangedEvent(
+          WalletSyncStatus.syncing,
+          walletId,
+          coin,
+        ),
+      );
+
+      final _mnemonic = await mnemonicString;
+      final _mnemonicPassphrase = await mnemonicPassphrase;
+
+      await db.deleteWalletBlockchainData(walletId);
+
+      await _recoverWalletFromBIP32SeedPhrase(
+        mnemonic: _mnemonic!,
+        mnemonicPassphrase: _mnemonicPassphrase!,
+        isRescan: true,
+      );
+
+      await refresh();
+      Logging.instance.log("Full rescan complete!", level: LogLevel.Info);
+      GlobalEventBus.instance.fire(
+        WalletSyncStatusChangedEvent(
+          WalletSyncStatus.synced,
+          walletId,
+          coin,
+        ),
+      );
+    } catch (e, s) {
+      GlobalEventBus.instance.fire(
+        WalletSyncStatusChangedEvent(
+          WalletSyncStatus.unableToSync,
+          walletId,
+          coin,
+        ),
+      );
+
+      // restore from backup
+      // await _rescanRestore();
+
+      Logging.instance.log(
+        "Exception rethrown from fullRescan(): $e\n$s",
+        level: LogLevel.Error,
+      );
+      rethrow;
+    } finally {
+      longMutex = false;
+    }
   }
 
   @override
   Future<bool> generateNewAddress() {
-    // TODO: implement generateNewAddress
+    // not used for stellar(?)
     throw UnimplementedError();
   }
 
@@ -428,6 +478,44 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
     }
   }
 
+  Future<void> _recoverWalletFromBIP32SeedPhrase({
+    required String mnemonic,
+    required String mnemonicPassphrase,
+    bool isRescan = false,
+  }) async {
+    final Wallet wallet = await Wallet.from(
+      mnemonic,
+      passphrase: mnemonicPassphrase,
+    );
+    final KeyPair keyPair = await wallet.getKeyPair(index: 0);
+    final String address = keyPair.accountId;
+    String secretSeed =
+        keyPair.secretSeed; //This will be required for sending a tx
+
+    await _secureStore.write(
+      key: '${_walletId}_secretSeed',
+      value: secretSeed,
+    );
+
+    final swAddress = SWAddress.Address(
+      walletId: walletId,
+      value: address,
+      publicKey: keyPair.publicKey,
+      derivationIndex: 0,
+      derivationPath: null,
+      type: SWAddress.AddressType.unknown,
+      subType: SWAddress.AddressSubType.unknown,
+    );
+
+    if (isRescan) {
+      await db.updateOrPutAddresses([swAddress]);
+    } else {
+      await db.putAddress(swAddress);
+    }
+  }
+
+  bool longMutex = false;
+
   @override
   Future<void> recoverFromMnemonic({
     required String mnemonic,
@@ -436,37 +524,41 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
     required int maxNumberOfIndexesToCheck,
     required int height,
   }) async {
-    if ((await mnemonicString) != null ||
-        (await this.mnemonicPassphrase) != null) {
-      throw Exception("Attempted to overwrite mnemonic on restore!");
+    longMutex = true;
+    try {
+      if ((await mnemonicString) != null ||
+          (await this.mnemonicPassphrase) != null) {
+        throw Exception("Attempted to overwrite mnemonic on restore!");
+      }
+
+      await _secureStore.write(
+        key: '${_walletId}_mnemonic',
+        value: mnemonic.trim(),
+      );
+      await _secureStore.write(
+        key: '${_walletId}_mnemonicPassphrase',
+        value: mnemonicPassphrase ?? "",
+      );
+
+      await _recoverWalletFromBIP32SeedPhrase(
+        mnemonic: mnemonic,
+        mnemonicPassphrase: mnemonicPassphrase ?? "",
+        isRescan: false,
+      );
+
+      await Future.wait([
+        updateCachedId(walletId),
+        updateCachedIsFavorite(false),
+      ]);
+    } catch (e, s) {
+      Logging.instance.log(
+          "Exception rethrown from recoverFromMnemonic(): $e\n$s",
+          level: LogLevel.Error);
+
+      rethrow;
+    } finally {
+      longMutex = false;
     }
-
-    var wallet = await Wallet.from(mnemonic);
-    var keyPair = await wallet.getKeyPair(index: 0);
-    var address = keyPair.accountId;
-    var secretSeed = keyPair.secretSeed;
-
-    await _secureStore.write(
-        key: '${_walletId}_mnemonic', value: mnemonic.trim());
-    await _secureStore.write(
-      key: '${_walletId}_mnemonicPassphrase',
-      value: mnemonicPassphrase ?? "",
-    );
-    await _secureStore.write(key: '${_walletId}_secretSeed', value: secretSeed);
-
-    final swAddress = SWAddress.Address(
-        walletId: walletId,
-        value: address,
-        publicKey: keyPair.publicKey,
-        derivationIndex: 0,
-        derivationPath: null,
-        type: SWAddress.AddressType.unknown, // TODO: set type
-        subType: SWAddress.AddressSubType.unknown);
-
-    await db.putAddress(swAddress);
-
-    await Future.wait(
-        [updateCachedId(walletId), updateCachedIsFavorite(false)]);
   }
 
   Future<void> updateChainHeight() async {
@@ -622,6 +714,7 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
       Logging.instance.log(
           "Exception rethrown from updateTransactions(): $e\n$s",
           level: LogLevel.Error);
+      rethrow;
     }
   }
 
@@ -659,6 +752,7 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
         "ERROR GETTING BALANCE $e\n$s",
         level: LogLevel.Info,
       );
+      rethrow;
     }
   }
 
@@ -733,9 +827,8 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
   int get storedChainHeight => getCachedChainHeight();
 
   @override
-  Future<bool> testNetworkConnection() {
-    // TODO: implement testNetworkConnection
-    throw UnimplementedError();
+  Future<bool> testNetworkConnection() async {
+    return await testStellarNodeConnection(_xlmNode!.host, _xlmNode!.port);
   }
 
   @override
@@ -786,7 +879,7 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
   }
 
   @override
-  // TODO: implement utxos
+  // not used
   Future<List<UTXO>> get utxos => throw UnimplementedError();
 
   @override

From 3cd31d1bf26fa26dccbb161966d6f3c16a7eb125 Mon Sep 17 00:00:00 2001
From: julian <julian@cypherstack.com>
Date: Wed, 23 Aug 2023 14:56:40 -0600
Subject: [PATCH 36/39] clean up

---
 lib/services/coins/stellar/stellar_wallet.dart | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/lib/services/coins/stellar/stellar_wallet.dart b/lib/services/coins/stellar/stellar_wallet.dart
index fc77bfe72..b12954628 100644
--- a/lib/services/coins/stellar/stellar_wallet.dart
+++ b/lib/services/coins/stellar/stellar_wallet.dart
@@ -330,9 +330,6 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
         ),
       );
 
-      // restore from backup
-      // await _rescanRestore();
-
       Logging.instance.log(
         "Exception rethrown from fullRescan(): $e\n$s",
         level: LogLevel.Error,

From 6e4a23007b5fe804e87e5afe7deac27308192e8e Mon Sep 17 00:00:00 2001
From: julian <julian@cypherstack.com>
Date: Wed, 23 Aug 2023 14:58:22 -0600
Subject: [PATCH 37/39] fix some rescan functionality

---
 lib/services/coins/tezos/tezos_wallet.dart | 180 ++++++++++++++++-----
 1 file changed, 141 insertions(+), 39 deletions(-)

diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart
index bf0a8cf5d..6e128478e 100644
--- a/lib/services/coins/tezos/tezos_wallet.dart
+++ b/lib/services/coins/tezos/tezos_wallet.dart
@@ -275,13 +275,6 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
     );
   }
 
-  @override
-  Future<void> fullRescan(
-      int maxUnusedAddressGap, int maxNumberOfIndexesToCheck) {
-    refresh();
-    return Future.value();
-  }
-
   @override
   Future<bool> generateNewAddress() {
     // TODO: implement generateNewAddress
@@ -321,11 +314,11 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
     final address = Address(
       walletId: walletId,
       value: newKeystore.address,
-      publicKey: [], // TODO: Add public key
+      publicKey: [],
       derivationIndex: 0,
       derivationPath: null,
       type: AddressType.unknown,
-      subType: AddressSubType.unknown,
+      subType: AddressSubType.receiving,
     );
 
     await db.putAddress(address);
@@ -369,40 +362,131 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
   Future<String?> get mnemonicString =>
       _secureStore.read(key: '${_walletId}_mnemonic');
 
-  @override
-  Future<void> recoverFromMnemonic(
-      {required String mnemonic,
-      String? mnemonicPassphrase,
-      required int maxUnusedAddressGap,
-      required int maxNumberOfIndexesToCheck,
-      required int height}) async {
-    if ((await mnemonicString) != null ||
-        (await this.mnemonicPassphrase) != null) {
-      throw Exception("Attempted to overwrite mnemonic on restore!");
-    }
-    await _secureStore.write(
-        key: '${_walletId}_mnemonic', value: mnemonic.trim());
-    await _secureStore.write(
-      key: '${_walletId}_mnemonicPassphrase',
-      value: mnemonicPassphrase ?? "",
+  Future<void> _recoverWalletFromSeedPhrase({
+    required String mnemonic,
+    required String mnemonicPassphrase,
+    bool isRescan = false,
+  }) async {
+    final keystore = Keystore.fromMnemonic(
+      mnemonic,
+      password: mnemonicPassphrase,
     );
 
     final address = Address(
       walletId: walletId,
-      value: Keystore.fromMnemonic(mnemonic).address,
-      publicKey: [], // TODO: Add public key
+      value: keystore.address,
+      publicKey: [],
       derivationIndex: 0,
       derivationPath: null,
       type: AddressType.unknown,
-      subType: AddressSubType.unknown,
+      subType: AddressSubType.receiving,
     );
 
-    await db.putAddress(address);
+    if (isRescan) {
+      await db.updateOrPutAddresses([address]);
+    } else {
+      await db.putAddress(address);
+    }
+  }
 
-    await Future.wait([
-      updateCachedId(walletId),
-      updateCachedIsFavorite(false),
-    ]);
+  bool longMutex = false;
+  @override
+  Future<void> fullRescan(
+    int maxUnusedAddressGap,
+    int maxNumberOfIndexesToCheck,
+  ) async {
+    try {
+      Logging.instance.log("Starting full rescan!", level: LogLevel.Info);
+      longMutex = true;
+      GlobalEventBus.instance.fire(
+        WalletSyncStatusChangedEvent(
+          WalletSyncStatus.syncing,
+          walletId,
+          coin,
+        ),
+      );
+
+      final _mnemonic = await mnemonicString;
+      final _mnemonicPassphrase = await mnemonicPassphrase;
+
+      await db.deleteWalletBlockchainData(walletId);
+
+      await _recoverWalletFromSeedPhrase(
+        mnemonic: _mnemonic!,
+        mnemonicPassphrase: _mnemonicPassphrase!,
+        isRescan: true,
+      );
+
+      await refresh();
+      Logging.instance.log("Full rescan complete!", level: LogLevel.Info);
+      GlobalEventBus.instance.fire(
+        WalletSyncStatusChangedEvent(
+          WalletSyncStatus.synced,
+          walletId,
+          coin,
+        ),
+      );
+    } catch (e, s) {
+      GlobalEventBus.instance.fire(
+        WalletSyncStatusChangedEvent(
+          WalletSyncStatus.unableToSync,
+          walletId,
+          coin,
+        ),
+      );
+
+      Logging.instance.log(
+        "Exception rethrown from fullRescan(): $e\n$s",
+        level: LogLevel.Error,
+      );
+      rethrow;
+    } finally {
+      longMutex = false;
+    }
+  }
+
+  @override
+  Future<void> recoverFromMnemonic({
+    required String mnemonic,
+    String? mnemonicPassphrase,
+    required int maxUnusedAddressGap,
+    required int maxNumberOfIndexesToCheck,
+    required int height,
+  }) async {
+    longMutex = true;
+    try {
+      if ((await mnemonicString) != null ||
+          (await this.mnemonicPassphrase) != null) {
+        throw Exception("Attempted to overwrite mnemonic on restore!");
+      }
+      await _secureStore.write(
+          key: '${_walletId}_mnemonic', value: mnemonic.trim());
+      await _secureStore.write(
+        key: '${_walletId}_mnemonicPassphrase',
+        value: mnemonicPassphrase ?? "",
+      );
+
+      await _recoverWalletFromSeedPhrase(
+        mnemonic: mnemonic,
+        mnemonicPassphrase: mnemonicPassphrase ?? "",
+        isRescan: false,
+      );
+
+      await Future.wait([
+        updateCachedId(walletId),
+        updateCachedIsFavorite(false),
+      ]);
+
+      await refresh();
+    } catch (e, s) {
+      Logging.instance.log(
+          "Exception rethrown from recoverFromMnemonic(): $e\n$s",
+          level: LogLevel.Error);
+
+      rethrow;
+    } finally {
+      longMutex = false;
+    }
   }
 
   Future<void> updateBalance() async {
@@ -438,10 +522,17 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
     for (var tx in response as List) {
       if (tx["type"] == "transaction") {
         TransactionType txType;
-        if (tx["sender"]["address"] == (await currentReceivingAddress)) {
+        final String myAddress = await currentReceivingAddress;
+        final String senderAddress = tx["sender"]["address"] as String;
+        final String targetAddress = tx["target"]["address"] as String;
+        if (senderAddress == myAddress && targetAddress == myAddress) {
+          txType = TransactionType.sentToSelf;
+        } else if (senderAddress == myAddress) {
           txType = TransactionType.outgoing;
-        } else {
+        } else if (targetAddress == myAddress) {
           txType = TransactionType.incoming;
+        } else {
+          txType = TransactionType.unknown;
         }
 
         var theTx = Transaction(
@@ -470,14 +561,25 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
           nonce: 0,
           numberOfMessages: null,
         );
-        var theAddress = Address(
+        final AddressSubType subType;
+        switch (txType) {
+          case TransactionType.incoming:
+          case TransactionType.sentToSelf:
+            subType = AddressSubType.receiving;
+            break;
+          case TransactionType.outgoing:
+          case TransactionType.unknown:
+            subType = AddressSubType.unknown;
+            break;
+        }
+        final theAddress = Address(
           walletId: walletId,
-          value: tx["target"]["address"].toString(),
-          publicKey: [], // TODO: Add public key
+          value: targetAddress,
+          publicKey: [],
           derivationIndex: 0,
           derivationPath: null,
           type: AddressType.unknown,
-          subType: AddressSubType.unknown,
+          subType: subType,
         );
         txs.add(Tuple2(theTx, theAddress));
       }

From 5b4e4c49037d9240134c5931ae3a9af67f9db544 Mon Sep 17 00:00:00 2001
From: julian <julian@cypherstack.com>
Date: Wed, 23 Aug 2023 15:05:16 -0600
Subject: [PATCH 38/39] fix price tests to include tezos

---
 test/price_test.dart | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/test/price_test.dart b/test/price_test.dart
index 6741d5445..e5383bef8 100644
--- a/test/price_test.dart
+++ b/test/price_test.dart
@@ -28,7 +28,8 @@ void main() {
         Uri.parse(
             "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids"
             "=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin,bitcoin-cash"
-            ",namecoin,wownero,ethereum,particl,nano,banano,stellar&order=market_cap_desc&per_page=50"
+            ",namecoin,wownero,ethereum,particl,nano,banano,stellar,tezos"
+            "&order=market_cap_desc&per_page=50"
             "&page=1&sparkline=false"),
         headers: {
           'Content-Type': 'application/json'
@@ -114,6 +115,7 @@ void main() {
       'Coin.nano: [0, 0.0], '
       'Coin.particl: [0, 0.0], '
       'Coin.stellar: [0, 0.0], '
+      'Coin.tezos: [0, 0.0], '
       'Coin.wownero: [0, 0.0], '
       'Coin.bitcoinTestNet: [0, 0.0], '
       'Coin.bitcoincashTestnet: [0, 0.0], '
@@ -128,6 +130,7 @@ void main() {
           "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc"
           "&ids=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin,"
           "bitcoin-cash,namecoin,wownero,ethereum,particl,nano,banano,stellar"
+          ",tezos"
           "&order=market_cap_desc&per_page=50&page=1&sparkline=false",
         ),
         headers: {'Content-Type': 'application/json'})).called(1);
@@ -143,6 +146,7 @@ void main() {
             "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&"
             "ids=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin,"
             "bitcoin-cash,namecoin,wownero,ethereum,particl,nano,banano,stellar"
+            ",tezos"
             "&order=market_cap_desc&per_page=50&page=1&sparkline=false"),
         headers: {
           'Content-Type': 'application/json'
@@ -228,7 +232,10 @@ void main() {
       'Coin.firo: [0.0001096, -0.89304], '
       'Coin.litecoin: [0, 0.0], '
       'Coin.namecoin: [0, 0.0], '
-      'Coin.nano: [0, 0.0], Coin.particl: [0, 0.0], Coin.stellar: [0, 0.0], '
+      'Coin.nano: [0, 0.0], '
+      'Coin.particl: [0, 0.0], '
+      'Coin.stellar: [0, 0.0], '
+      'Coin.tezos: [0, 0.0], '
       'Coin.wownero: [0, 0.0], '
       'Coin.bitcoinTestNet: [0, 0.0], '
       'Coin.bitcoincashTestnet: [0, 0.0], Coin.dogecoinTestNet: [0, 0.0], '
@@ -244,6 +251,7 @@ void main() {
             "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids"
             "=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin,"
             "bitcoin-cash,namecoin,wownero,ethereum,particl,nano,banano,stellar"
+            ",tezos"
             "&order=market_cap_desc&per_page=50&page=1&sparkline=false"),
         headers: {'Content-Type': 'application/json'})).called(1);
 
@@ -258,6 +266,7 @@ void main() {
             "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc"
             "&ids=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin,"
             "bitcoin-cash,namecoin,wownero,ethereum,particl,nano,banano,stellar"
+            ",tezos"
             "&order=market_cap_desc&per_page=50&page=1&sparkline=false"),
         headers: {
           'Content-Type': 'application/json'
@@ -343,6 +352,7 @@ void main() {
       'Coin.nano: [0, 0.0], '
       'Coin.particl: [0, 0.0], '
       'Coin.stellar: [0, 0.0], '
+      'Coin.tezos: [0, 0.0], '
       'Coin.wownero: [0, 0.0], '
       'Coin.bitcoinTestNet: [0, 0.0], '
       'Coin.bitcoincashTestnet: [0, 0.0], '
@@ -362,6 +372,7 @@ void main() {
             "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc"
             "&ids=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin,"
             "bitcoin-cash,namecoin,wownero,ethereum,particl,nano,banano,stellar"
+            ",tezos"
             "&order=market_cap_desc&per_page=50&page=1&sparkline=false"),
         headers: {
           'Content-Type': 'application/json'
@@ -390,6 +401,7 @@ void main() {
       'Coin.nano: [0, 0.0], '
       'Coin.particl: [0, 0.0], '
       'Coin.stellar: [0, 0.0], '
+      'Coin.tezos: [0, 0.0], '
       'Coin.wownero: [0, 0.0], '
       'Coin.bitcoinTestNet: [0, 0.0], '
       'Coin.bitcoincashTestnet: [0, 0.0], '

From 0c481f2e492eab0e687732bf8967c10a84743d93 Mon Sep 17 00:00:00 2001
From: likho <likhojiba@gmail.com>
Date: Thu, 24 Aug 2023 11:30:04 +0200
Subject: [PATCH 39/39] Remove new address button for xtz and xlm

---
 lib/pages/receive_view/receive_view.dart               | 10 ++++++++--
 .../wallet_view/sub_widgets/desktop_receive.dart       | 10 ++++++++--
 2 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/lib/pages/receive_view/receive_view.dart b/lib/pages/receive_view/receive_view.dart
index d77e0e244..480813fc9 100644
--- a/lib/pages/receive_view/receive_view.dart
+++ b/lib/pages/receive_view/receive_view.dart
@@ -307,14 +307,20 @@ class _ReceiveViewState extends ConsumerState<ReceiveView> {
                   if (coin != Coin.epicCash &&
                       coin != Coin.ethereum &&
                       coin != Coin.banano &&
-                      coin != Coin.nano)
+                      coin != Coin.nano &&
+                      coin != Coin.stellar &&
+                      coin != Coin.stellarTestnet &&
+                      coin != Coin.tezos)
                     const SizedBox(
                       height: 12,
                     ),
                   if (coin != Coin.epicCash &&
                       coin != Coin.ethereum &&
                       coin != Coin.banano &&
-                      coin != Coin.nano)
+                      coin != Coin.nano &&
+                      coin != Coin.stellar &&
+                      coin != Coin.stellarTestnet &&
+                      coin != Coin.tezos)
                     TextButton(
                       onPressed: generateNewAddress,
                       style: Theme.of(context)
diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_receive.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_receive.dart
index 292517699..22da0f217 100644
--- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_receive.dart
+++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_receive.dart
@@ -219,14 +219,20 @@ class _DesktopReceiveState extends ConsumerState<DesktopReceive> {
         if (coin != Coin.epicCash &&
             coin != Coin.ethereum &&
             coin != Coin.banano &&
-            coin != Coin.nano)
+            coin != Coin.nano &&
+            coin != Coin.stellar &&
+            coin != Coin.stellarTestnet &&
+            coin != Coin.tezos)
           const SizedBox(
             height: 20,
           ),
         if (coin != Coin.epicCash &&
             coin != Coin.ethereum &&
             coin != Coin.banano &&
-            coin != Coin.nano)
+            coin != Coin.nano &&
+            coin != Coin.stellar &&
+            coin != Coin.stellarTestnet &&
+            coin != Coin.tezos)
           SecondaryButton(
             buttonHeight: ButtonHeight.l,
             onPressed: generateNewAddress,