diff --git a/README.md b/README.md
index 458002037..7c996db04 100644
--- a/README.md
+++ b/README.md
@@ -1,18 +1,29 @@
 [![codecov](https://codecov.io/gh/cypherstack/stack_wallet/branch/main/graph/badge.svg?token=PM1N56UTEW)](https://codecov.io/gh/cypherstack/stack_wallet)
 
 # Stack Wallet
-put details here
+Stack Wallet is a fully open source cryptocurrency wallet. With an easy to use user interface and quick and speedy transactions, this wallet is ideal for anyone no matter how much they know about the cryptocurrency space. The app is actively maintained to provide new user friendly features.
 
 [![Playstore](https://bluewallet.io/img/play-store-badge.svg)](https://play.google.com/store/apps/details?id=com.cypherstack.stackwallet)
 
 ## Feature List
-put features here
+
+Highlights include:
+- 5 Different cryptocurrencies
+- All private keys and seeds stay on device and are never shared.
+- Easy backup and restore feature to save all the information that's important to you.
+- Trading cryptocurrencies through our partners.
+- Custom address book
+- Favorite wallets with fast syncing
+- Custom Nodes.
+- Open source software.
 
 ## Build and run
 ### Prerequisites
-- Flutter 3.0.5
-- Flutter SDK Requirement (>=2.12.0, up until <3.0.0)
-- Android/iOS dev setup (Android Studio, xCode and subsequent dependencies)
+- The only OS supported for building is Ubuntu 20.04
+- A machine with at least 100 GB of Storage
+- Flutter 3.0.5 [(install manually or with git, do not install with snap)](https://docs.flutter.dev/get-started/install)
+- Dart SDK Requirement (>=2.17.0, up until <3.0.0)
+- Android setup ([Android Studio](https://developer.android.com/studio) and subsequent dependencies)
 
 After that download the project and init the submodules
 ```
@@ -21,31 +32,34 @@ cd stack_wallet
 git submodule update --init --recursive
 ```
 
+You will need to install all dependencies listed in each of the plugins in the crypto_plugins folder. (eg. [Monero](https://github.com/cypherstack/flutter_libmonero), [Epic Cash](https://github.com/cypherstack/flutter_libepiccash) ) as of Sep 8th 2022 that is:
+
+Install [Rust](https://www.rust-lang.org/tools/install)
+```
+cargo install cargo-ndk
+rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
+
+sudo apt install libc6-dev-i386
+sudo apt install build-essential cmake git libgit2-dev clang libncurses5-dev libncursesw5-dev zlib1g-dev pkg-config llvm 
+sudo apt install build-essential debhelper cmake libclang-dev libncurses5-dev clang libncursesw5-dev cargo rustc opencl-headers libssl-dev pkg-config ocl-icd-opencl-dev
+sudo apt install unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake openjdk-8-jre-headless
+```
+
 Building plugins for Android
 ```
-cd crypto_plugins/flutter_liblelantus/scripts/android/
-// note if you are on a mac go one directory further to android_on_mac
+cd scripts/android/
 ./build_all.sh
 // when finished go back to the root directory
-cd ../../../..
-```
-
-Building plugins for IOS
-
-```
-cd crypto_plugins/flutter_liblelantus/scripts/ios/
-./build_all.sh
-// when finished go back to the root directory
-cd ../../../..
+cd ../..
 ```
 
 Building plugins for testing on Linux
 
 ```
-cd crypto_plugins/flutter_liblelantus/scripts/linux/
+cd scripts/linux/
 ./build_all.sh
 // when finished go back to the root directory
-cd ../../../..
+cd ../..
 ```
 
 Finally, plug in your android device or use the emulator available via Android Studio and then run the following commands:
@@ -53,3 +67,5 @@ Finally, plug in your android device or use the emulator available via Android S
 flutter pub get
 flutter run
 ```
+
+Note on Emulators: Only x86_64 emulators are supported, x86 emulators will not work
diff --git a/assets/svg/share-2.svg b/assets/svg/share-2.svg
new file mode 100644
index 000000000..d002d2bff
--- /dev/null
+++ b/assets/svg/share-2.svg
@@ -0,0 +1,14 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_5024_11503)">
+<path d="M9 4C9.82843 4 10.5 3.32843 10.5 2.5C10.5 1.67157 9.82843 1 9 1C8.17157 1 7.5 1.67157 7.5 2.5C7.5 3.32843 8.17157 4 9 4Z" fill="white" stroke="#111111" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M3 7.5C3.82843 7.5 4.5 6.82843 4.5 6C4.5 5.17157 3.82843 4.5 3 4.5C2.17157 4.5 1.5 5.17157 1.5 6C1.5 6.82843 2.17157 7.5 3 7.5Z" stroke="#111111" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M9 11C9.82843 11 10.5 10.3284 10.5 9.5C10.5 8.67157 9.82843 8 9 8C8.17157 8 7.5 8.67157 7.5 9.5C7.5 10.3284 8.17157 11 9 11Z" stroke="#111111" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M4.29504 6.75488L7.71004 8.74488" stroke="#111111" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M7.70504 3.25488L4.29504 5.24488" stroke="#111111" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_5024_11503">
+<rect width="12" height="12" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/assets/svg/tx-icon-anonymize-failed.svg b/assets/svg/tx-icon-anonymize-failed.svg
new file mode 100644
index 000000000..4a225f36e
--- /dev/null
+++ b/assets/svg/tx-icon-anonymize-failed.svg
@@ -0,0 +1,13 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M23.0154 16.7681C23.6489 15.3066 24 13.6943 24 12C24 5.37258 18.6274 0 12 0C5.37258 0 0 5.37258 0 12C0 18.6274 5.37258 24 12 24C13.6943 24 15.3066 23.6489 16.7681 23.0154C16.2832 22.2973 16 21.4317 16 20.5C16 18.0147 18.0147 16 20.5 16C21.4317 16 22.2973 16.2832 23.0154 16.7681Z" fill="#E0E3E3"/>
+<g clip-path="url(#clip0_5035_57298)">
+<path d="M10.0169 11.6619C10.1425 12.2062 9.54581 12.6328 9.0721 12.3345L8.43612 11.9367L7.10397 14.0678C6.7551 14.6258 7.15642 15.3497 7.81454 15.3497H8.65256C9.11423 15.3497 9.48954 15.7245 9.48954 16.1862C9.48954 16.6479 9.11423 17.025 8.65256 17.025H7.81716C5.84484 17.025 4.64251 14.8569 5.68493 13.183L7.01525 11.0521L6.3777 10.6516C5.90373 10.3533 6.02464 9.63093 6.56954 9.5053L8.96244 8.95177C9.18725 8.90335 9.41495 9.03944 9.46729 9.26714L10.0169 11.6619ZM12.71 7.36601L13.7896 9.09702L13.1549 9.49169C12.6796 9.7877 12.7998 10.5108 13.3454 10.6372L15.7375 11.1908C15.9632 11.243 16.1884 11.1021 16.2403 10.8764L16.7909 8.48355C16.9163 7.93892 16.3211 7.51389 15.8469 7.80937L15.2093 8.20718L14.1311 6.48088C13.1476 4.90691 10.8544 4.90586 9.87034 6.47927L9.67667 6.78866C9.43327 7.17732 9.55366 7.6963 9.941 7.94023C10.3315 8.18517 10.851 8.0681 11.0954 7.67746L11.2902 7.36628C11.6239 6.83263 12.3907 6.85226 12.71 7.36601ZM18.316 13.1851L17.8713 12.4716C17.627 12.0796 17.1108 11.9597 16.7187 12.2044C16.3277 12.4483 16.2079 12.9673 16.4523 13.3581L16.897 14.0686C17.2464 14.6266 16.845 15.3511 16.1867 15.3511H13.6744L13.675 14.5989C13.675 14.0393 12.9985 13.759 12.6028 14.1547L10.8647 15.8933C10.7019 16.0562 10.7019 16.3228 10.8648 16.4856L12.6031 18.2218C12.9989 18.617 13.6749 18.3366 13.6749 17.7774L13.6743 17.0268H16.1831C18.1564 17.0271 19.3603 14.8575 18.316 13.1851Z" fill="#494949"/>
+</g>
+<circle cx="20.5" cy="20.5" r="3.5" fill="#C00205"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M19.1465 21.2072C18.9512 21.4025 18.9512 21.7191 19.1465 21.9143C19.3418 22.1096 19.6583 22.1096 19.8536 21.9143L20.5293 21.2386L21.2054 21.9146C21.4007 22.1099 21.7172 22.1099 21.9125 21.9146C22.1078 21.7194 22.1078 21.4028 21.9125 21.2075L21.2365 20.5315L21.9749 19.793C22.1702 19.5977 22.1702 19.2812 21.9749 19.0859C21.7797 18.8906 21.4631 18.8906 21.2678 19.0859L20.5293 19.8244L19.7912 19.0862C19.5959 18.8909 19.2793 18.8909 19.0841 19.0862C18.8888 19.2815 18.8888 19.598 19.0841 19.7933L19.8222 20.5315L19.1465 21.2072Z" fill="white"/>
+<defs>
+<clipPath id="clip0_5035_57298">
+<rect width="13.4" height="13.4" fill="white" transform="translate(5.30078 5.2998)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/assets/svg/tx-icon-anonymize-pending.svg b/assets/svg/tx-icon-anonymize-pending.svg
new file mode 100644
index 000000000..48125ec85
--- /dev/null
+++ b/assets/svg/tx-icon-anonymize-pending.svg
@@ -0,0 +1,13 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M23.0154 16.7681C23.6489 15.3066 24 13.6943 24 12C24 5.37258 18.6274 0 12 0C5.37258 0 0 5.37258 0 12C0 18.6274 5.37258 24 12 24C13.6943 24 15.3066 23.6489 16.7681 23.0154C16.2832 22.2973 16 21.4317 16 20.5C16 18.0147 18.0147 16 20.5 16C21.4317 16 22.2973 16.2832 23.0154 16.7681Z" fill="#E0E3E3"/>
+<circle cx="20.5" cy="20.5" r="3.5" fill="#F4C517"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M20.5 18.5C20.7761 18.5 21 18.7239 21 19V20H21.5C21.7761 20 22 20.2239 22 20.5C22 20.7761 21.7761 21 21.5 21H20.5C20.2239 21 20 20.7761 20 20.5V19C20 18.7239 20.2239 18.5 20.5 18.5Z" fill="white"/>
+<g clip-path="url(#clip0_5035_57297)">
+<path d="M10.0169 11.6619C10.1425 12.2062 9.54581 12.6328 9.0721 12.3345L8.43612 11.9367L7.10397 14.0678C6.7551 14.6258 7.15642 15.3497 7.81454 15.3497H8.65256C9.11423 15.3497 9.48954 15.7245 9.48954 16.1862C9.48954 16.6479 9.11423 17.025 8.65256 17.025H7.81716C5.84484 17.025 4.64251 14.8569 5.68493 13.183L7.01525 11.0521L6.3777 10.6516C5.90373 10.3533 6.02464 9.63093 6.56954 9.5053L8.96244 8.95177C9.18725 8.90335 9.41495 9.03944 9.46729 9.26714L10.0169 11.6619ZM12.71 7.36601L13.7896 9.09702L13.1549 9.49169C12.6796 9.7877 12.7998 10.5108 13.3454 10.6372L15.7375 11.1908C15.9632 11.243 16.1884 11.1021 16.2403 10.8764L16.7909 8.48355C16.9163 7.93892 16.3211 7.51389 15.8469 7.80937L15.2093 8.20718L14.1311 6.48088C13.1476 4.90691 10.8544 4.90586 9.87034 6.47927L9.67667 6.78866C9.43327 7.17732 9.55366 7.6963 9.941 7.94023C10.3315 8.18517 10.851 8.0681 11.0954 7.67746L11.2902 7.36628C11.6239 6.83263 12.3907 6.85226 12.71 7.36601ZM18.316 13.1851L17.8713 12.4716C17.627 12.0796 17.1108 11.9597 16.7187 12.2044C16.3277 12.4483 16.2079 12.9673 16.4523 13.3581L16.897 14.0686C17.2464 14.6266 16.845 15.3511 16.1867 15.3511H13.6744L13.675 14.5989C13.675 14.0393 12.9985 13.759 12.6028 14.1547L10.8647 15.8933C10.7019 16.0562 10.7019 16.3228 10.8648 16.4856L12.6031 18.2218C12.9989 18.617 13.6749 18.3366 13.6749 17.7774L13.6743 17.0268H16.1831C18.1564 17.0271 19.3603 14.8575 18.316 13.1851Z" fill="#494949"/>
+</g>
+<defs>
+<clipPath id="clip0_5035_57297">
+<rect width="13.4" height="13.4" fill="white" transform="translate(5.30078 5.2998)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/assets/svg/tx-icon-anonymize.svg b/assets/svg/tx-icon-anonymize.svg
new file mode 100644
index 000000000..8f8acd695
--- /dev/null
+++ b/assets/svg/tx-icon-anonymize.svg
@@ -0,0 +1,16 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_5035_57299)">
+<circle cx="12" cy="12" r="12" fill="#E0E3E3"/>
+<g clip-path="url(#clip1_5035_57299)">
+<path d="M9.92728 11.6469C10.0585 12.2157 9.4351 12.6614 8.94018 12.3497L8.27572 11.934L6.88393 14.1606C6.51943 14.7436 6.93872 15.4999 7.62631 15.4999H8.50185C8.9842 15.4999 9.37631 15.8915 9.37631 16.3738C9.37631 16.8562 8.9842 17.2502 8.50185 17.2502H7.62904C5.56842 17.2502 4.31225 14.9851 5.40135 13.2361L6.79123 11.0098L6.12514 10.5915C5.62994 10.2797 5.75627 9.52505 6.32557 9.3938L8.8256 8.81548C9.06049 8.7649 9.29838 8.90709 9.35307 9.14498L9.92728 11.6469ZM12.741 7.15873L13.8689 8.96724L13.2058 9.37959C12.7092 9.68884 12.8347 10.4444 13.4048 10.5764L15.904 11.1547C16.1398 11.2093 16.3752 11.0621 16.4293 10.8263L17.0046 8.32631C17.1356 7.75728 16.5138 7.31322 16.0183 7.62193L15.3522 8.03755L14.2257 6.23396C13.1981 4.58951 10.8023 4.58841 9.77416 6.23227L9.57182 6.55552C9.31752 6.96158 9.4433 7.50381 9.84799 7.75865C10.256 8.01456 10.7987 7.89225 11.0541 7.48412L11.2576 7.159C11.6062 6.60146 12.4074 6.62197 12.741 7.15873ZM18.598 13.2383L18.1334 12.4929C17.8781 12.0833 17.3388 11.9581 16.9292 12.2138C16.5207 12.4686 16.3954 13.0108 16.6508 13.4191L17.1154 14.1615C17.4804 14.7444 17.0612 15.5013 16.3733 15.5013H13.7486L13.7492 14.7154C13.7492 14.1308 13.0424 13.838 12.6289 14.2514L10.813 16.0679C10.6429 16.238 10.6429 16.5166 10.8132 16.6867L12.6293 18.5006C13.0428 18.9135 13.7491 18.6206 13.7491 18.0363L13.7484 17.2521H16.3696C18.4312 17.2524 19.689 14.9856 18.598 13.2383Z" fill="#494949"/>
+</g>
+</g>
+<defs>
+<clipPath id="clip0_5035_57299">
+<rect width="24" height="24" fill="white"/>
+</clipPath>
+<clipPath id="clip1_5035_57299">
+<rect width="14" height="14" fill="white" transform="translate(5 5)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/lib/electrumx_rpc/cached_electrumx.dart b/lib/electrumx_rpc/cached_electrumx.dart
index a063ff00b..7a90c2343 100644
--- a/lib/electrumx_rpc/cached_electrumx.dart
+++ b/lib/electrumx_rpc/cached_electrumx.dart
@@ -1,5 +1,6 @@
 import 'package:stackwallet/electrumx_rpc/electrumx.dart';
 import 'package:stackwallet/hive/db.dart';
+import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
 import 'package:stackwallet/utilities/enums/coin_enum.dart';
 import 'package:stackwallet/utilities/logger.dart';
 import 'package:stackwallet/utilities/prefs.dart';
@@ -59,6 +60,20 @@ class CachedElectrumX {
           "setHash": "",
           "coins": <dynamic>[],
         };
+
+        // try up to 3 times
+        for (int i = 0; i < 3; i++) {
+          final result = await getInitialAnonymitySetCache(groupId);
+          if (result != null) {
+            set["setHash"] = result["setHash"];
+            set["blockHash"] = result["blockHash"];
+            set["coins"] = result["coins"];
+            Logging.instance.log(
+                "Populated initial anon set cache for group $groupId",
+                level: LogLevel.Info);
+            break;
+          }
+        }
       } else {
         set = Map<String, dynamic>.from(cachedSet);
       }
diff --git a/lib/hive/db.dart b/lib/hive/db.dart
index da161ce2d..3aae3096a 100644
--- a/lib/hive/db.dart
+++ b/lib/hive/db.dart
@@ -10,6 +10,8 @@ import 'package:stackwallet/models/trade_wallet_lookup.dart';
 import 'package:stackwallet/services/wallets_service.dart';
 import 'package:stackwallet/utilities/enums/coin_enum.dart';
 
+import 'package:stackwallet/utilities/logger.dart';
+
 class DB {
   static const String boxNameAddressBook = "addressBook";
   static const String boxNameDebugInfo = "debugInfoBox";
@@ -27,6 +29,7 @@ class DB {
   static const String boxNamePrefs = "prefs";
   static const String boxNameWalletsToDeleteOnStart = "walletsToDeleteOnStart";
   static const String boxNamePriceCache = "priceAPIPrice24hCache";
+  static const String boxNameDBInfo = "dbInfo";
 
   String boxNameTxCache({required Coin coin}) => "${coin.name}_txCache";
   String boxNameSetCache({required Coin coin}) =>
@@ -50,6 +53,7 @@ class DB {
   late final Box<xmr.WalletInfo> _walletInfoSource;
   late final Box<dynamic> _boxPrefs;
   late final Box<TradeWalletLookup> _boxTradeLookup;
+  late final Box<dynamic> _boxDBInfo;
 
   final Map<String, Box<dynamic>> _walletBoxes = {};
 
@@ -80,13 +84,40 @@ class DB {
   // open hive boxes
   Future<void> init() async {
     if (!_initialized) {
+      if (Hive.isBoxOpen(boxNameDBInfo)) {
+        _boxDBInfo = Hive.box<dynamic>(boxNameDBInfo);
+      } else {
+        _boxDBInfo = await Hive.openBox<dynamic>(boxNameDBInfo);
+      }
       await Hive.openBox<String>(boxNameWalletsToDeleteOnStart);
-      _boxPrefs = await Hive.openBox<dynamic>(boxNamePrefs);
+
+      if (Hive.isBoxOpen(boxNamePrefs)) {
+        _boxPrefs = Hive.box<dynamic>(boxNamePrefs);
+      } else {
+        _boxPrefs = await Hive.openBox<dynamic>(boxNamePrefs);
+      }
+
       _boxAddressBook = await Hive.openBox<dynamic>(boxNameAddressBook);
       _boxDebugInfo = await Hive.openBox<String>(boxNameDebugInfo);
-      _boxNodeModels = await Hive.openBox<NodeModel>(boxNameNodeModels);
-      _boxPrimaryNodes = await Hive.openBox<NodeModel>(boxNamePrimaryNodes);
-      _boxAllWalletsData = await Hive.openBox<dynamic>(boxNameAllWalletsData);
+
+      if (Hive.isBoxOpen(boxNameNodeModels)) {
+        _boxNodeModels = Hive.box<NodeModel>(boxNameNodeModels);
+      } else {
+        _boxNodeModels = await Hive.openBox<NodeModel>(boxNameNodeModels);
+      }
+
+      if (Hive.isBoxOpen(boxNamePrimaryNodes)) {
+        _boxPrimaryNodes = Hive.box<NodeModel>(boxNamePrimaryNodes);
+      } else {
+        _boxPrimaryNodes = await Hive.openBox<NodeModel>(boxNamePrimaryNodes);
+      }
+
+      if (Hive.isBoxOpen(boxNameAllWalletsData)) {
+        _boxAllWalletsData = Hive.box<dynamic>(boxNameAllWalletsData);
+      } else {
+        _boxAllWalletsData = await Hive.openBox<dynamic>(boxNameAllWalletsData);
+      }
+
       _boxNotifications =
           await Hive.openBox<NotificationModel>(boxNameNotifications);
       _boxWatchedTransactions =
@@ -112,12 +143,29 @@ class DB {
 
   Future<void> _loadWalletBoxes() async {
     final names = _boxAllWalletsData.get("names") as Map? ?? {};
+    names.removeWhere((name, dyn) {
+      final jsonObject = Map<String, dynamic>.from(dyn as Map);
+      try {
+        Coin.values.byName(jsonObject["coin"] as String);
+        return false;
+      } catch (e, s) {
+        Logging.instance.log(
+            "Error, ${jsonObject["coin"]} does not exist, $name wallet cannot be loaded",
+            level: LogLevel.Error);
+        return true;
+      }
+    });
     final mapped = Map<String, dynamic>.from(names).map((name, dyn) => MapEntry(
         name, WalletInfo.fromJson(Map<String, dynamic>.from(dyn as Map))));
 
     for (final entry in mapped.entries) {
-      _walletBoxes[entry.value.walletId] =
-          await Hive.openBox<dynamic>(entry.value.walletId);
+      if (Hive.isBoxOpen(entry.value.walletId)) {
+        _walletBoxes[entry.value.walletId] =
+            Hive.box<dynamic>(entry.value.walletId);
+      } else {
+        _walletBoxes[entry.value.walletId] =
+            await Hive.openBox<dynamic>(entry.value.walletId);
+      }
     }
   }
 
diff --git a/lib/main.dart b/lib/main.dart
index 5ceb47e1a..10067ac19 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -51,6 +51,7 @@ import 'package:stackwallet/services/trade_service.dart';
 import 'package:stackwallet/services/wallets.dart';
 import 'package:stackwallet/utilities/cfcolors.dart';
 import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/db_version_migration.dart';
 import 'package:stackwallet/utilities/enums/backup_frequency_type.dart';
 import 'package:stackwallet/utilities/logger.dart';
 import 'package:stackwallet/utilities/prefs.dart';
@@ -119,18 +120,16 @@ void main() async {
 
   Hive.registerAdapter(UnspentCoinsInfoAdapter());
 
+  await Hive.openBox<dynamic>(DB.boxNameDBInfo);
+  int dbVersion = DB.instance.get<dynamic>(
+          boxName: DB.boxNameDBInfo, key: "hive_data_version") as int? ??
+      0;
+  if (dbVersion < Constants.currentHiveDbVersion) {
+    await DbVersionMigrator().migrate(dbVersion);
+  }
+
   monero.onStartup();
 
-  // final wallets = await Hive.openBox('wallets');
-  // await wallets.put('currentWalletName', "");
-
-  // NOT USED YET
-  // int dbVersion = await wallets.get("db_version");
-  // if (dbVersion == null || dbVersion < Constants.currentDbVersion) {
-  //   if (dbVersion == null) dbVersion = 0;
-  //   await DbVersionMigrator().migrate(dbVersion);
-  // }
-
   // SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
   //     overlays: [SystemUiOverlay.bottom]);
   await NotificationApi.init();
@@ -344,20 +343,23 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
     _prefs = ref.read(prefsChangeNotifierProvider);
     _wallets = ref.read(walletsChangeNotifierProvider);
 
-    WidgetsBinding.instance.addPostFrameCallback((_) async {
-      // fetch open file if it exists
-      await getOpenFile();
+    if (Platform.isAndroid) {
+      WidgetsBinding.instance.addPostFrameCallback((_) async {
+        // fetch open file if it exists
+        await getOpenFile();
 
-      if (ref.read(openedFromSWBFileStringStateProvider.state).state != null) {
-        // waiting for loading to complete before going straight to restore if the app was opened via file
-        await loadingCompleter.future;
+        if (ref.read(openedFromSWBFileStringStateProvider.state).state !=
+            null) {
+          // waiting for loading to complete before going straight to restore if the app was opened via file
+          await loadingCompleter.future;
 
-        await goToRestoreSWB(
-            ref.read(openedFromSWBFileStringStateProvider.state).state!);
-        ref.read(openedFromSWBFileStringStateProvider.state).state = null;
-      }
-      // ref.read(shouldShowLockscreenOnResumeStateProvider.state).state = false;
-    });
+          await goToRestoreSWB(
+              ref.read(openedFromSWBFileStringStateProvider.state).state!);
+          ref.read(openedFromSWBFileStringStateProvider.state).state = null;
+        }
+        // ref.read(shouldShowLockscreenOnResumeStateProvider.state).state = false;
+      });
+    }
 
     super.initState();
   }
@@ -378,14 +380,16 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
       case AppLifecycleState.paused:
         break;
       case AppLifecycleState.resumed:
-        // fetch open file if it exists
-        await getOpenFile();
-        // go straight to restore if the app was resumed via file
-        if (ref.read(openedFromSWBFileStringStateProvider.state).state !=
-            null) {
-          await goToRestoreSWB(
-              ref.read(openedFromSWBFileStringStateProvider.state).state!);
-          ref.read(openedFromSWBFileStringStateProvider.state).state = null;
+        if (Platform.isAndroid) {
+          // fetch open file if it exists
+          await getOpenFile();
+          // go straight to restore if the app was resumed via file
+          if (ref.read(openedFromSWBFileStringStateProvider.state).state !=
+              null) {
+            await goToRestoreSWB(
+                ref.read(openedFromSWBFileStringStateProvider.state).state!);
+            ref.read(openedFromSWBFileStringStateProvider.state).state = null;
+          }
         }
         // if (ref.read(hasAuthenticatedOnStartStateProvider.state).state &&
         //     ref.read(shouldShowLockscreenOnResumeStateProvider.state).state) {
@@ -419,6 +423,7 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
     }
   }
 
+  /// should only be called on android currently
   Future<void> getOpenFile() async {
     // update provider with new file content state
     ref.read(openedFromSWBFileStringStateProvider.state).state =
@@ -432,6 +437,7 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
         level: LogLevel.Info);
   }
 
+  /// should only be called on android currently
   Future<void> resetOpenPath() async {
     await platform.invokeMethod("resetOpenPath");
   }
diff --git a/lib/models/exchange/change_now/cn_exchange_estimate.dart b/lib/models/exchange/change_now/cn_exchange_estimate.dart
new file mode 100644
index 000000000..d20606865
--- /dev/null
+++ b/lib/models/exchange/change_now/cn_exchange_estimate.dart
@@ -0,0 +1,163 @@
+import 'package:decimal/decimal.dart';
+import 'package:stackwallet/utilities/logger.dart';
+
+enum CNEstimateType { direct, reverse }
+
+enum CNFlowType implements Comparable<CNFlowType> {
+  standard("standard"),
+  fixedRate("fixed-rate");
+
+  const CNFlowType(this.value);
+
+  final String value;
+
+  @override
+  int compareTo(CNFlowType other) => value.compareTo(other.value);
+}
+
+class CNExchangeEstimate {
+  /// Ticker of the currency you want to exchange
+  final String fromCurrency;
+
+  /// Network of the currency you want to exchange
+  final String fromNetwork;
+
+  /// Ticker of the currency you want to receive
+  final String toCurrency;
+
+  /// Network of the currency you want to receive
+  final String toNetwork;
+
+  /// Type of exchange flow. Enum: ["standard", "fixed-rate"]
+  final CNFlowType flow;
+
+  /// Direction of exchange flow. Use "direct" value to set amount for
+  /// currencyFrom and get amount of currencyTo. Use "reverse" value to set
+  /// amount for currencyTo and get amount of currencyFrom.
+  /// Enum: ["direct", "reverse"]
+  final CNEstimateType type;
+
+  /// (Optional) Use rateId for fixed-rate flow. If this field is true, you
+  /// could use returned field "rateId" in next method for creating transaction
+  /// to freeze estimated amount that you got in this method. Current estimated
+  /// amount would be valid until time in field "validUntil"
+  final String? rateId;
+
+  /// Date and time before estimated amount would be freezed in case of using
+  /// rateId. If you set param "useRateId" to true, you could use returned field
+  /// "rateId" in next method for creating transaction to freeze estimated
+  /// amount that you got in this method. Estimated amount would be valid until
+  /// this date and time
+  final String? validUntil;
+
+  /// Dash-separated min and max estimated time in minutes
+  final String? transactionSpeedForecast;
+
+  /// Some warnings like warnings that transactions on this network
+  /// take longer or that the currency has moved to another network
+  final String? warningMessage;
+
+  /// Exchange amount of fromCurrency (in case when type=reverse it is an
+  /// estimated value)
+  final Decimal fromAmount;
+
+  /// Exchange amount of toCurrency (in case when type=direct it is an
+  /// estimated value)
+  final Decimal toAmount;
+
+  CNExchangeEstimate({
+    required this.fromCurrency,
+    required this.fromNetwork,
+    required this.toCurrency,
+    required this.toNetwork,
+    required this.flow,
+    required this.type,
+    this.rateId,
+    this.validUntil,
+    this.transactionSpeedForecast,
+    this.warningMessage,
+    required this.fromAmount,
+    required this.toAmount,
+  });
+
+  factory CNExchangeEstimate.fromJson(Map<String, dynamic> json) {
+    try {
+      final flow = CNFlowType.values
+          .firstWhere((element) => element.value == json["flow"]);
+      final type = CNEstimateType.values
+          .firstWhere((element) => element.name == json["type"]);
+
+      return CNExchangeEstimate(
+        fromCurrency: json["fromCurrency"] as String,
+        fromNetwork: json["fromNetwork"] as String,
+        toCurrency: json["toCurrency"] as String,
+        toNetwork: json["toNetwork"] as String,
+        flow: flow,
+        type: type,
+        rateId: json["rateId"] as String?,
+        validUntil: json["validUntil"] as String?,
+        transactionSpeedForecast: json["transactionSpeedForecast"] as String?,
+        warningMessage: json["warningMessage"] as String?,
+        fromAmount: Decimal.parse(json["fromAmount"].toString()),
+        toAmount: Decimal.parse(json["toAmount"].toString()),
+      );
+    } catch (e, s) {
+      Logging.instance
+          .log("Failed to parse: $json \n$e\n$s", level: LogLevel.Fatal);
+      rethrow;
+    }
+  }
+
+  Map<String, dynamic> toJson() {
+    return {
+      "fromCurrency": fromCurrency,
+      "fromNetwork": fromNetwork,
+      "toCurrency": toCurrency,
+      "toNetwork": toNetwork,
+      "flow": flow,
+      "type": type,
+      "rateId": rateId,
+      "validUntil": validUntil,
+      "transactionSpeedForecast": transactionSpeedForecast,
+      "warningMessage": warningMessage,
+      "fromAmount": fromAmount,
+      "toAmount": toAmount,
+    };
+  }
+
+  CNExchangeEstimate copyWith({
+    String? fromCurrency,
+    String? fromNetwork,
+    String? toCurrency,
+    String? toNetwork,
+    CNFlowType? flow,
+    CNEstimateType? type,
+    String? rateId,
+    String? validUntil,
+    String? transactionSpeedForecast,
+    String? warningMessage,
+    Decimal? fromAmount,
+    Decimal? toAmount,
+  }) {
+    return CNExchangeEstimate(
+      fromCurrency: fromCurrency ?? this.fromCurrency,
+      fromNetwork: fromNetwork ?? this.fromNetwork,
+      toCurrency: toCurrency ?? this.toCurrency,
+      toNetwork: toNetwork ?? this.toNetwork,
+      flow: flow ?? this.flow,
+      type: type ?? this.type,
+      rateId: rateId ?? this.rateId,
+      validUntil: validUntil ?? this.validUntil,
+      transactionSpeedForecast:
+          transactionSpeedForecast ?? this.transactionSpeedForecast,
+      warningMessage: warningMessage ?? this.warningMessage,
+      fromAmount: fromAmount ?? this.fromAmount,
+      toAmount: toAmount ?? this.toAmount,
+    );
+  }
+
+  @override
+  String toString() {
+    return "EstimatedExchangeAmount: ${toJson()}";
+  }
+}
diff --git a/lib/models/exchange/estimated_rate_exchange_form_state.dart b/lib/models/exchange/estimated_rate_exchange_form_state.dart
index 210df8c95..3161d83c1 100644
--- a/lib/models/exchange/estimated_rate_exchange_form_state.dart
+++ b/lib/models/exchange/estimated_rate_exchange_form_state.dart
@@ -1,10 +1,14 @@
 import 'package:decimal/decimal.dart';
 import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
 import 'package:stackwallet/models/exchange/change_now/currency.dart';
 import 'package:stackwallet/services/change_now/change_now.dart';
 import 'package:stackwallet/utilities/logger.dart';
 
 class EstimatedRateExchangeFormState extends ChangeNotifier {
+  /// used in testing to inject mock
+  ChangeNow? cnTesting;
+
   Decimal? _fromAmount;
   Decimal? _toAmount;
 
@@ -16,9 +20,43 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
   Currency? _from;
   Currency? _to;
 
+  void Function(String)? _onError;
+
   Currency? get from => _from;
   Currency? get to => _to;
 
+  String get fromAmountString =>
+      _fromAmount == null ? "" : _fromAmount!.toStringAsFixed(8);
+  String get toAmountString =>
+      _toAmount == null ? "" : _toAmount!.toStringAsFixed(8);
+
+  String get rateDisplayString {
+    if (rate == null || from == null || to == null) {
+      return "N/A";
+    } else {
+      return "1 ${from!.ticker.toUpperCase()} ~${rate!.toStringAsFixed(8)} ${to!.ticker.toUpperCase()}";
+    }
+  }
+
+  bool get canExchange {
+    return _fromAmount != null &&
+        _fromAmount != Decimal.zero &&
+        _toAmount != null &&
+        rate != null &&
+        minimumSendWarning.isEmpty;
+  }
+
+  String get minimumSendWarning {
+    if (_from != null &&
+        _fromAmount != null &&
+        _minFromAmount != null &&
+        _fromAmount! < _minFromAmount!) {
+      return "Minimum amount ${_minFromAmount!.toString()} ${from!.ticker.toUpperCase()}";
+    }
+
+    return "";
+  }
+
   Future<void> init(Currency? from, Currency? to) async {
     _from = from;
     _to = to;
@@ -43,10 +81,6 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
     final Decimal? newMinFromAmount = _minToAmount;
     final Decimal? newMinToAmount = _minFromAmount;
 
-    // final Decimal? newRate = rate == null
-    //     ? rate
-    //     : (Decimal.one / rate!).toDecimal(scaleOnInfinitePrecision: 12);
-
     final Currency? newTo = from;
     final Currency? newFrom = to;
 
@@ -63,48 +97,11 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
 
     await _updateMinFromAmount(shouldNotifyListeners: false);
 
-    rate = null;
-
-    if (_fromAmount != null) {
-      Decimal? amt;
-      if (_minFromAmount != null) {
-        if (_minFromAmount! > _fromAmount!) {
-          amt = await getStandardEstimatedToAmount(
-              fromAmount: _minFromAmount!, from: _from!, to: _to!);
-          if (amt != null) {
-            rate =
-                (amt / _minFromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
-          }
-        } else {
-          amt = await getStandardEstimatedToAmount(
-              fromAmount: _fromAmount!, from: _from!, to: _to!);
-          if (amt != null) {
-            rate = (amt / _fromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
-          }
-        }
-      }
-      if (rate != null) {
-        _toAmount = (_fromAmount! * rate!);
-      }
-    } else {
-      if (_minFromAmount != null) {
-        Decimal? amt = await getStandardEstimatedToAmount(
-            fromAmount: _minFromAmount!, from: _from!, to: _to!);
-        if (amt != null) {
-          rate =
-              (amt / _minFromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
-        }
-      }
-    }
+    await updateRate();
 
     notifyListeners();
   }
 
-  String get fromAmountString =>
-      _fromAmount == null ? "" : _fromAmount!.toStringAsFixed(8);
-  String get toAmountString =>
-      _toAmount == null ? "" : _toAmount!.toStringAsFixed(8);
-
   Future<void> updateTo(Currency to, bool shouldNotifyListeners) async {
     try {
       _to = to;
@@ -115,46 +112,8 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
       }
 
       await _updateMinFromAmount(shouldNotifyListeners: shouldNotifyListeners);
-      // await _updateMinToAmount(shouldNotifyListeners: shouldNotifyListeners);
 
-      rate = null;
-
-      if (_fromAmount != null) {
-        Decimal? amt;
-        if (_minFromAmount != null) {
-          if (_minFromAmount! > _fromAmount!) {
-            amt = await getStandardEstimatedToAmount(
-                fromAmount: _minFromAmount!, from: _from!, to: _to!);
-            if (amt != null) {
-              rate = (amt / _minFromAmount!)
-                  .toDecimal(scaleOnInfinitePrecision: 12);
-            }
-            debugPrint("A");
-          } else {
-            amt = await getStandardEstimatedToAmount(
-                fromAmount: _fromAmount!, from: _from!, to: _to!);
-            if (amt != null) {
-              rate =
-                  (amt / _fromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
-            }
-            debugPrint("B");
-          }
-        }
-        if (rate != null) {
-          _toAmount = (_fromAmount! * rate!);
-        }
-        debugPrint("C");
-      } else {
-        if (_minFromAmount != null) {
-          Decimal? amt = await getStandardEstimatedToAmount(
-              fromAmount: _minFromAmount!, from: _from!, to: _to!);
-          if (amt != null) {
-            rate =
-                (amt / _minFromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
-          }
-          debugPrint("D");
-        }
-      }
+      await updateRate(shouldNotifyListeners: shouldNotifyListeners);
 
       debugPrint(
           "_updated TO: _from=${_from!.ticker} _to=${_to!.ticker} _fromAmount=$_fromAmount _toAmount=$_toAmount rate:$rate");
@@ -163,7 +122,7 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
         notifyListeners();
       }
     } catch (e, s) {
-      Logging.instance.log("$e\n$s", level: LogLevel.Fatal);
+      Logging.instance.log("$e\n$s", level: LogLevel.Error);
     }
   }
 
@@ -179,40 +138,7 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
 
       await _updateMinFromAmount(shouldNotifyListeners: shouldNotifyListeners);
 
-      rate = null;
-
-      if (_fromAmount != null) {
-        Decimal? amt;
-        if (_minFromAmount != null) {
-          if (_minFromAmount! > _fromAmount!) {
-            amt = await getStandardEstimatedToAmount(
-                fromAmount: _minFromAmount!, from: _from!, to: _to!);
-            if (amt != null) {
-              rate = (amt / _minFromAmount!)
-                  .toDecimal(scaleOnInfinitePrecision: 12);
-            }
-          } else {
-            amt = await getStandardEstimatedToAmount(
-                fromAmount: _fromAmount!, from: _from!, to: _to!);
-            if (amt != null) {
-              rate =
-                  (amt / _fromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
-            }
-          }
-        }
-        if (rate != null) {
-          _toAmount = (_fromAmount! * rate!);
-        }
-      } else {
-        if (_minFromAmount != null) {
-          Decimal? amt = await getStandardEstimatedToAmount(
-              fromAmount: _minFromAmount!, from: _from!, to: _to!);
-          if (amt != null) {
-            rate =
-                (amt / _minFromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
-          }
-        }
-      }
+      await updateRate(shouldNotifyListeners: shouldNotifyListeners);
 
       debugPrint(
           "_updated FROM: _from=${_from!.ticker} _to=${_to!.ticker} _fromAmount=$_fromAmount _toAmount=$_toAmount rate:$rate");
@@ -220,55 +146,10 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
         notifyListeners();
       }
     } catch (e, s) {
-      Logging.instance.log("$e\n$s", level: LogLevel.Fatal);
+      Logging.instance.log("$e\n$s", level: LogLevel.Error);
     }
   }
 
-  String get rateDisplayString {
-    if (rate == null || from == null || to == null) {
-      return "N/A";
-    } else {
-      return "1 ${from!.ticker.toUpperCase()} ~${rate!.toStringAsFixed(8)} ${to!.ticker.toUpperCase()}";
-    }
-  }
-
-  bool get canExchange {
-    return _fromAmount != null &&
-        _fromAmount != Decimal.zero &&
-        _toAmount != null &&
-        rate != null &&
-        minimumReceiveWarning.isEmpty &&
-        minimumSendWarning.isEmpty;
-  }
-
-  String get minimumSendWarning {
-    if (_from != null &&
-        _fromAmount != null &&
-        _minFromAmount != null &&
-        _fromAmount! < _minFromAmount!) {
-      return "Minimum amount ${_minFromAmount!.toString()} ${from!.ticker.toUpperCase()}";
-    }
-
-    return "";
-  }
-
-  String get minimumReceiveWarning {
-    // TODO not sure this is needed
-    // if (_toAmount != null &&
-    //     _minToAmount != null &&
-    //     _toAmount! < _minToAmount!) {
-    //   return "Minimum amount ${_minToAmount!.toString()} ${to.ticker.toUpperCase()}";
-    // }
-    return "";
-  }
-
-  // Future<void> _updateMinToAmount({required bool shouldNotifyListeners}) async {
-  //   _minToAmount = await getStandardMinExchangeAmount(from: to!, to: from!);
-  //   if (shouldNotifyListeners) {
-  //     notifyListeners();
-  //   }
-  // }
-
   Future<void> _updateMinFromAmount(
       {required bool shouldNotifyListeners}) async {
     _minFromAmount = await getStandardMinExchangeAmount(from: from!, to: to!);
@@ -277,48 +158,32 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
     }
   }
 
-  Future<void> setToAmountAndCalculateFromAmount(
-    Decimal newToAmount,
-    bool shouldNotifyListeners,
-  ) async {
-    // if (newToAmount == Decimal.zero) {
-    //   _fromAmount = Decimal.zero;
-    //   _toAmount = Decimal.zero;
-    //   if (shouldNotifyListeners) {
-    //     notifyListeners();
-    //   }
-    //   return;
-    // }
-
-    if (rate != null) {
-      _fromAmount =
-          (newToAmount / rate!).toDecimal(scaleOnInfinitePrecision: 12);
-    }
-
-    _toAmount = newToAmount;
-    if (shouldNotifyListeners) {
-      notifyListeners();
-    }
-  }
+  // Future<void> setToAmountAndCalculateFromAmount(
+  //   Decimal newToAmount,
+  //   bool shouldNotifyListeners,
+  // ) async {
+  //   if (newToAmount == Decimal.zero) {
+  //     _fromAmount = Decimal.zero;
+  //   }
+  //
+  //   _toAmount = newToAmount;
+  //   await updateRate();
+  //   if (shouldNotifyListeners) {
+  //     notifyListeners();
+  //   }
+  // }
 
   Future<void> setFromAmountAndCalculateToAmount(
     Decimal newFromAmount,
     bool shouldNotifyListeners,
   ) async {
-    // if (newFromAmount == Decimal.zero) {
-    //   _fromAmount = Decimal.zero;
-    //   _toAmount = Decimal.zero;
-    //   if (shouldNotifyListeners) {
-    //     notifyListeners();
-    //   }
-    //   return;
-    // }
-
-    if (rate != null) {
-      _toAmount = (newFromAmount * rate!);
+    if (newFromAmount == Decimal.zero) {
+      _toAmount = Decimal.zero;
     }
 
     _fromAmount = newFromAmount;
+    await updateRate(shouldNotifyListeners: shouldNotifyListeners);
+
     if (shouldNotifyListeners) {
       notifyListeners();
     }
@@ -329,8 +194,12 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
     required Currency from,
     required Currency to,
   }) async {
-    final response = await ChangeNow.instance.getEstimatedExchangeAmount(
-        fromTicker: from.ticker, toTicker: to.ticker, fromAmount: fromAmount);
+    final response =
+        await (cnTesting ?? ChangeNow.instance).getEstimatedExchangeAmount(
+      fromTicker: from.ticker,
+      toTicker: to.ticker,
+      fromAmount: fromAmount,
+    );
 
     if (response.value != null) {
       return response.value!.estimatedAmount;
@@ -341,11 +210,31 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
     }
   }
 
+  // Future<Decimal?> getStandardEstimatedFromAmount({
+  //   required Decimal toAmount,
+  //   required Currency from,
+  //   required Currency to,
+  // }) async {
+  //   final response = await (cnTesting ?? ChangeNow.instance)
+  //       .getEstimatedExchangeAmount(
+  //           fromTicker: from.ticker,
+  //           toTicker: to.ticker,
+  //       fromAmount: toAmount, );
+  //
+  //   if (response.value != null) {
+  //     return response.value!.fromAmount;
+  //   } else {
+  //     _onError?.call(
+  //         "Failed to fetch estimated amount: ${response.exception?.toString()}");
+  //     return null;
+  //   }
+  // }
+
   Future<Decimal?> getStandardMinExchangeAmount({
     required Currency from,
     required Currency to,
   }) async {
-    final response = await ChangeNow.instance
+    final response = await (cnTesting ?? ChangeNow.instance)
         .getMinimalExchangeAmount(fromTicker: from.ticker, toTicker: to.ticker);
 
     if (response.value != null) {
@@ -357,8 +246,6 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
     }
   }
 
-  void Function(String)? _onError;
-
   void setOnError({
     required void Function(String)? onError,
     bool shouldNotifyListeners = false,
@@ -368,4 +255,28 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
       notifyListeners();
     }
   }
+
+  Future<void> updateRate({bool shouldNotifyListeners = false}) async {
+    rate = null;
+    final amount = _fromAmount;
+    final minAmount = _minFromAmount;
+    if (amount != null && amount > Decimal.zero) {
+      Decimal? amt;
+      if (minAmount != null) {
+        if (minAmount <= amount) {
+          amt = await getStandardEstimatedToAmount(
+              fromAmount: amount, from: _from!, to: _to!);
+          if (amt != null) {
+            rate = (amt / amount).toDecimal(scaleOnInfinitePrecision: 12);
+          }
+        }
+      }
+      if (rate != null && amt != null) {
+        _toAmount = amt;
+      }
+    }
+    if (shouldNotifyListeners) {
+      notifyListeners();
+    }
+  }
 }
diff --git a/lib/models/exchange/fixed_rate_exchange_form_state.dart b/lib/models/exchange/fixed_rate_exchange_form_state.dart
index 1b282c30a..b75193158 100644
--- a/lib/models/exchange/fixed_rate_exchange_form_state.dart
+++ b/lib/models/exchange/fixed_rate_exchange_form_state.dart
@@ -1,27 +1,44 @@
 import 'package:decimal/decimal.dart';
 import 'package:flutter/cupertino.dart';
+import 'package:stackwallet/models/exchange/change_now/cn_exchange_estimate.dart';
 import 'package:stackwallet/models/exchange/change_now/fixed_rate_market.dart';
+import 'package:stackwallet/services/change_now/change_now.dart';
+import 'package:stackwallet/utilities/logger.dart';
 
 class FixedRateExchangeFormState extends ChangeNotifier {
   Decimal? _fromAmount;
   Decimal? _toAmount;
 
   FixedRateMarket? _market;
-
   FixedRateMarket? get market => _market;
 
+  CNExchangeEstimate? _estimate;
+  CNExchangeEstimate? get estimate => _estimate;
+
+  Decimal? get rate {
+    if (_estimate == null) {
+      return null;
+    } else {
+      return (_estimate!.toAmount / _estimate!.fromAmount)
+          .toDecimal(scaleOnInfinitePrecision: 12);
+    }
+  }
+
   Future<void> swap(FixedRateMarket reverseFixedRateMarket) async {
     final Decimal? tmp = _fromAmount;
     _fromAmount = _toAmount;
     _toAmount = tmp;
 
-    await updateMarket(reverseFixedRateMarket, true);
+    await updateMarket(reverseFixedRateMarket, false);
+    await updateRateEstimate(CNEstimateType.direct);
+    _toAmount = _estimate?.toAmount ?? Decimal.zero;
+    notifyListeners();
   }
 
   String get fromAmountString =>
-      _fromAmount == null ? "-" : _fromAmount!.toStringAsFixed(8);
+      _fromAmount == null ? "" : _fromAmount!.toStringAsFixed(8);
   String get toAmountString =>
-      _toAmount == null ? "-" : _toAmount!.toStringAsFixed(8);
+      _toAmount == null ? "" : _toAmount!.toStringAsFixed(8);
 
   Future<void> updateMarket(
     FixedRateMarket? market,
@@ -37,7 +54,7 @@ class FixedRateExchangeFormState extends ChangeNotifier {
         if (_fromAmount! <= Decimal.zero) {
           _toAmount = Decimal.zero;
         } else {
-          _toAmount = (_fromAmount! * _market!.rate) - _market!.minerFee;
+          await updateRateEstimate(CNEstimateType.direct);
         }
       }
     }
@@ -48,10 +65,10 @@ class FixedRateExchangeFormState extends ChangeNotifier {
   }
 
   String get rateDisplayString {
-    if (_market == null) {
+    if (_market == null || _estimate == null) {
       return "N/A";
     } else {
-      return "1 ${_market!.from.toUpperCase()} ~${_market!.rate.toStringAsFixed(8)} ${_market!.to.toUpperCase()}";
+      return "1 ${_estimate!.fromCurrency.toUpperCase()} ~${rate!.toStringAsFixed(8)} ${_estimate!.toCurrency.toUpperCase()}";
     }
   }
 
@@ -78,14 +95,10 @@ class FixedRateExchangeFormState extends ChangeNotifier {
     Decimal newToAmount,
     bool shouldNotifyListeners,
   ) async {
-    if (_market != null) {
-      _fromAmount = (newToAmount / _market!.rate)
-              .toDecimal(scaleOnInfinitePrecision: 12) +
-          _market!.minerFee;
-    }
-
     _toAmount = newToAmount;
+
     if (shouldNotifyListeners) {
+      await updateRateEstimate(CNEstimateType.reverse);
       notifyListeners();
     }
   }
@@ -94,12 +107,10 @@ class FixedRateExchangeFormState extends ChangeNotifier {
     Decimal newFromAmount,
     bool shouldNotifyListeners,
   ) async {
-    if (_market != null) {
-      _toAmount = (newFromAmount * _market!.rate) - _market!.minerFee;
-    }
-
     _fromAmount = newFromAmount;
+
     if (shouldNotifyListeners) {
+      await updateRateEstimate(CNEstimateType.direct);
       notifyListeners();
     }
   }
@@ -115,4 +126,53 @@ class FixedRateExchangeFormState extends ChangeNotifier {
       notifyListeners();
     }
   }
+
+  Future<void> updateRateEstimate(CNEstimateType direction) async {
+    if (market != null) {
+      Decimal? amount;
+      // set amount based on trade estimate direction
+      switch (direction) {
+        case CNEstimateType.direct:
+          if (_fromAmount != null
+              // &&
+              // market!.min >= _fromAmount! &&
+              // _fromAmount! <= market!.max
+              ) {
+            amount = _fromAmount!;
+          }
+          break;
+        case CNEstimateType.reverse:
+          if (_toAmount != null
+              // &&
+              // market!.min >= _toAmount! &&
+              // _toAmount! <= market!.max
+              ) {
+            amount = _toAmount!;
+          }
+          break;
+      }
+
+      if (amount != null && market != null && amount > Decimal.zero) {
+        final response = await ChangeNow.instance.getEstimatedExchangeAmountV2(
+          fromTicker: market!.from,
+          toTicker: market!.to,
+          fromOrTo: direction,
+          flow: CNFlowType.fixedRate,
+          amount: amount,
+        );
+
+        if (response.value != null) {
+          // update estimate if response succeeded
+          _estimate = response.value;
+
+          _toAmount = _estimate?.toAmount;
+          _fromAmount = _estimate?.fromAmount;
+          notifyListeners();
+        } else if (response.exception != null) {
+          Logging.instance.log("updateRateEstimate(): ${response.exception}",
+              level: LogLevel.Warning);
+        }
+      }
+    }
+  }
 }
diff --git a/lib/pages/exchange_view/exchange_step_views/step_4_view.dart b/lib/pages/exchange_view/exchange_step_views/step_4_view.dart
index 7ce46630d..91c3f1a6d 100644
--- a/lib/pages/exchange_view/exchange_step_views/step_4_view.dart
+++ b/lib/pages/exchange_view/exchange_step_views/step_4_view.dart
@@ -164,7 +164,7 @@ class _Step4ViewState extends ConsumerState<Step4View> {
                           height: 8,
                         ),
                         Text(
-                          "Send FIRO to the address below. Once it is received, ChangeNOW will send the BTC to the recipient address you provided. You can find this trade details and check its status in the list of trades.",
+                          "Send ${model.sendTicker} to the address below. Once it is received, ChangeNOW will send the ${model.receiveTicker} to the recipient address you provided. You can find this trade details and check its status in the list of trades.",
                           style: STextStyles.itemSubtitle,
                         ),
                         const SizedBox(
diff --git a/lib/pages/exchange_view/exchange_view.dart b/lib/pages/exchange_view/exchange_view.dart
index df659616f..b95315359 100644
--- a/lib/pages/exchange_view/exchange_view.dart
+++ b/lib/pages/exchange_view/exchange_view.dart
@@ -7,6 +7,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:flutter_svg/flutter_svg.dart';
 import 'package:flutter_svg/svg.dart';
 import 'package:stackwallet/models/exchange/change_now/available_floating_rate_pair.dart';
+import 'package:stackwallet/models/exchange/change_now/cn_exchange_estimate.dart';
 import 'package:stackwallet/models/exchange/change_now/currency.dart';
 import 'package:stackwallet/models/exchange/change_now/fixed_rate_market.dart';
 import 'package:stackwallet/models/exchange/incomplete_exchange.dart';
@@ -231,6 +232,65 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
         ? ref.read(estimatedRateExchangeFormProvider).toAmountString
         : ref.read(fixedRateExchangeFormProvider).toAmountString;
 
+    _sendFocusNode.addListener(() async {
+      if (!_sendFocusNode.hasFocus) {
+        final newFromAmount = Decimal.tryParse(_sendController.text);
+        if (newFromAmount != null) {
+          if (ref.read(prefsChangeNotifierProvider).exchangeRateType ==
+              ExchangeRateType.estimated) {
+            await ref
+                .read(estimatedRateExchangeFormProvider)
+                .setFromAmountAndCalculateToAmount(newFromAmount, true);
+          } else {
+            await ref
+                .read(fixedRateExchangeFormProvider)
+                .setFromAmountAndCalculateToAmount(newFromAmount, true);
+          }
+        } else {
+          if (ref.read(prefsChangeNotifierProvider).exchangeRateType ==
+              ExchangeRateType.estimated) {
+            await ref
+                .read(estimatedRateExchangeFormProvider)
+                .setFromAmountAndCalculateToAmount(Decimal.zero, true);
+          } else {
+            await ref
+                .read(fixedRateExchangeFormProvider)
+                .setFromAmountAndCalculateToAmount(Decimal.zero, true);
+          }
+          _receiveController.text = "";
+        }
+      }
+    });
+    _receiveFocusNode.addListener(() async {
+      if (!_receiveFocusNode.hasFocus) {
+        final newToAmount = Decimal.tryParse(_receiveController.text);
+        if (newToAmount != null) {
+          if (ref.read(prefsChangeNotifierProvider).exchangeRateType ==
+              ExchangeRateType.estimated) {
+            // await ref
+            //     .read(estimatedRateExchangeFormProvider)
+            //     .setToAmountAndCalculateFromAmount(newToAmount, true);
+          } else {
+            await ref
+                .read(fixedRateExchangeFormProvider)
+                .setToAmountAndCalculateFromAmount(newToAmount, true);
+          }
+        } else {
+          if (ref.read(prefsChangeNotifierProvider).exchangeRateType ==
+              ExchangeRateType.estimated) {
+            // await ref
+            //     .read(estimatedRateExchangeFormProvider)
+            //     .setToAmountAndCalculateFromAmount(Decimal.zero, true);
+          } else {
+            await ref
+                .read(fixedRateExchangeFormProvider)
+                .setToAmountAndCalculateFromAmount(Decimal.zero, true);
+          }
+          _sendController.text = "";
+        }
+      }
+    });
+
     super.initState();
   }
 
@@ -332,12 +392,12 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
                               await ref
                                   .read(estimatedRateExchangeFormProvider)
                                   .setFromAmountAndCalculateToAmount(
-                                      newFromAmount, true);
+                                      newFromAmount, false);
                             } else {
                               await ref
                                   .read(fixedRateExchangeFormProvider)
                                   .setFromAmountAndCalculateToAmount(
-                                      newFromAmount, true);
+                                      newFromAmount, false);
                             }
                           } else {
                             if (ref
@@ -347,12 +407,12 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
                               await ref
                                   .read(estimatedRateExchangeFormProvider)
                                   .setFromAmountAndCalculateToAmount(
-                                      Decimal.zero, true);
+                                      Decimal.zero, false);
                             } else {
                               await ref
                                   .read(fixedRateExchangeFormProvider)
                                   .setFromAmountAndCalculateToAmount(
-                                      Decimal.zero, true);
+                                      Decimal.zero, false);
                             }
                             _receiveController.text = "";
                           }
@@ -631,6 +691,10 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
                       TextFormField(
                         focusNode: _receiveFocusNode,
                         controller: _receiveController,
+                        readOnly: ref
+                                .read(prefsChangeNotifierProvider)
+                                .exchangeRateType ==
+                            ExchangeRateType.estimated,
                         onTap: () {
                           if (_receiveController.text == "-") {
                             _receiveController.text = "";
@@ -643,30 +707,30 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
                                     .read(prefsChangeNotifierProvider)
                                     .exchangeRateType ==
                                 ExchangeRateType.estimated) {
-                              await ref
-                                  .read(estimatedRateExchangeFormProvider)
-                                  .setToAmountAndCalculateFromAmount(
-                                      newToAmount, true);
+                              // await ref
+                              //     .read(estimatedRateExchangeFormProvider)
+                              //     .setToAmountAndCalculateFromAmount(
+                              //         newToAmount, false);
                             } else {
                               await ref
                                   .read(fixedRateExchangeFormProvider)
                                   .setToAmountAndCalculateFromAmount(
-                                      newToAmount, true);
+                                      newToAmount, false);
                             }
                           } else {
                             if (ref
                                     .read(prefsChangeNotifierProvider)
                                     .exchangeRateType ==
                                 ExchangeRateType.estimated) {
-                              await ref
-                                  .read(estimatedRateExchangeFormProvider)
-                                  .setToAmountAndCalculateFromAmount(
-                                      Decimal.zero, true);
+                              // await ref
+                              //     .read(estimatedRateExchangeFormProvider)
+                              //     .setToAmountAndCalculateFromAmount(
+                              //         Decimal.zero, false);
                             } else {
                               await ref
                                   .read(fixedRateExchangeFormProvider)
                                   .setToAmountAndCalculateFromAmount(
-                                      Decimal.zero, true);
+                                      Decimal.zero, false);
                             }
                             _sendController.text = "";
                           }
@@ -948,6 +1012,24 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
                                     final to = availableCurrencies.firstWhere(
                                         (e) => e.ticker == toTicker);
 
+                                    final newFromAmount =
+                                        Decimal.tryParse(_sendController.text);
+                                    if (newFromAmount != null) {
+                                      await ref
+                                          .read(
+                                              estimatedRateExchangeFormProvider)
+                                          .setFromAmountAndCalculateToAmount(
+                                              newFromAmount, false);
+                                    } else {
+                                      await ref
+                                          .read(
+                                              estimatedRateExchangeFormProvider)
+                                          .setFromAmountAndCalculateToAmount(
+                                              Decimal.zero, false);
+
+                                      _receiveController.text = "";
+                                    }
+
                                     await ref
                                         .read(estimatedRateExchangeFormProvider)
                                         .updateTo(to, false);
@@ -992,6 +1074,23 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
                                 } catch (_) {
                                   market = null;
                                 }
+
+                                final newFromAmount =
+                                    Decimal.tryParse(_sendController.text);
+                                if (newFromAmount != null) {
+                                  await ref
+                                      .read(fixedRateExchangeFormProvider)
+                                      .setFromAmountAndCalculateToAmount(
+                                          newFromAmount, false);
+                                } else {
+                                  await ref
+                                      .read(fixedRateExchangeFormProvider)
+                                      .setFromAmountAndCalculateToAmount(
+                                          Decimal.zero, false);
+
+                                  _receiveController.text = "";
+                                }
+
                                 await ref
                                     .read(fixedRateExchangeFormProvider)
                                     .updateMarket(market, false);
@@ -1170,11 +1269,12 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
 
                                   final response = await ref
                                       .read(changeNowProvider)
-                                      .getEstimatedFixedRateExchangeAmount(
+                                      .getEstimatedExchangeAmountV2(
                                         fromTicker: fromTicker,
                                         toTicker: toTicker,
-                                        fromAmount: sendAmount,
-                                        useRateId: true,
+                                        fromOrTo: CNEstimateType.direct,
+                                        amount: sendAmount,
+                                        flow: CNFlowType.fixedRate,
                                       );
 
                                   bool? shouldCancel;
@@ -1251,15 +1351,14 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
                                   }
 
                                   String rate =
-                                      "1 $fromTicker ~${ref.read(fixedRateExchangeFormProvider).market!.rate.toStringAsFixed(8)} $toTicker";
+                                      "1 $fromTicker ~${ref.read(fixedRateExchangeFormProvider).rate!.toStringAsFixed(8)} $toTicker";
 
                                   final model = IncompleteExchangeModel(
                                     sendTicker: fromTicker,
                                     receiveTicker: toTicker,
                                     rateInfo: rate,
                                     sendAmount: sendAmount,
-                                    receiveAmount:
-                                        response.value!.estimatedAmount,
+                                    receiveAmount: response.value!.toAmount,
                                     rateId: response.value!.rateId,
                                     rateType: rateType,
                                   );
diff --git a/lib/pages/exchange_view/sub_widgets/step_row.dart b/lib/pages/exchange_view/sub_widgets/step_row.dart
index 88d6e06cd..5404eb98b 100644
--- a/lib/pages/exchange_view/sub_widgets/step_row.dart
+++ b/lib/pages/exchange_view/sub_widgets/step_row.dart
@@ -55,7 +55,7 @@ class StepRow extends StatelessWidget {
       ));
     }
     list.add(StepIndicator(
-      step: count - 1,
+      step: count,
       status: getStatus(count - 1),
     ));
     return list;
diff --git a/lib/pages/exchange_view/trade_details_view.dart b/lib/pages/exchange_view/trade_details_view.dart
index 16c34891a..68b1f49a6 100644
--- a/lib/pages/exchange_view/trade_details_view.dart
+++ b/lib/pages/exchange_view/trade_details_view.dart
@@ -1,3 +1,5 @@
+import 'dart:async';
+
 import 'package:decimal/decimal.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
@@ -10,6 +12,7 @@ import 'package:stackwallet/notifications/show_flush_bar.dart';
 import 'package:stackwallet/pages/exchange_view/edit_trade_note_view.dart';
 import 'package:stackwallet/pages/wallet_view/transaction_views/edit_note_view.dart';
 import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
+import 'package:stackwallet/providers/exchange/change_now_provider.dart';
 import 'package:stackwallet/providers/exchange/trade_note_service_provider.dart';
 import 'package:stackwallet/providers/global/trades_service_provider.dart';
 import 'package:stackwallet/providers/providers.dart';
@@ -63,6 +66,26 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
     clipboard = widget.clipboard;
     transactionIfSentFromStack = widget.transactionIfSentFromStack;
     walletId = widget.walletId;
+
+    WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
+      final trade = ref
+          .read(tradesServiceProvider)
+          .trades
+          .firstWhere((e) => e.id == tradeId);
+
+      if (mounted && trade.statusObject == null ||
+          trade.statusObject!.amountSendDecimal.isEmpty) {
+        final status = await ref
+            .read(changeNowProvider)
+            .getTransactionStatus(id: trade.id);
+
+        if (mounted && status.value != null) {
+          await ref.read(tradesServiceProvider).edit(
+              trade: trade.copyWith(statusObject: status.value),
+              shouldNotifyListeners: true);
+        }
+      }
+    });
     super.initState();
   }
 
@@ -77,8 +100,6 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
       status = ChangeNowTransactionStatus.Failed;
     }
 
-    debugPrint("statusstatusstatusstatus: $status");
-    debugPrint("statusstatusstatusstatusSTRING: $statusString");
     switch (status) {
       case ChangeNowTransactionStatus.New:
       case ChangeNowTransactionStatus.Waiting:
@@ -113,6 +134,11 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
     debugPrint("hasTx: $hasTx");
     debugPrint("trade: ${trade.toString()}");
 
+    final sendAmount = Decimal.tryParse(
+            trade.statusObject?.amountSendDecimal ?? "") ??
+        Decimal.tryParse(trade.statusObject?.expectedSendAmountDecimal ?? "") ??
+        Decimal.parse("-1");
+
     return Scaffold(
       backgroundColor: CFColors.almostWhite,
       appBar: AppBar(
@@ -150,7 +176,7 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
                             height: 4,
                           ),
                           SelectableText(
-                            "${Format.localizedStringAsFixed(value: Decimal.parse(trade.statusObject?.amountSendDecimal ?? trade.amount), locale: ref.watch(
+                            "${Format.localizedStringAsFixed(value: sendAmount, locale: ref.watch(
                                   localeServiceChangeNotifierProvider
                                       .select((value) => value.locale),
                                 ), decimalPlaces: trade.fromCurrency.toLowerCase() == "xmr" ? 12 : 8)} ${trade.fromCurrency.toUpperCase()}",
@@ -205,7 +231,7 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
                     ],
                   ),
                 ),
-                if (!sentFromStack && hasTx)
+                if (!sentFromStack && !hasTx)
                   const SizedBox(
                     height: 12,
                   ),
@@ -214,9 +240,8 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
                     color: CFColors.warningBackground,
                     child: RichText(
                       text: TextSpan(
-                          text: "You must send at least ${Decimal.parse(
-                            trade.statusObject!.amountSendDecimal,
-                          ).toStringAsFixed(
+                          text:
+                              "You must send at least ${sendAmount.toStringAsFixed(
                             trade.fromCurrency.toLowerCase() == "xmr" ? 12 : 8,
                           )} ${trade.fromCurrency.toUpperCase()}. ",
                           style: STextStyles.label.copyWith(
@@ -225,9 +250,8 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
                           ),
                           children: [
                             TextSpan(
-                              text: "If you send less than ${Decimal.parse(
-                                trade.statusObject!.amountSendDecimal,
-                              ).toStringAsFixed(
+                              text:
+                                  "If you send less than ${sendAmount.toStringAsFixed(
                                 trade.fromCurrency.toLowerCase() == "xmr"
                                     ? 12
                                     : 8,
@@ -623,11 +647,11 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
                             onTap: () async {
                               final data = ClipboardData(text: trade.id);
                               await clipboard.setData(data);
-                              showFloatingFlushBar(
+                              unawaited(showFloatingFlushBar(
                                 type: FlushBarType.info,
                                 message: "Copied to clipboard",
                                 context: context,
-                              );
+                              ));
                             },
                             child: SvgPicture.asset(
                               Assets.svg.copy,
diff --git a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart
index 152826345..74519e379 100644
--- a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart
+++ b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart
@@ -6,6 +6,7 @@ import 'package:flutter/services.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:flutter_svg/svg.dart';
 import 'package:stackwallet/models/exchange/change_now/available_floating_rate_pair.dart';
+import 'package:stackwallet/models/exchange/change_now/cn_exchange_estimate.dart';
 import 'package:stackwallet/models/exchange/change_now/currency.dart';
 import 'package:stackwallet/models/exchange/change_now/fixed_rate_market.dart';
 import 'package:stackwallet/models/exchange/incomplete_exchange.dart';
@@ -243,6 +244,64 @@ class _WalletInitiatedExchangeViewState
       ref.read(estimatedRateExchangeFormProvider).clearAmounts(true);
       // ref.read(fixedRateExchangeFormProvider);
     });
+    _sendFocusNode.addListener(() async {
+      if (!_sendFocusNode.hasFocus) {
+        final newFromAmount = Decimal.tryParse(_sendController.text);
+        if (newFromAmount != null) {
+          if (ref.read(prefsChangeNotifierProvider).exchangeRateType ==
+              ExchangeRateType.estimated) {
+            await ref
+                .read(estimatedRateExchangeFormProvider)
+                .setFromAmountAndCalculateToAmount(newFromAmount, true);
+          } else {
+            await ref
+                .read(fixedRateExchangeFormProvider)
+                .setFromAmountAndCalculateToAmount(newFromAmount, true);
+          }
+        } else {
+          if (ref.read(prefsChangeNotifierProvider).exchangeRateType ==
+              ExchangeRateType.estimated) {
+            await ref
+                .read(estimatedRateExchangeFormProvider)
+                .setFromAmountAndCalculateToAmount(Decimal.zero, true);
+          } else {
+            await ref
+                .read(fixedRateExchangeFormProvider)
+                .setFromAmountAndCalculateToAmount(Decimal.zero, true);
+          }
+          _receiveController.text = "";
+        }
+      }
+    });
+    _receiveFocusNode.addListener(() async {
+      if (!_receiveFocusNode.hasFocus) {
+        final newToAmount = Decimal.tryParse(_receiveController.text);
+        if (newToAmount != null) {
+          if (ref.read(prefsChangeNotifierProvider).exchangeRateType ==
+              ExchangeRateType.estimated) {
+            // await ref
+            //     .read(estimatedRateExchangeFormProvider)
+            //     .setToAmountAndCalculateFromAmount(newToAmount, true);
+          } else {
+            await ref
+                .read(fixedRateExchangeFormProvider)
+                .setToAmountAndCalculateFromAmount(newToAmount, true);
+          }
+        } else {
+          if (ref.read(prefsChangeNotifierProvider).exchangeRateType ==
+              ExchangeRateType.estimated) {
+            // await ref
+            //     .read(estimatedRateExchangeFormProvider)
+            //     .setToAmountAndCalculateFromAmount(Decimal.zero, true);
+          } else {
+            await ref
+                .read(fixedRateExchangeFormProvider)
+                .setToAmountAndCalculateFromAmount(Decimal.zero, true);
+          }
+          _sendController.text = "";
+        }
+      }
+    });
     super.initState();
   }
 
@@ -379,12 +438,12 @@ class _WalletInitiatedExchangeViewState
                                 await ref
                                     .read(estimatedRateExchangeFormProvider)
                                     .setFromAmountAndCalculateToAmount(
-                                        newFromAmount, true);
+                                        newFromAmount, false);
                               } else {
                                 await ref
                                     .read(fixedRateExchangeFormProvider)
                                     .setFromAmountAndCalculateToAmount(
-                                        newFromAmount, true);
+                                        newFromAmount, false);
                               }
                             } else {
                               if (ref
@@ -394,12 +453,12 @@ class _WalletInitiatedExchangeViewState
                                 await ref
                                     .read(estimatedRateExchangeFormProvider)
                                     .setFromAmountAndCalculateToAmount(
-                                        Decimal.zero, true);
+                                        Decimal.zero, false);
                               } else {
                                 await ref
                                     .read(fixedRateExchangeFormProvider)
                                     .setFromAmountAndCalculateToAmount(
-                                        Decimal.zero, true);
+                                        Decimal.zero, false);
                               }
                               _receiveController.text = "";
                             }
@@ -716,6 +775,10 @@ class _WalletInitiatedExchangeViewState
                         TextFormField(
                           focusNode: _receiveFocusNode,
                           controller: _receiveController,
+                          readOnly: ref
+                                  .read(prefsChangeNotifierProvider)
+                                  .exchangeRateType ==
+                              ExchangeRateType.estimated,
                           onTap: () {
                             if (_receiveController.text == "-") {
                               _receiveController.text = "";
@@ -728,30 +791,30 @@ class _WalletInitiatedExchangeViewState
                                       .read(prefsChangeNotifierProvider)
                                       .exchangeRateType ==
                                   ExchangeRateType.estimated) {
-                                await ref
-                                    .read(estimatedRateExchangeFormProvider)
-                                    .setToAmountAndCalculateFromAmount(
-                                        newToAmount, true);
+                                // await ref
+                                //     .read(estimatedRateExchangeFormProvider)
+                                //     .setToAmountAndCalculateFromAmount(
+                                //         newToAmount, false);
                               } else {
                                 await ref
                                     .read(fixedRateExchangeFormProvider)
                                     .setToAmountAndCalculateFromAmount(
-                                        newToAmount, true);
+                                        newToAmount, false);
                               }
                             } else {
                               if (ref
                                       .read(prefsChangeNotifierProvider)
                                       .exchangeRateType ==
                                   ExchangeRateType.estimated) {
-                                await ref
-                                    .read(estimatedRateExchangeFormProvider)
-                                    .setToAmountAndCalculateFromAmount(
-                                        Decimal.zero, true);
+                                // await ref
+                                //     .read(estimatedRateExchangeFormProvider)
+                                //     .setToAmountAndCalculateFromAmount(
+                                //         Decimal.zero, false);
                               } else {
                                 await ref
                                     .read(fixedRateExchangeFormProvider)
                                     .setToAmountAndCalculateFromAmount(
-                                        Decimal.zero, true);
+                                        Decimal.zero, false);
                               }
                               _sendController.text = "";
                             }
@@ -1374,11 +1437,12 @@ class _WalletInitiatedExchangeViewState
 
                                     final response = await ref
                                         .read(changeNowProvider)
-                                        .getEstimatedFixedRateExchangeAmount(
+                                        .getEstimatedExchangeAmountV2(
                                           fromTicker: fromTicker,
                                           toTicker: toTicker,
-                                          fromAmount: sendAmount,
-                                          useRateId: true,
+                                          fromOrTo: CNEstimateType.direct,
+                                          amount: sendAmount,
+                                          flow: CNFlowType.fixedRate,
                                         );
 
                                     bool? shouldCancel;
@@ -1456,15 +1520,14 @@ class _WalletInitiatedExchangeViewState
                                     }
 
                                     String rate =
-                                        "1 $fromTicker ~${ref.read(fixedRateExchangeFormProvider).market!.rate.toStringAsFixed(8)} $toTicker";
+                                        "1 $fromTicker ~${ref.read(fixedRateExchangeFormProvider).rate!.toStringAsFixed(8)} $toTicker";
 
                                     final model = IncompleteExchangeModel(
                                       sendTicker: fromTicker,
                                       receiveTicker: toTicker,
                                       rateInfo: rate,
                                       sendAmount: sendAmount,
-                                      receiveAmount:
-                                          response.value!.estimatedAmount,
+                                      receiveAmount: response.value!.toAmount,
                                       rateId: response.value!.rateId,
                                       rateType: rateType,
                                     );
diff --git a/lib/pages/receive_view/generate_receiving_uri_qr_code_view.dart b/lib/pages/receive_view/generate_receiving_uri_qr_code_view.dart
index a473d0d45..037677a40 100644
--- a/lib/pages/receive_view/generate_receiving_uri_qr_code_view.dart
+++ b/lib/pages/receive_view/generate_receiving_uri_qr_code_view.dart
@@ -6,10 +6,12 @@ import 'dart:ui' as ui;
 import 'package:decimal/decimal.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/rendering.dart';
+import 'package:flutter_svg/svg.dart';
 import 'package:path_provider/path_provider.dart';
 import 'package:qr_flutter/qr_flutter.dart';
 import 'package:share_plus/share_plus.dart';
 import 'package:stackwallet/notifications/show_flush_bar.dart';
+import 'package:stackwallet/utilities/assets.dart';
 import 'package:stackwallet/utilities/cfcolors.dart';
 import 'package:stackwallet/utilities/clipboard_interface.dart';
 import 'package:stackwallet/utilities/constants.dart';
@@ -318,8 +320,7 @@ class _GenerateUriQrCodeViewState extends State<GenerateUriQrCodeView> {
                                             child: QrImage(
                                               data: uriString,
                                               size: width,
-                                              backgroundColor:
-                                                  CFColors.almostWhite,
+                                              backgroundColor: CFColors.white,
                                               foregroundColor:
                                                   CFColors.stackAccent,
                                             ),
@@ -344,12 +345,40 @@ class _GenerateUriQrCodeViewState extends State<GenerateUriQrCodeView> {
                                                 CFColors.buttonGray,
                                               ),
                                             ),
-                                            child: Text(
-                                              "Share",
-                                              style:
-                                                  STextStyles.button.copyWith(
-                                                color: CFColors.stackAccent,
-                                              ),
+                                            child: Row(
+                                              mainAxisAlignment:
+                                                  MainAxisAlignment.center,
+                                              crossAxisAlignment:
+                                                  CrossAxisAlignment.center,
+                                              children: [
+                                                Center(
+                                                  child: SvgPicture.asset(
+                                                    Assets.svg.share,
+                                                    width: 14,
+                                                    height: 14,
+                                                  ),
+                                                ),
+                                                const SizedBox(
+                                                  width: 4,
+                                                ),
+                                                Column(
+                                                  children: [
+                                                    Text(
+                                                      "Share",
+                                                      textAlign:
+                                                          TextAlign.center,
+                                                      style: STextStyles.button
+                                                          .copyWith(
+                                                        color: CFColors
+                                                            .stackAccent,
+                                                      ),
+                                                    ),
+                                                    const SizedBox(
+                                                      height: 2,
+                                                    ),
+                                                  ],
+                                                ),
+                                              ],
                                             ),
                                           ),
                                         ),
diff --git a/lib/pages/receive_view/receive_view.dart b/lib/pages/receive_view/receive_view.dart
index 4662abac2..b0f49682b 100644
--- a/lib/pages/receive_view/receive_view.dart
+++ b/lib/pages/receive_view/receive_view.dart
@@ -1,36 +1,114 @@
+import 'dart:async';
+
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:flutter_svg/flutter_svg.dart';
 import 'package:qr_flutter/qr_flutter.dart';
 import 'package:stackwallet/notifications/show_flush_bar.dart';
 import 'package:stackwallet/pages/receive_view/generate_receiving_uri_qr_code_view.dart';
+import 'package:stackwallet/providers/providers.dart';
 import 'package:stackwallet/route_generator.dart';
 import 'package:stackwallet/utilities/assets.dart';
 import 'package:stackwallet/utilities/cfcolors.dart';
 import 'package:stackwallet/utilities/clipboard_interface.dart';
-import 'package:stackwallet/utilities/constants.dart';
 import 'package:stackwallet/utilities/enums/coin_enum.dart';
 import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
 import 'package:stackwallet/utilities/text_styles.dart';
 import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
+import 'package:stackwallet/widgets/custom_loading_overlay.dart';
+import 'package:stackwallet/widgets/rounded_white_container.dart';
 
-class ReceiveView extends StatelessWidget {
+class ReceiveView extends ConsumerStatefulWidget {
   const ReceiveView({
     Key? key,
     required this.coin,
-    required this.receivingAddress,
+    required this.walletId,
     this.clipboard = const ClipboardWrapper(),
   }) : super(key: key);
 
   static const String routeName = "/receiveView";
 
   final Coin coin;
-  final String receivingAddress;
+  final String walletId;
   final ClipboardInterface clipboard;
 
+  @override
+  ConsumerState<ReceiveView> createState() => _ReceiveViewState();
+}
+
+class _ReceiveViewState extends ConsumerState<ReceiveView> {
+  late final Coin coin;
+  late final String walletId;
+  late final ClipboardInterface clipboard;
+
+  Future<void> generateNewAddress() async {
+    bool shouldPop = false;
+    unawaited(
+      showDialog(
+        context: context,
+        builder: (_) {
+          return WillPopScope(
+            onWillPop: () async => shouldPop,
+            child: const CustomLoadingOverlay(
+              message: "Generating address",
+              eventBus: null,
+            ),
+          );
+        },
+      ),
+    );
+
+    await ref
+        .read(walletsChangeNotifierProvider)
+        .getManager(walletId)
+        .generateNewAddress();
+
+    shouldPop = true;
+
+    if (mounted) {
+      Navigator.of(context)
+          .popUntil(ModalRoute.withName(ReceiveView.routeName));
+    }
+  }
+
+  String receivingAddress = "";
+
+  @override
+  void initState() {
+    walletId = widget.walletId;
+    coin = widget.coin;
+    clipboard = widget.clipboard;
+
+    WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
+      final address = await ref
+          .read(walletsChangeNotifierProvider)
+          .getManager(walletId)
+          .currentReceivingAddress;
+      setState(() {
+        receivingAddress = address;
+      });
+    });
+
+    super.initState();
+  }
+
   @override
   Widget build(BuildContext context) {
     debugPrint("BUILD: $runtimeType");
+
+    ref.listen(
+        ref
+            .read(walletsChangeNotifierProvider)
+            .getManagerProvider(walletId)
+            .select((value) => value.currentReceivingAddress),
+        (previous, next) {
+      if (next is Future<String>) {
+        next.then((value) => setState(() => receivingAddress = value));
+      }
+    });
+
     return Scaffold(
       backgroundColor: CFColors.almostWhite,
       appBar: AppBar(
@@ -52,15 +130,19 @@ class ReceiveView extends StatelessWidget {
             child: Column(
               crossAxisAlignment: CrossAxisAlignment.stretch,
               children: [
-                Container(
-                  decoration: BoxDecoration(
-                    color: CFColors.white,
-                    borderRadius: BorderRadius.circular(
-                      Constants.size.circularBorderRadius,
-                    ),
-                  ),
-                  child: Padding(
-                    padding: const EdgeInsets.all(12.0),
+                GestureDetector(
+                  onTap: () {
+                    clipboard.setData(
+                      ClipboardData(text: receivingAddress),
+                    );
+                    showFloatingFlushBar(
+                      type: FlushBarType.info,
+                      message: "Copied to clipboard",
+                      iconAsset: Assets.svg.copy,
+                      context: context,
+                    );
+                  },
+                  child: RoundedWhiteContainer(
                     child: Column(
                       children: [
                         Row(
@@ -70,35 +152,22 @@ class ReceiveView extends StatelessWidget {
                               style: STextStyles.itemSubtitle,
                             ),
                             const Spacer(),
-                            GestureDetector(
-                              onTap: () {
-                                clipboard.setData(
-                                  ClipboardData(text: receivingAddress),
-                                );
-                                showFloatingFlushBar(
-                                  type: FlushBarType.info,
-                                  message: "Copied to clipboard",
-                                  iconAsset: Assets.svg.copy,
-                                  context: context,
-                                );
-                              },
-                              child: Row(
-                                children: [
-                                  SvgPicture.asset(
-                                    Assets.svg.copy,
-                                    width: 10,
-                                    height: 10,
-                                    color: CFColors.link2,
-                                  ),
-                                  const SizedBox(
-                                    width: 4,
-                                  ),
-                                  Text(
-                                    "Copy",
-                                    style: STextStyles.link2,
-                                  ),
-                                ],
-                              ),
+                            Row(
+                              children: [
+                                SvgPicture.asset(
+                                  Assets.svg.copy,
+                                  width: 10,
+                                  height: 10,
+                                  color: CFColors.link2,
+                                ),
+                                const SizedBox(
+                                  width: 4,
+                                ),
+                                Text(
+                                  "Copy",
+                                  style: STextStyles.link2,
+                                ),
+                              ],
                             ),
                           ],
                         ),
@@ -119,47 +188,62 @@ class ReceiveView extends StatelessWidget {
                     ),
                   ),
                 ),
-                const SizedBox(
-                  height: 30,
-                ),
-                Center(
-                  child: QrImage(
-                    data: "${coin.uriScheme}:$receivingAddress",
-                    size: MediaQuery.of(context).size.width / 2,
-                    foregroundColor: CFColors.stackAccent,
+                if (coin != Coin.epicCash)
+                  const SizedBox(
+                    height: 12,
                   ),
-                ),
-                const SizedBox(
-                  height: 30,
-                ),
-                // Spacer(
-                //   flex: 7,
-                // ),
-                TextButton(
-                  onPressed: () {
-                    Navigator.of(context).push(
-                      RouteGenerator.getRoute(
-                        shouldUseMaterialRoute:
-                            RouteGenerator.useMaterialPageRoute,
-                        builder: (_) => GenerateUriQrCodeView(
-                          coin: coin,
-                          receivingAddress: receivingAddress,
-                        ),
-                        settings: const RouteSettings(
-                          name: GenerateUriQrCodeView.routeName,
-                        ),
+                if (coin != Coin.epicCash)
+                  TextButton(
+                    onPressed: generateNewAddress,
+                    style: ButtonStyle(
+                      backgroundColor: MaterialStateProperty.all<Color>(
+                        CFColors.buttonGray,
+                      ),
+                    ),
+                    child: Text(
+                      "Generate new address",
+                      style: STextStyles.button.copyWith(
+                        color: CFColors.stackAccent,
                       ),
-                    );
-                  },
-                  style: ButtonStyle(
-                    backgroundColor: MaterialStateProperty.all<Color>(
-                      CFColors.buttonGray,
                     ),
                   ),
-                  child: Text(
-                    "Generate QR Code",
-                    style: STextStyles.button.copyWith(
-                      color: CFColors.stackAccent,
+                const SizedBox(
+                  height: 30,
+                ),
+                RoundedWhiteContainer(
+                  child: Padding(
+                    padding: const EdgeInsets.all(8.0),
+                    child: Center(
+                      child: Column(
+                        children: [
+                          QrImage(
+                            data: "${coin.uriScheme}:$receivingAddress",
+                            size: MediaQuery.of(context).size.width / 2,
+                            foregroundColor: CFColors.stackAccent,
+                          ),
+                          const SizedBox(
+                            height: 20,
+                          ),
+                          BlueTextButton(
+                            text: "Create new QR code",
+                            onTap: () async {
+                              unawaited(Navigator.of(context).push(
+                                RouteGenerator.getRoute(
+                                  shouldUseMaterialRoute:
+                                      RouteGenerator.useMaterialPageRoute,
+                                  builder: (_) => GenerateUriQrCodeView(
+                                    coin: coin,
+                                    receivingAddress: receivingAddress,
+                                  ),
+                                  settings: const RouteSettings(
+                                    name: GenerateUriQrCodeView.routeName,
+                                  ),
+                                ),
+                              ));
+                            },
+                          ),
+                        ],
+                      ),
                     ),
                   ),
                 ),
diff --git a/lib/pages/send_view/confirm_transaction_view.dart b/lib/pages/send_view/confirm_transaction_view.dart
index 4494790cc..5d28619aa 100644
--- a/lib/pages/send_view/confirm_transaction_view.dart
+++ b/lib/pages/send_view/confirm_transaction_view.dart
@@ -9,6 +9,7 @@ import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
 import 'package:stackwallet/providers/providers.dart';
 import 'package:stackwallet/route_generator.dart';
 import 'package:stackwallet/services/coins/epiccash/epiccash_wallet.dart';
+import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
 import 'package:stackwallet/utilities/cfcolors.dart';
 import 'package:stackwallet/utilities/enums/coin_enum.dart';
 import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
@@ -19,6 +20,8 @@ import 'package:stackwallet/widgets/rounded_container.dart';
 import 'package:stackwallet/widgets/rounded_white_container.dart';
 import 'package:stackwallet/widgets/stack_dialog.dart';
 
+import '../../providers/wallet/public_private_balance_state_provider.dart';
+
 class ConfirmTransactionView extends ConsumerStatefulWidget {
   const ConfirmTransactionView({
     Key? key,
@@ -56,10 +59,20 @@ class _ConfirmTransactionViewState
 
     final note = transactionInfo["note"] as String? ?? "";
     final manager =
-    ref.read(walletsChangeNotifierProvider).getManager(walletId);
+        ref.read(walletsChangeNotifierProvider).getManager(walletId);
 
     try {
-      final txid = await manager.confirmSend(txData: transactionInfo);
+      String txid;
+      final coin = manager.coin;
+      if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
+          ref.read(publicPrivateBalanceStateProvider.state).state !=
+              "Private") {
+        txid = await (manager.wallet as FiroWallet)
+            .confirmSendPublic(txData: transactionInfo);
+      } else {
+        txid = await manager.confirmSend(txData: transactionInfo);
+      }
+
       unawaited(manager.refresh());
 
       // save note
@@ -79,7 +92,7 @@ class _ConfirmTransactionViewState
           showFloatingFlushBar(
             type: FlushBarType.warning,
             message:
-            "Connection failed. Please check the address and try again.",
+                "Connection failed. Please check the address and try again.",
             context: context,
           ),
         );
@@ -100,10 +113,10 @@ class _ConfirmTransactionViewState
             message: e.toString(),
             rightButton: TextButton(
               style: Theme.of(context).textButtonTheme.style?.copyWith(
-                backgroundColor: MaterialStateProperty.all<Color>(
-                  CFColors.buttonGray,
-                ),
-              ),
+                    backgroundColor: MaterialStateProperty.all<Color>(
+                      CFColors.buttonGray,
+                    ),
+                  ),
               child: Text(
                 "Ok",
                 style: STextStyles.button.copyWith(
@@ -212,9 +225,9 @@ class _ConfirmTransactionViewState
                                         .select((value) => value.locale),
                                   ),
                                 )} ${ref.watch(
-                                  managerProvider
-                                      .select((value) => value.coin),
-                                ).ticker}",
+                                      managerProvider
+                                          .select((value) => value.coin),
+                                    ).ticker}",
                                 style: STextStyles.itemSubtitle12,
                                 textAlign: TextAlign.right,
                               ),
@@ -240,9 +253,9 @@ class _ConfirmTransactionViewState
                                         .select((value) => value.locale),
                                   ),
                                 )} ${ref.watch(
-                                  managerProvider
-                                      .select((value) => value.coin),
-                                ).ticker}",
+                                      managerProvider
+                                          .select((value) => value.coin),
+                                    ).ticker}",
                                 style: STextStyles.itemSubtitle12,
                                 textAlign: TextAlign.right,
                               ),
@@ -292,9 +305,9 @@ class _ConfirmTransactionViewState
                                         .select((value) => value.locale),
                                   ),
                                 )} ${ref.watch(
-                                  managerProvider
-                                      .select((value) => value.coin),
-                                ).ticker}",
+                                      managerProvider
+                                          .select((value) => value.coin),
+                                    ).ticker}",
                                 style: STextStyles.itemSubtitle12,
                                 textAlign: TextAlign.right,
                               ),
@@ -306,18 +319,18 @@ class _ConfirmTransactionViewState
                         ),
                         TextButton(
                           style:
-                          Theme.of(context).textButtonTheme.style?.copyWith(
-                            backgroundColor:
-                            MaterialStateProperty.all<Color>(
-                              CFColors.stackAccent,
-                            ),
-                          ),
+                              Theme.of(context).textButtonTheme.style?.copyWith(
+                                    backgroundColor:
+                                        MaterialStateProperty.all<Color>(
+                                      CFColors.stackAccent,
+                                    ),
+                                  ),
                           onPressed: () async {
                             final unlocked = await Navigator.push(
                               context,
                               RouteGenerator.getRoute(
                                 shouldUseMaterialRoute:
-                                RouteGenerator.useMaterialPageRoute,
+                                    RouteGenerator.useMaterialPageRoute,
                                 builder: (_) => const LockscreenView(
                                   showBackButton: true,
                                   popOnSuccess: true,
@@ -325,9 +338,9 @@ class _ConfirmTransactionViewState
                                   routeOnSuccess: "",
                                   biometricsCancelButtonString: "CANCEL",
                                   biometricsLocalizedReason:
-                                  "Authenticate to send transaction",
+                                      "Authenticate to send transaction",
                                   biometricsAuthenticationTitle:
-                                  "Confirm Transaction",
+                                      "Confirm Transaction",
                                 ),
                                 settings: const RouteSettings(
                                     name: "/confirmsendlockscreen"),
diff --git a/lib/pages/send_view/send_view.dart b/lib/pages/send_view/send_view.dart
index 191f12a15..6dc274464 100644
--- a/lib/pages/send_view/send_view.dart
+++ b/lib/pages/send_view/send_view.dart
@@ -13,7 +13,9 @@ import 'package:stackwallet/pages/send_view/sub_widgets/transaction_fee_selectio
 import 'package:stackwallet/providers/providers.dart';
 import 'package:stackwallet/providers/ui/fee_rate_type_state_provider.dart';
 import 'package:stackwallet/providers/ui/preview_tx_button_state_provider.dart';
+import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart';
 import 'package:stackwallet/route_generator.dart';
+import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
 import 'package:stackwallet/services/coins/manager.dart';
 import 'package:stackwallet/utilities/address_utils.dart';
 import 'package:stackwallet/utilities/assets.dart';
@@ -37,6 +39,8 @@ import 'package:stackwallet/widgets/stack_dialog.dart';
 import 'package:stackwallet/widgets/stack_text_field.dart';
 import 'package:stackwallet/widgets/textfield_icon_button.dart';
 
+import 'sub_widgets/firo_balance_selection_sheet.dart';
+
 class SendView extends ConsumerStatefulWidget {
   const SendView({
     Key? key,
@@ -82,6 +86,9 @@ class _SendViewState extends ConsumerState<SendView> {
   Decimal? _cachedAmountToSend;
   String? _address;
 
+  String? _privateBalanceString;
+  String? _publicBalanceString;
+
   bool _addressToggleFlag = false;
 
   bool _cryptoAmountChangeLock = false;
@@ -160,13 +167,26 @@ class _SendViewState extends ConsumerState<SendView> {
   late Future<String> _calculateFeesFuture;
 
   Map<int, String> cachedFees = {};
+  Map<int, String> cachedFiroPrivateFees = {};
+  Map<int, String> cachedFiroPublicFees = {};
 
   Future<String> calculateFees(int amount) async {
     if (amount <= 0) {
       return "0";
     }
 
-    if (cachedFees[amount] != null) {
+    if (coin == Coin.firo || coin == Coin.firoTestNet) {
+      if (ref.read(publicPrivateBalanceStateProvider.state).state ==
+          "Private") {
+        if (cachedFiroPrivateFees[amount] != null) {
+          return cachedFiroPrivateFees[amount]!;
+        }
+      } else {
+        if (cachedFiroPublicFees[amount] != null) {
+          return cachedFiroPublicFees[amount]!;
+        }
+      }
+    } else if (cachedFees[amount] != null) {
       return cachedFees[amount]!;
     }
 
@@ -188,12 +208,53 @@ class _SendViewState extends ConsumerState<SendView> {
         break;
     }
 
-    final fee = await manager.estimateFeeFor(amount, feeRate);
+    int fee;
 
-    cachedFees[amount] =
-        Format.satoshisToAmount(fee).toStringAsFixed(Constants.decimalPlaces);
+    if (coin == Coin.firo || coin == Coin.firoTestNet) {
+      if (ref.read(publicPrivateBalanceStateProvider.state).state ==
+          "Private") {
+        fee = await manager.estimateFeeFor(amount, feeRate);
 
-    return cachedFees[amount]!;
+        cachedFiroPrivateFees[amount] = Format.satoshisToAmount(fee)
+            .toStringAsFixed(Constants.decimalPlaces);
+
+        return cachedFiroPrivateFees[amount]!;
+      } else {
+        fee = await (manager.wallet as FiroWallet)
+            .estimateFeeForPublic(amount, feeRate);
+
+        cachedFiroPublicFees[amount] = Format.satoshisToAmount(fee)
+            .toStringAsFixed(Constants.decimalPlaces);
+
+        return cachedFiroPublicFees[amount]!;
+      }
+    } else {
+      fee = await manager.estimateFeeFor(amount, feeRate);
+      cachedFees[amount] =
+          Format.satoshisToAmount(fee).toStringAsFixed(Constants.decimalPlaces);
+
+      return cachedFees[amount]!;
+    }
+  }
+
+  Future<String?> _firoBalanceFuture(
+      ChangeNotifierProvider<Manager> provider, String locale) async {
+    final wallet = ref.read(provider).wallet as FiroWallet?;
+
+    if (wallet != null) {
+      Decimal? balance;
+      if (ref.read(publicPrivateBalanceStateProvider.state).state ==
+          "Private") {
+        balance = await wallet.availablePrivateBalance();
+      } else {
+        balance = await wallet.availablePublicBalance();
+      }
+
+      return Format.localizedStringAsFixed(
+          value: balance, locale: locale, decimalPlaces: 8);
+    }
+
+    return null;
   }
 
   @override
@@ -282,6 +343,22 @@ class _SendViewState extends ConsumerState<SendView> {
         .select((value) => value.getManagerProvider(walletId)));
     final String locale = ref.watch(
         localeServiceChangeNotifierProvider.select((value) => value.locale));
+
+    if (coin == Coin.firo || coin == Coin.firoTestNet) {
+      ref.listen(publicPrivateBalanceStateProvider, (previous, next) {
+        if (_amountToSend == null) {
+          setState(() {
+            _calculateFeesFuture = calculateFees(0);
+          });
+        } else {
+          setState(() {
+            _calculateFeesFuture =
+                calculateFees(Format.decimalAmountToSatoshis(_amountToSend!));
+          });
+        }
+      });
+    }
+
     return Scaffold(
       backgroundColor: CFColors.almostWhite,
       appBar: AppBar(
@@ -334,21 +411,59 @@ class _SendViewState extends ConsumerState<SendView> {
                               children: [
                                 SvgPicture.asset(
                                   Assets.svg.iconFor(coin: coin),
-                                  width: 18,
-                                  height: 18,
+                                  width: 22,
+                                  height: 22,
                                 ),
                                 const SizedBox(
                                   width: 6,
                                 ),
-                                Text(
-                                  ref.watch(provider
-                                      .select((value) => value.walletName)),
-                                  style: STextStyles.titleBold12,
-                                ),
+                                if (coin != Coin.firo &&
+                                    coin != Coin.firoTestNet)
+                                  Text(
+                                    ref.watch(provider
+                                        .select((value) => value.walletName)),
+                                    style: STextStyles.titleBold12,
+                                  ),
+                                if (coin == Coin.firo ||
+                                    coin == Coin.firoTestNet)
+                                  Column(
+                                    crossAxisAlignment:
+                                        CrossAxisAlignment.start,
+                                    children: [
+                                      Text(
+                                        ref.watch(provider.select(
+                                            (value) => value.walletName)),
+                                        style: STextStyles.titleBold12
+                                            .copyWith(fontSize: 14),
+                                      ),
+                                      // const SizedBox(
+                                      //   height: 2,
+                                      // ),
+                                      Text(
+                                        "${ref.watch(publicPrivateBalanceStateProvider.state).state} balance",
+                                        style: STextStyles.label
+                                            .copyWith(fontSize: 10),
+                                      ),
+                                    ],
+                                  ),
                                 const Spacer(),
                                 FutureBuilder(
-                                  future: ref.watch(provider.select(
-                                      (value) => value.availableBalance)),
+                                  future: (coin != Coin.firo &&
+                                          coin != Coin.firoTestNet)
+                                      ? ref.watch(provider.select(
+                                          (value) => value.availableBalance))
+                                      : ref
+                                                  .watch(
+                                                      publicPrivateBalanceStateProvider
+                                                          .state)
+                                                  .state ==
+                                              "Private"
+                                          ? (ref.watch(provider).wallet
+                                                  as FiroWallet)
+                                              .availablePrivateBalance()
+                                          : (ref.watch(provider).wallet
+                                                  as FiroWallet)
+                                              .availablePublicBalance(),
                                   builder:
                                       (_, AsyncSnapshot<Decimal> snapshot) {
                                     if (snapshot.connectionState ==
@@ -423,6 +538,9 @@ class _SendViewState extends ConsumerState<SendView> {
                                               fontSize: 10,
                                             ),
                                           ),
+                                          const SizedBox(
+                                            height: 2,
+                                          ),
                                           AnimatedText(
                                             stringsToLoopThrough: const [
                                               "Loading balance   ",
@@ -730,6 +848,141 @@ class _SendViewState extends ConsumerState<SendView> {
                             }
                           },
                         ),
+                        if (coin == Coin.firo)
+                          const SizedBox(
+                            height: 12,
+                          ),
+                        if (coin == Coin.firo)
+                          Text(
+                            "Send from",
+                            style: STextStyles.smallMed12,
+                            textAlign: TextAlign.left,
+                          ),
+                        if (coin == Coin.firo)
+                          const SizedBox(
+                            height: 8,
+                          ),
+                        if (coin == Coin.firo)
+                          Stack(
+                            children: [
+                              const TextField(
+                                readOnly: true,
+                                textInputAction: TextInputAction.none,
+                              ),
+                              Padding(
+                                padding: const EdgeInsets.symmetric(
+                                  horizontal: 12,
+                                ),
+                                child: RawMaterialButton(
+                                  splashColor: CFColors.splashLight,
+                                  shape: RoundedRectangleBorder(
+                                    borderRadius: BorderRadius.circular(
+                                      Constants.size.circularBorderRadius,
+                                    ),
+                                  ),
+                                  onPressed: () {
+                                    showModalBottomSheet<dynamic>(
+                                      backgroundColor: Colors.transparent,
+                                      context: context,
+                                      shape: const RoundedRectangleBorder(
+                                        borderRadius: BorderRadius.vertical(
+                                          top: Radius.circular(20),
+                                        ),
+                                      ),
+                                      builder: (_) => FiroBalanceSelectionSheet(
+                                        walletId: walletId,
+                                      ),
+                                    );
+                                  },
+                                  child: Row(
+                                    mainAxisAlignment:
+                                        MainAxisAlignment.spaceBetween,
+                                    children: [
+                                      Row(
+                                        children: [
+                                          Text(
+                                            "${ref.watch(publicPrivateBalanceStateProvider.state).state} balance",
+                                            style: STextStyles.itemSubtitle12,
+                                          ),
+                                          const SizedBox(
+                                            width: 10,
+                                          ),
+                                          FutureBuilder(
+                                            future: _firoBalanceFuture(
+                                                provider, locale),
+                                            builder: (context,
+                                                AsyncSnapshot<String?>
+                                                    snapshot) {
+                                              if (snapshot.connectionState ==
+                                                      ConnectionState.done &&
+                                                  snapshot.hasData) {
+                                                if (ref
+                                                        .read(
+                                                            publicPrivateBalanceStateProvider
+                                                                .state)
+                                                        .state ==
+                                                    "Private") {
+                                                  _privateBalanceString =
+                                                      snapshot.data!;
+                                                } else {
+                                                  _publicBalanceString =
+                                                      snapshot.data!;
+                                                }
+                                              }
+                                              if (ref
+                                                          .read(
+                                                              publicPrivateBalanceStateProvider
+                                                                  .state)
+                                                          .state ==
+                                                      "Private" &&
+                                                  _privateBalanceString !=
+                                                      null) {
+                                                return Text(
+                                                  "$_privateBalanceString ${coin.ticker}",
+                                                  style:
+                                                      STextStyles.itemSubtitle,
+                                                );
+                                              } else if (ref
+                                                          .read(
+                                                              publicPrivateBalanceStateProvider
+                                                                  .state)
+                                                          .state ==
+                                                      "Public" &&
+                                                  _publicBalanceString !=
+                                                      null) {
+                                                return Text(
+                                                  "$_publicBalanceString ${coin.ticker}",
+                                                  style:
+                                                      STextStyles.itemSubtitle,
+                                                );
+                                              } else {
+                                                return AnimatedText(
+                                                  stringsToLoopThrough: const [
+                                                    "Loading balance",
+                                                    "Loading balance.",
+                                                    "Loading balance..",
+                                                    "Loading balance...",
+                                                  ],
+                                                  style:
+                                                      STextStyles.itemSubtitle,
+                                                );
+                                              }
+                                            },
+                                          ),
+                                        ],
+                                      ),
+                                      SvgPicture.asset(
+                                        Assets.svg.chevronDown,
+                                        width: 8,
+                                        height: 4,
+                                        color: CFColors.gray3,
+                                      ),
+                                    ],
+                                  ),
+                                ),
+                              )
+                            ],
+                          ),
                         const SizedBox(
                           height: 12,
                         ),
@@ -744,10 +997,34 @@ class _SendViewState extends ConsumerState<SendView> {
                             BlueTextButton(
                               text: "Send all ${coin.ticker}",
                               onTap: () async {
-                                cryptoAmountController.text = (await ref
-                                        .read(provider)
-                                        .availableBalance)
-                                    .toStringAsFixed(Constants.decimalPlaces);
+                                if (coin == Coin.firo ||
+                                    coin == Coin.firoTestNet) {
+                                  final firoWallet =
+                                      ref.read(provider).wallet as FiroWallet;
+                                  if (ref
+                                          .read(
+                                              publicPrivateBalanceStateProvider
+                                                  .state)
+                                          .state ==
+                                      "Private") {
+                                    cryptoAmountController.text =
+                                        (await firoWallet
+                                                .availablePrivateBalance())
+                                            .toStringAsFixed(
+                                                Constants.decimalPlaces);
+                                  } else {
+                                    cryptoAmountController.text =
+                                        (await firoWallet
+                                                .availablePublicBalance())
+                                            .toStringAsFixed(
+                                                Constants.decimalPlaces);
+                                  }
+                                } else {
+                                  cryptoAmountController.text = (await ref
+                                          .read(provider)
+                                          .availableBalance)
+                                      .toStringAsFixed(Constants.decimalPlaces);
+                                }
                               },
                             ),
                           ],
@@ -973,74 +1250,126 @@ class _SendViewState extends ConsumerState<SendView> {
                                     Constants.size.circularBorderRadius,
                                   ),
                                 ),
-                                onPressed: () {
-                                  showModalBottomSheet<dynamic>(
-                                    backgroundColor: Colors.transparent,
-                                    context: context,
-                                    shape: const RoundedRectangleBorder(
-                                      borderRadius: BorderRadius.vertical(
-                                        top: Radius.circular(20),
+                                onPressed: (coin == Coin.firo ||
+                                            coin == Coin.firoTestNet) &&
+                                        ref
+                                                .watch(
+                                                    publicPrivateBalanceStateProvider
+                                                        .state)
+                                                .state ==
+                                            "Private"
+                                    ? null
+                                    : () {
+                                        showModalBottomSheet<dynamic>(
+                                          backgroundColor: Colors.transparent,
+                                          context: context,
+                                          shape: const RoundedRectangleBorder(
+                                            borderRadius: BorderRadius.vertical(
+                                              top: Radius.circular(20),
+                                            ),
+                                          ),
+                                          builder: (_) =>
+                                              TransactionFeeSelectionSheet(
+                                            walletId: walletId,
+                                            amount: Decimal.tryParse(
+                                                    cryptoAmountController
+                                                        .text) ??
+                                                Decimal.zero,
+                                          ),
+                                        );
+                                      },
+                                child: ((coin == Coin.firo ||
+                                            coin == Coin.firoTestNet) &&
+                                        ref
+                                                .watch(
+                                                    publicPrivateBalanceStateProvider
+                                                        .state)
+                                                .state ==
+                                            "Private")
+                                    ? Row(
+                                        children: [
+                                          FutureBuilder(
+                                            future: _calculateFeesFuture,
+                                            builder: (context, snapshot) {
+                                              if (snapshot.connectionState ==
+                                                      ConnectionState.done &&
+                                                  snapshot.hasData) {
+                                                return Text(
+                                                  "~${snapshot.data! as String} ${coin.ticker}",
+                                                  style:
+                                                      STextStyles.itemSubtitle,
+                                                );
+                                              } else {
+                                                return AnimatedText(
+                                                  stringsToLoopThrough: const [
+                                                    "Calculating",
+                                                    "Calculating.",
+                                                    "Calculating..",
+                                                    "Calculating...",
+                                                  ],
+                                                  style:
+                                                      STextStyles.itemSubtitle,
+                                                );
+                                              }
+                                            },
+                                          ),
+                                        ],
+                                      )
+                                    : Row(
+                                        mainAxisAlignment:
+                                            MainAxisAlignment.spaceBetween,
+                                        children: [
+                                          Row(
+                                            children: [
+                                              Text(
+                                                ref
+                                                    .watch(
+                                                        feeRateTypeStateProvider
+                                                            .state)
+                                                    .state
+                                                    .prettyName,
+                                                style:
+                                                    STextStyles.itemSubtitle12,
+                                              ),
+                                              const SizedBox(
+                                                width: 10,
+                                              ),
+                                              FutureBuilder(
+                                                future: _calculateFeesFuture,
+                                                builder: (context, snapshot) {
+                                                  if (snapshot.connectionState ==
+                                                          ConnectionState
+                                                              .done &&
+                                                      snapshot.hasData) {
+                                                    return Text(
+                                                      "~${snapshot.data! as String} ${coin.ticker}",
+                                                      style: STextStyles
+                                                          .itemSubtitle,
+                                                    );
+                                                  } else {
+                                                    return AnimatedText(
+                                                      stringsToLoopThrough: const [
+                                                        "Calculating",
+                                                        "Calculating.",
+                                                        "Calculating..",
+                                                        "Calculating...",
+                                                      ],
+                                                      style: STextStyles
+                                                          .itemSubtitle,
+                                                    );
+                                                  }
+                                                },
+                                              ),
+                                            ],
+                                          ),
+                                          SvgPicture.asset(
+                                            Assets.svg.chevronDown,
+                                            width: 8,
+                                            height: 4,
+                                            color: CFColors.gray3,
+                                          ),
+                                        ],
                                       ),
-                                    ),
-                                    builder: (_) =>
-                                        TransactionFeeSelectionSheet(
-                                      walletId: walletId,
-                                      amount: Decimal.tryParse(
-                                              cryptoAmountController.text) ??
-                                          Decimal.zero,
-                                    ),
-                                  );
-                                },
-                                child: Row(
-                                  mainAxisAlignment:
-                                      MainAxisAlignment.spaceBetween,
-                                  children: [
-                                    Row(
-                                      children: [
-                                        Text(
-                                          ref
-                                              .watch(feeRateTypeStateProvider
-                                                  .state)
-                                              .state
-                                              .prettyName,
-                                          style: STextStyles.itemSubtitle12,
-                                        ),
-                                        const SizedBox(
-                                          width: 10,
-                                        ),
-                                        FutureBuilder(
-                                          future: _calculateFeesFuture,
-                                          builder: (context, snapshot) {
-                                            if (snapshot.connectionState ==
-                                                    ConnectionState.done &&
-                                                snapshot.hasData) {
-                                              return Text(
-                                                "~${snapshot.data! as String} ${coin.ticker}",
-                                                style: STextStyles.itemSubtitle,
-                                              );
-                                            } else {
-                                              return AnimatedText(
-                                                stringsToLoopThrough: const [
-                                                  "Calculating",
-                                                  "Calculating.",
-                                                  "Calculating..",
-                                                  "Calculating...",
-                                                ],
-                                                style: STextStyles.itemSubtitle,
-                                              );
-                                            }
-                                          },
-                                        ),
-                                      ],
-                                    ),
-                                    SvgPicture.asset(
-                                      Assets.svg.chevronDown,
-                                      width: 8,
-                                      height: 4,
-                                      color: CFColors.gray3,
-                                    ),
-                                  ],
-                                ),
                               ),
                             )
                           ],
@@ -1106,9 +1435,32 @@ class _SendViewState extends ConsumerState<SendView> {
 
                                   final amount = Format.decimalAmountToSatoshis(
                                       _amountToSend!);
-                                  final availableBalance =
-                                      Format.decimalAmountToSatoshis(
-                                          await manager.availableBalance);
+                                  int availableBalance;
+                                  if ((coin == Coin.firo ||
+                                      coin == Coin.firoTestNet)) {
+                                    if (ref
+                                            .read(
+                                                publicPrivateBalanceStateProvider
+                                                    .state)
+                                            .state ==
+                                        "Private") {
+                                      availableBalance =
+                                          Format.decimalAmountToSatoshis(
+                                              await (manager.wallet
+                                                      as FiroWallet)
+                                                  .availablePrivateBalance());
+                                    } else {
+                                      availableBalance =
+                                          Format.decimalAmountToSatoshis(
+                                              await (manager.wallet
+                                                      as FiroWallet)
+                                                  .availablePublicBalance());
+                                    }
+                                  } else {
+                                    availableBalance =
+                                        Format.decimalAmountToSatoshis(
+                                            await manager.availableBalance);
+                                  }
 
                                   // confirm send all
                                   if (amount == availableBalance) {
@@ -1192,14 +1544,36 @@ class _SendViewState extends ConsumerState<SendView> {
                                       },
                                     ));
 
-                                    final txData = await manager.prepareSend(
-                                      address: _address!,
-                                      satoshiAmount: amount,
-                                      args: {
-                                        "feeRate":
-                                            ref.read(feeRateTypeStateProvider)
-                                      },
-                                    );
+                                    Map<String, dynamic> txData;
+
+                                    if ((coin == Coin.firo ||
+                                            coin == Coin.firoTestNet) &&
+                                        ref
+                                                .read(
+                                                    publicPrivateBalanceStateProvider
+                                                        .state)
+                                                .state !=
+                                            "Private") {
+                                      txData =
+                                          await (manager.wallet as FiroWallet)
+                                              .prepareSendPublic(
+                                        address: _address!,
+                                        satoshiAmount: amount,
+                                        args: {
+                                          "feeRate":
+                                              ref.read(feeRateTypeStateProvider)
+                                        },
+                                      );
+                                    } else {
+                                      txData = await manager.prepareSend(
+                                        address: _address!,
+                                        satoshiAmount: amount,
+                                        args: {
+                                          "feeRate":
+                                              ref.read(feeRateTypeStateProvider)
+                                        },
+                                      );
+                                    }
 
                                     if (!wasCancelled && mounted) {
                                       // pop building dialog
diff --git a/lib/pages/send_view/sub_widgets/firo_balance_selection_sheet.dart b/lib/pages/send_view/sub_widgets/firo_balance_selection_sheet.dart
new file mode 100644
index 000000000..8cb1e64dd
--- /dev/null
+++ b/lib/pages/send_view/sub_widgets/firo_balance_selection_sheet.dart
@@ -0,0 +1,287 @@
+import 'package:decimal/decimal.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:stackwallet/providers/providers.dart';
+import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart';
+import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
+import 'package:stackwallet/utilities/cfcolors.dart';
+import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/widgets/animated_text.dart';
+
+class FiroBalanceSelectionSheet extends ConsumerStatefulWidget {
+  const FiroBalanceSelectionSheet({
+    Key? key,
+    required this.walletId,
+  }) : super(key: key);
+
+  final String walletId;
+
+  @override
+  ConsumerState<FiroBalanceSelectionSheet> createState() =>
+      _FiroBalanceSelectionSheetState();
+}
+
+class _FiroBalanceSelectionSheetState
+    extends ConsumerState<FiroBalanceSelectionSheet> {
+  late final String walletId;
+
+  final stringsToLoopThrough = [
+    "Loading balance",
+    "Loading balance.",
+    "Loading balance..",
+    "Loading balance...",
+  ];
+
+  @override
+  void initState() {
+    walletId = widget.walletId;
+    super.initState();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    debugPrint("BUILD: $runtimeType");
+
+    final manager = ref.watch(walletsChangeNotifierProvider
+        .select((value) => value.getManager(walletId)));
+    final firoWallet = manager.wallet as FiroWallet;
+
+    return Container(
+      decoration: const BoxDecoration(
+        color: CFColors.white,
+        borderRadius: BorderRadius.vertical(
+          top: Radius.circular(20),
+        ),
+      ),
+      child: Padding(
+        padding: const EdgeInsets.only(
+          left: 24,
+          right: 24,
+          top: 10,
+          bottom: 0,
+        ),
+        child: Column(
+          mainAxisSize: MainAxisSize.min,
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            Center(
+              child: Container(
+                decoration: BoxDecoration(
+                  color: CFColors.fieldGray,
+                  borderRadius: BorderRadius.circular(
+                    Constants.size.circularBorderRadius,
+                  ),
+                ),
+                width: 60,
+                height: 4,
+              ),
+            ),
+            const SizedBox(
+              height: 36,
+            ),
+            Column(
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [
+                Text(
+                  "Select balance",
+                  style: STextStyles.pageTitleH2,
+                  textAlign: TextAlign.left,
+                ),
+                const SizedBox(
+                  height: 16,
+                ),
+                GestureDetector(
+                  onTap: () {
+                    final state =
+                        ref.read(publicPrivateBalanceStateProvider.state).state;
+                    if (state != "Private") {
+                      ref.read(publicPrivateBalanceStateProvider.state).state =
+                          "Private";
+                    }
+                    Navigator.of(context).pop();
+                  },
+                  child: Container(
+                    color: Colors.transparent,
+                    child: Row(
+                      crossAxisAlignment: CrossAxisAlignment.start,
+                      children: [
+                        Column(
+                          mainAxisAlignment: MainAxisAlignment.start,
+                          children: [
+                            SizedBox(
+                              width: 20,
+                              height: 20,
+                              child: Radio(
+                                activeColor: CFColors.link2,
+                                value: "Private",
+                                groupValue: ref
+                                    .watch(
+                                        publicPrivateBalanceStateProvider.state)
+                                    .state,
+                                onChanged: (x) {
+                                  ref
+                                      .read(publicPrivateBalanceStateProvider
+                                          .state)
+                                      .state = "Private";
+
+                                  Navigator.of(context).pop();
+                                },
+                              ),
+                            ),
+                          ],
+                        ),
+                        const SizedBox(
+                          width: 12,
+                        ),
+                        Flexible(
+                          child: Column(
+                            crossAxisAlignment: CrossAxisAlignment.start,
+                            children: [
+                              // Row(
+                              //   children: [
+                              Text(
+                                "Private balance",
+                                style: STextStyles.titleBold12.copyWith(
+                                  color: const Color(0xFF44464E),
+                                ),
+                                textAlign: TextAlign.left,
+                              ),
+                              const SizedBox(
+                                width: 2,
+                              ),
+                              FutureBuilder(
+                                future: firoWallet.availablePrivateBalance(),
+                                builder:
+                                    (context, AsyncSnapshot<Decimal> snapshot) {
+                                  if (snapshot.connectionState ==
+                                          ConnectionState.done &&
+                                      snapshot.hasData) {
+                                    return Text(
+                                      "${snapshot.data!} ${manager.coin.ticker}",
+                                      style: STextStyles.itemSubtitle,
+                                      textAlign: TextAlign.left,
+                                    );
+                                  } else {
+                                    return AnimatedText(
+                                      stringsToLoopThrough:
+                                          stringsToLoopThrough,
+                                      style: STextStyles.itemSubtitle,
+                                    );
+                                  }
+                                },
+                              )
+                            ],
+                          ),
+                          //   ],
+                          // ),
+                        )
+                      ],
+                    ),
+                  ),
+                ),
+                const SizedBox(
+                  height: 16,
+                ),
+                GestureDetector(
+                  onTap: () {
+                    final state =
+                        ref.read(publicPrivateBalanceStateProvider.state).state;
+                    if (state != "Public") {
+                      ref.read(publicPrivateBalanceStateProvider.state).state =
+                          "Public";
+                    }
+                    Navigator.of(context).pop();
+                  },
+                  child: Container(
+                    color: Colors.transparent,
+                    child: Row(
+                      crossAxisAlignment: CrossAxisAlignment.start,
+                      children: [
+                        Column(
+                          children: [
+                            SizedBox(
+                              width: 20,
+                              height: 20,
+                              child: Radio(
+                                activeColor: CFColors.link2,
+                                value: "Public",
+                                groupValue: ref
+                                    .watch(
+                                        publicPrivateBalanceStateProvider.state)
+                                    .state,
+                                onChanged: (x) {
+                                  ref
+                                      .read(publicPrivateBalanceStateProvider
+                                          .state)
+                                      .state = "Public";
+                                  Navigator.of(context).pop();
+                                },
+                              ),
+                            ),
+                          ],
+                        ),
+                        const SizedBox(
+                          width: 12,
+                        ),
+                        Flexible(
+                          child: Column(
+                            crossAxisAlignment: CrossAxisAlignment.start,
+                            children: [
+                              // Row(
+                              //   children: [
+                              Text(
+                                "Public balance",
+                                style: STextStyles.titleBold12.copyWith(
+                                  color: const Color(0xFF44464E),
+                                ),
+                                textAlign: TextAlign.left,
+                              ),
+                              const SizedBox(
+                                width: 2,
+                              ),
+                              FutureBuilder(
+                                future: firoWallet.availablePublicBalance(),
+                                builder:
+                                    (context, AsyncSnapshot<Decimal> snapshot) {
+                                  if (snapshot.connectionState ==
+                                          ConnectionState.done &&
+                                      snapshot.hasData) {
+                                    return Text(
+                                      "${snapshot.data!} ${manager.coin.ticker}",
+                                      style: STextStyles.itemSubtitle,
+                                      textAlign: TextAlign.left,
+                                    );
+                                  } else {
+                                    return AnimatedText(
+                                      stringsToLoopThrough:
+                                          stringsToLoopThrough,
+                                      style: STextStyles.itemSubtitle,
+                                    );
+                                  }
+                                },
+                              )
+                              //   ],
+                              // ),
+                            ],
+                          ),
+                        ),
+                      ],
+                    ),
+                  ),
+                ),
+                const SizedBox(
+                  height: 16,
+                ),
+                const SizedBox(
+                  height: 24,
+                ),
+              ],
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart b/lib/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart
index 9a214bfab..4eca34f3d 100644
--- a/lib/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart
+++ b/lib/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart
@@ -4,6 +4,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:stackwallet/models/paymint/fee_object_model.dart';
 import 'package:stackwallet/providers/providers.dart';
 import 'package:stackwallet/providers/ui/fee_rate_type_state_provider.dart';
+import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart';
+import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
 import 'package:stackwallet/utilities/cfcolors.dart';
 import 'package:stackwallet/utilities/constants.dart';
 import 'package:stackwallet/utilities/enums/coin_enum.dart';
@@ -58,35 +60,63 @@ class _TransactionFeeSelectionSheetState
     required int amount,
     required FeeRateType feeRateType,
     required int feeRate,
+    required Coin coin,
   }) async {
     switch (feeRateType) {
       case FeeRateType.fast:
         if (ref.read(feeSheetSessionCacheProvider).fast[amount] == null) {
-          ref.read(feeSheetSessionCacheProvider).fast[amount] =
-              Format.satoshisToAmount(await ref
-                  .read(walletsChangeNotifierProvider)
-                  .getManager(walletId)
-                  .estimateFeeFor(amount, feeRate));
+          final manager =
+              ref.read(walletsChangeNotifierProvider).getManager(walletId);
+
+          if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
+              ref.read(publicPrivateBalanceStateProvider.state).state !=
+                  "Private") {
+            ref.read(feeSheetSessionCacheProvider).fast[amount] =
+                Format.satoshisToAmount(await (manager.wallet as FiroWallet)
+                    .estimateFeeForPublic(amount, feeRate));
+          } else {
+            ref.read(feeSheetSessionCacheProvider).fast[amount] =
+                Format.satoshisToAmount(
+                    await manager.estimateFeeFor(amount, feeRate));
+          }
         }
         return ref.read(feeSheetSessionCacheProvider).fast[amount]!;
 
       case FeeRateType.average:
         if (ref.read(feeSheetSessionCacheProvider).average[amount] == null) {
-          ref.read(feeSheetSessionCacheProvider).average[amount] =
-              Format.satoshisToAmount(await ref
-                  .read(walletsChangeNotifierProvider)
-                  .getManager(walletId)
-                  .estimateFeeFor(amount, feeRate));
+          final manager =
+              ref.read(walletsChangeNotifierProvider).getManager(walletId);
+
+          if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
+              ref.read(publicPrivateBalanceStateProvider.state).state !=
+                  "Private") {
+            ref.read(feeSheetSessionCacheProvider).average[amount] =
+                Format.satoshisToAmount(await (manager.wallet as FiroWallet)
+                    .estimateFeeForPublic(amount, feeRate));
+          } else {
+            ref.read(feeSheetSessionCacheProvider).average[amount] =
+                Format.satoshisToAmount(
+                    await manager.estimateFeeFor(amount, feeRate));
+          }
         }
         return ref.read(feeSheetSessionCacheProvider).average[amount]!;
 
       case FeeRateType.slow:
         if (ref.read(feeSheetSessionCacheProvider).slow[amount] == null) {
-          ref.read(feeSheetSessionCacheProvider).slow[amount] =
-              Format.satoshisToAmount(await ref
-                  .read(walletsChangeNotifierProvider)
-                  .getManager(walletId)
-                  .estimateFeeFor(amount, feeRate));
+          final manager =
+              ref.read(walletsChangeNotifierProvider).getManager(walletId);
+
+          if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
+              ref.read(publicPrivateBalanceStateProvider.state).state !=
+                  "Private") {
+            ref.read(feeSheetSessionCacheProvider).slow[amount] =
+                Format.satoshisToAmount(await (manager.wallet as FiroWallet)
+                    .estimateFeeForPublic(amount, feeRate));
+          } else {
+            ref.read(feeSheetSessionCacheProvider).slow[amount] =
+                Format.satoshisToAmount(
+                    await manager.estimateFeeFor(amount, feeRate));
+          }
         }
         return ref.read(feeSheetSessionCacheProvider).slow[amount]!;
     }
@@ -249,6 +279,7 @@ class _TransactionFeeSelectionSheetState
                                       if (feeObject != null)
                                         FutureBuilder(
                                           future: feeFor(
+                                              coin: manager.coin,
                                               feeRateType: FeeRateType.fast,
                                               feeRate: feeObject!.fast,
                                               amount: Format
@@ -372,6 +403,7 @@ class _TransactionFeeSelectionSheetState
                                       if (feeObject != null)
                                         FutureBuilder(
                                           future: feeFor(
+                                              coin: manager.coin,
                                               feeRateType: FeeRateType.fast,
                                               feeRate: feeObject!.fast,
                                               amount: Format
@@ -496,6 +528,7 @@ class _TransactionFeeSelectionSheetState
                                       if (feeObject != null)
                                         FutureBuilder(
                                           future: feeFor(
+                                              coin: manager.coin,
                                               feeRateType: FeeRateType.slow,
                                               feeRate: feeObject!.slow,
                                               amount: Format
diff --git a/lib/pages/settings_views/global_settings_view/hidden_settings.dart b/lib/pages/settings_views/global_settings_view/hidden_settings.dart
index 0fa57db88..43929b94f 100644
--- a/lib/pages/settings_views/global_settings_view/hidden_settings.dart
+++ b/lib/pages/settings_views/global_settings_view/hidden_settings.dart
@@ -1,15 +1,14 @@
+import 'dart:async';
+
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:lottie/lottie.dart';
 import 'package:stackwallet/notifications/show_flush_bar.dart';
 import 'package:stackwallet/providers/global/debug_service_provider.dart';
 import 'package:stackwallet/providers/providers.dart';
-import 'package:stackwallet/utilities/assets.dart';
 import 'package:stackwallet/utilities/cfcolors.dart';
 import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
 import 'package:stackwallet/utilities/text_styles.dart';
 import 'package:stackwallet/widgets/rounded_white_container.dart';
-import 'package:stackwallet/widgets/stack_dialog.dart';
 
 class HiddenSettings extends StatelessWidget {
   const HiddenSettings({Key? key}) : super(key: key);
@@ -55,11 +54,11 @@ class HiddenSettings extends StatelessWidget {
                                 .read(notificationsProvider)
                                 .delete(notifs[0], true);
 
-                            showFloatingFlushBar(
+                            unawaited(showFloatingFlushBar(
                               type: FlushBarType.success,
                               message: "Notification history deleted",
                               context: context,
-                            );
+                            ));
                           },
                           child: RoundedWhiteContainer(
                             child: Text(
@@ -109,11 +108,11 @@ class HiddenSettings extends StatelessWidget {
                                 .read(debugServiceProvider)
                                 .deleteAllMessages();
 
-                            showFloatingFlushBar(
+                            unawaited(showFloatingFlushBar(
                               type: FlushBarType.success,
                               message: "Debug Logs deleted",
                               context: context,
-                            );
+                            ));
                           },
                           child: RoundedWhiteContainer(
                             child: Text(
@@ -125,34 +124,34 @@ class HiddenSettings extends StatelessWidget {
                           ),
                         );
                       }),
-                      const SizedBox(
-                        height: 12,
-                      ),
-                      GestureDetector(
-                        onTap: () async {
-                          showDialog<void>(
-                            context: context,
-                            builder: (_) {
-                              return StackDialogBase(
-                                child: SizedBox(
-                                  width: 200,
-                                  child: Lottie.asset(
-                                    Assets.lottie.test2,
-                                  ),
-                                ),
-                              );
-                            },
-                          );
-                        },
-                        child: RoundedWhiteContainer(
-                          child: Text(
-                            "Lottie test",
-                            style: STextStyles.button.copyWith(
-                              color: CFColors.stackAccent,
-                            ),
-                          ),
-                        ),
-                      ),
+                      // const SizedBox(
+                      //   height: 12,
+                      // ),
+                      // GestureDetector(
+                      //   onTap: () async {
+                      //     showDialog<void>(
+                      //       context: context,
+                      //       builder: (_) {
+                      //         return StackDialogBase(
+                      //           child: SizedBox(
+                      //             width: 200,
+                      //             child: Lottie.asset(
+                      //               Assets.lottie.test2,
+                      //             ),
+                      //           ),
+                      //         );
+                      //       },
+                      //     );
+                      //   },
+                      //   child: RoundedWhiteContainer(
+                      //     child: Text(
+                      //       "Lottie test",
+                      //       style: STextStyles.button.copyWith(
+                      //         color: CFColors.stackAccent,
+                      //       ),
+                      //     ),
+                      //   ),
+                      // ),
                     ],
                   ),
                 ),
diff --git a/lib/pages/wallet_view/sub_widgets/transactions_list.dart b/lib/pages/wallet_view/sub_widgets/transactions_list.dart
index 4b9fdd985..efc3e74e5 100644
--- a/lib/pages/wallet_view/sub_widgets/transactions_list.dart
+++ b/lib/pages/wallet_view/sub_widgets/transactions_list.dart
@@ -1,3 +1,5 @@
+import 'dart:async';
+
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:stackwallet/models/paymint/transactions_model.dart';
@@ -110,7 +112,7 @@ class _TransactionsListState extends ConsumerState<TransactionsList> {
                   .read(walletsChangeNotifierProvider)
                   .getManagerProvider(widget.walletId);
               if (!ref.read(managerProvider).isRefreshing) {
-                ref.read(managerProvider).refresh();
+                unawaited(ref.read(managerProvider).refresh());
               }
             },
             child: ListView.builder(
diff --git a/lib/pages/wallet_view/sub_widgets/tx_icon.dart b/lib/pages/wallet_view/sub_widgets/tx_icon.dart
index 1ae231930..45b4e610d 100644
--- a/lib/pages/wallet_view/sub_widgets/tx_icon.dart
+++ b/lib/pages/wallet_view/sub_widgets/tx_icon.dart
@@ -10,6 +10,16 @@ class TxIcon extends StatelessWidget {
   static const Size size = Size(32, 32);
 
   String _getAssetName(bool isCancelled, bool isReceived, bool isPending) {
+    if (!isReceived && transaction.subType == "mint") {
+      if (isCancelled) {
+        return Assets.svg.anonymizeFailed;
+      }
+      if (isPending) {
+        return Assets.svg.anonymizePending;
+      }
+      return Assets.svg.anonymize;
+    }
+
     if (isReceived) {
       if (isCancelled) {
         return Assets.svg.receiveCancelled;
diff --git a/lib/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart b/lib/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart
index e65133f4e..1d51aa74d 100644
--- a/lib/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart
+++ b/lib/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart
@@ -1,8 +1,10 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:stackwallet/providers/providers.dart';
 import 'package:stackwallet/providers/wallet/wallet_balance_toggle_state_provider.dart';
 import 'package:stackwallet/utilities/cfcolors.dart';
 import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
 import 'package:stackwallet/utilities/enums/wallet_balance_toggle_state.dart';
 import 'package:stackwallet/utilities/text_styles.dart';
 
@@ -18,6 +20,9 @@ class WalletBalanceToggleSheet extends ConsumerWidget {
   Widget build(BuildContext context, WidgetRef ref) {
     final maxHeight = MediaQuery.of(context).size.height * 0.60;
 
+    final coin = ref.watch(walletsChangeNotifierProvider
+        .select((value) => value.getManager(walletId).coin));
+
     return Container(
       decoration: const BoxDecoration(
         color: CFColors.white,
@@ -105,25 +110,44 @@ class WalletBalanceToggleSheet extends ConsumerWidget {
                       const SizedBox(
                         width: 12,
                       ),
-                      Column(
-                        crossAxisAlignment: CrossAxisAlignment.start,
-                        children: [
-                          Text(
-                            "Available balance",
-                            style: STextStyles.titleBold12,
-                          ),
-                          const SizedBox(
-                            height: 2,
-                          ),
-                          // TODO need text from design
-                          Text(
-                            "Current spendable (unlocked) balance",
-                            style: STextStyles.itemSubtitle12.copyWith(
-                              color: CFColors.neutral60,
+                      if (coin != Coin.firo && coin != Coin.firoTestNet)
+                        Column(
+                          crossAxisAlignment: CrossAxisAlignment.start,
+                          children: [
+                            Text(
+                              "Available balance",
+                              style: STextStyles.titleBold12,
                             ),
-                          ),
-                        ],
-                      ),
+                            const SizedBox(
+                              height: 2,
+                            ),
+                            Text(
+                              "Current spendable (unlocked) balance",
+                              style: STextStyles.itemSubtitle12.copyWith(
+                                color: CFColors.neutral60,
+                              ),
+                            ),
+                          ],
+                        ),
+                      if (coin == Coin.firo || coin == Coin.firoTestNet)
+                        Column(
+                          crossAxisAlignment: CrossAxisAlignment.start,
+                          children: [
+                            Text(
+                              "Private balance",
+                              style: STextStyles.titleBold12,
+                            ),
+                            const SizedBox(
+                              height: 2,
+                            ),
+                            Text(
+                              "Current private spendable (unlocked) balance",
+                              style: STextStyles.itemSubtitle12.copyWith(
+                                color: CFColors.neutral60,
+                              ),
+                            ),
+                          ],
+                        ),
                     ],
                   ),
                 ),
@@ -172,25 +196,44 @@ class WalletBalanceToggleSheet extends ConsumerWidget {
                       const SizedBox(
                         width: 12,
                       ),
-                      Column(
-                        crossAxisAlignment: CrossAxisAlignment.start,
-                        children: [
-                          Text(
-                            "Full balance",
-                            style: STextStyles.titleBold12,
-                          ),
-                          const SizedBox(
-                            height: 2,
-                          ),
-                          // TODO need text from design
-                          Text(
-                            "Total wallet balance",
-                            style: STextStyles.itemSubtitle12.copyWith(
-                              color: CFColors.neutral60,
+                      if (coin != Coin.firo && coin != Coin.firoTestNet)
+                        Column(
+                          crossAxisAlignment: CrossAxisAlignment.start,
+                          children: [
+                            Text(
+                              "Full balance",
+                              style: STextStyles.titleBold12,
                             ),
-                          ),
-                        ],
-                      ),
+                            const SizedBox(
+                              height: 2,
+                            ),
+                            Text(
+                              "Total wallet balance",
+                              style: STextStyles.itemSubtitle12.copyWith(
+                                color: CFColors.neutral60,
+                              ),
+                            ),
+                          ],
+                        ),
+                      if (coin == Coin.firo || coin == Coin.firoTestNet)
+                        Column(
+                          crossAxisAlignment: CrossAxisAlignment.start,
+                          children: [
+                            Text(
+                              "Public balance",
+                              style: STextStyles.titleBold12,
+                            ),
+                            const SizedBox(
+                              height: 2,
+                            ),
+                            Text(
+                              "Current public spendable (unlocked) balance",
+                              style: STextStyles.itemSubtitle12.copyWith(
+                                color: CFColors.neutral60,
+                              ),
+                            ),
+                          ],
+                        ),
                     ],
                   ),
                 ),
diff --git a/lib/pages/wallet_view/sub_widgets/wallet_summary_info.dart b/lib/pages/wallet_view/sub_widgets/wallet_summary_info.dart
index b45caa3bc..8687e8a59 100644
--- a/lib/pages/wallet_view/sub_widgets/wallet_summary_info.dart
+++ b/lib/pages/wallet_view/sub_widgets/wallet_summary_info.dart
@@ -6,6 +6,7 @@ import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_balance_toggle_
 import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_refresh_button.dart';
 import 'package:stackwallet/providers/providers.dart';
 import 'package:stackwallet/providers/wallet/wallet_balance_toggle_state_provider.dart';
+import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
 import 'package:stackwallet/services/coins/manager.dart';
 import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
 import 'package:stackwallet/utilities/assets.dart';
@@ -67,15 +68,25 @@ class _WalletSummaryInfoState extends State<WalletSummaryInfo> {
         Expanded(
           child: Consumer(
             builder: (_, ref, __) {
-              final totalBalanceFuture = ref
-                  .watch(managerProvider.select((value) => value.totalBalance));
-
-              final availableBalanceFuture = ref.watch(
-                  managerProvider.select((value) => value.availableBalance));
-
               final Coin coin =
                   ref.watch(managerProvider.select((value) => value.coin));
 
+              Future<Decimal>? totalBalanceFuture;
+              Future<Decimal>? availableBalanceFuture;
+              if (coin == Coin.firo || coin == Coin.firoTestNet) {
+                final firoWallet =
+                    ref.watch(managerProvider.select((value) => value.wallet))
+                        as FiroWallet;
+                totalBalanceFuture = firoWallet.availablePublicBalance();
+                availableBalanceFuture = firoWallet.availablePrivateBalance();
+              } else {
+                totalBalanceFuture = ref.watch(
+                    managerProvider.select((value) => value.totalBalance));
+
+                availableBalanceFuture = ref.watch(
+                    managerProvider.select((value) => value.availableBalance));
+              }
+
               final locale = ref.watch(localeServiceChangeNotifierProvider
                   .select((value) => value.locale));
 
@@ -114,12 +125,20 @@ class _WalletSummaryInfoState extends State<WalletSummaryInfo> {
                           onTap: showSheet,
                           child: Row(
                             children: [
-                              Text(
-                                "${_showAvailable ? "Available" : "Full"} Balance",
-                                style: STextStyles.subtitle.copyWith(
-                                  fontWeight: FontWeight.w500,
+                              if (coin == Coin.firo || coin == Coin.firoTestNet)
+                                Text(
+                                  "${_showAvailable ? "Private" : "Public"} Balance",
+                                  style: STextStyles.subtitle.copyWith(
+                                    fontWeight: FontWeight.w500,
+                                  ),
+                                ),
+                              if (coin != Coin.firo && coin != Coin.firoTestNet)
+                                Text(
+                                  "${_showAvailable ? "Available" : "Full"} Balance",
+                                  style: STextStyles.subtitle.copyWith(
+                                    fontWeight: FontWeight.w500,
+                                  ),
                                 ),
-                              ),
                               const SizedBox(
                                 width: 4,
                               ),
@@ -166,12 +185,20 @@ class _WalletSummaryInfoState extends State<WalletSummaryInfo> {
                           onTap: showSheet,
                           child: Row(
                             children: [
-                              Text(
-                                "${_showAvailable ? "Available" : "Full"} Balance",
-                                style: STextStyles.subtitle.copyWith(
-                                  fontWeight: FontWeight.w500,
+                              if (coin == Coin.firo || coin == Coin.firoTestNet)
+                                Text(
+                                  "${_showAvailable ? "Private" : "Public"} Balance",
+                                  style: STextStyles.subtitle.copyWith(
+                                    fontWeight: FontWeight.w500,
+                                  ),
+                                ),
+                              if (coin != Coin.firo && coin != Coin.firoTestNet)
+                                Text(
+                                  "${_showAvailable ? "Available" : "Full"} Balance",
+                                  style: STextStyles.subtitle.copyWith(
+                                    fontWeight: FontWeight.w500,
+                                  ),
                                 ),
-                              ),
                               const SizedBox(
                                 width: 4,
                               ),
diff --git a/lib/pages/wallet_view/transaction_views/transaction_details_view.dart b/lib/pages/wallet_view/transaction_views/transaction_details_view.dart
index 7d410479a..3bed97db6 100644
--- a/lib/pages/wallet_view/transaction_views/transaction_details_view.dart
+++ b/lib/pages/wallet_view/transaction_views/transaction_details_view.dart
@@ -1,3 +1,5 @@
+import 'dart:async';
+
 import 'package:decimal/decimal.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
@@ -67,13 +69,19 @@ class _TransactionDetailsViewState
     coin = widget.coin;
     amount = Format.satoshisToAmount(_transaction.amount);
     fee = Format.satoshisToAmount(_transaction.fees);
-    amountPrefix = _transaction.txType.toLowerCase() == "sent" ? "- " : "+ ";
 
-    if (coin == Coin.firo || coin == Coin.firoTestNet) {
-      showFeePending = true;
+    if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
+        _transaction.subType == "mint") {
+      amountPrefix = "";
     } else {
-      showFeePending = false;
+      amountPrefix = _transaction.txType.toLowerCase() == "sent" ? "- " : "+ ";
     }
+
+    // if (coin == Coin.firo || coin == Coin.firoTestNet) {
+    //   showFeePending = true;
+    // } else {
+    //   showFeePending = false;
+    // }
     super.initState();
   }
 
@@ -83,10 +91,21 @@ class _TransactionDetailsViewState
   }
 
   String whatIsIt(String type) {
+    if (coin == Coin.firo || coin == Coin.firoTestNet) {
+      if (_transaction.subType == "mint") {
+        if (_transaction.confirmedStatus) {
+          return "Minted";
+        } else {
+          return "Minting";
+        }
+      }
+    }
+
     if (type == "Received") {
-      if (_transaction.isMinting) {
-        return "Minting";
-      } else if (_transaction.confirmedStatus) {
+      // if (_transaction.isMinting) {
+      //   return "Minting";
+      // } else
+      if (_transaction.confirmedStatus) {
         return "Received";
       } else {
         return "Receiving";
@@ -124,6 +143,66 @@ class _TransactionDetailsViewState
 
   String _note = "";
 
+  Future<bool> showExplorerWarning(String explorer) async {
+    final bool? shouldContinue = await showDialog<bool>(
+      context: context,
+      barrierDismissible: false,
+      builder: (_) => StackDialog(
+        title: "Attention",
+        message:
+            "You are about to view this transaction in a block explorer. The explorer may log your IP address and link it to the transaction. Only proceed if you trust $explorer.",
+        icon: Row(
+          children: [
+            Consumer(builder: (_, ref, __) {
+              return Checkbox(
+                value: ref.watch(prefsChangeNotifierProvider
+                    .select((value) => value.hideBlockExplorerWarning)),
+                onChanged: (value) {
+                  if (value is bool) {
+                    ref
+                        .read(prefsChangeNotifierProvider)
+                        .hideBlockExplorerWarning = value;
+                    setState(() {});
+                  }
+                },
+              );
+            }),
+            Text(
+              "Never show again",
+              style: STextStyles.smallMed14,
+            )
+          ],
+        ),
+        leftButton: TextButton(
+          onPressed: () {
+            Navigator.of(context).pop(false);
+          },
+          child: Text(
+            "Cancel",
+            style: STextStyles.button.copyWith(
+              color: CFColors.stackAccent,
+            ),
+          ),
+        ),
+        rightButton: TextButton(
+          style: Theme.of(context).textButtonTheme.style?.copyWith(
+                backgroundColor: MaterialStateProperty.all<Color>(
+                  CFColors.stackAccent,
+                ),
+              ),
+          onPressed: () {
+            Navigator.of(context).pop(true);
+          },
+          child: Text(
+            "Continue",
+            style: STextStyles.button,
+          ),
+        ),
+      ),
+    );
+    return shouldContinue ?? false;
+  }
+
   @override
   Widget build(BuildContext context) {
     return Scaffold(
@@ -221,12 +300,16 @@ class _TransactionDetailsViewState
                   ),
                 ),
                 if (!(coin == Coin.monero &&
-                    _transaction.txType.toLowerCase() == "sent"))
+                        _transaction.txType.toLowerCase() == "sent") &&
+                    !((coin == Coin.firo || coin == Coin.firoTestNet) &&
+                        _transaction.subType == "mint"))
                   const SizedBox(
                     height: 12,
                   ),
                 if (!(coin == Coin.monero &&
-                    _transaction.txType.toLowerCase() == "sent"))
+                        _transaction.txType.toLowerCase() == "sent") &&
+                    !((coin == Coin.firo || coin == Coin.firoTestNet) &&
+                        _transaction.subType == "mint"))
                   RoundedWhiteContainer(
                     child: Column(
                       crossAxisAlignment: CrossAxisAlignment.start,
@@ -469,6 +552,19 @@ class _TransactionDetailsViewState
                               coin: coin,
                               txid: _transaction.txid,
                             );
+
+                            if (ref
+                                    .read(prefsChangeNotifierProvider)
+                                    .hideBlockExplorerWarning ==
+                                false) {
+                              final shouldContinue =
+                                  await showExplorerWarning(uri.host);
+
+                              if (!shouldContinue) {
+                                return;
+                              }
+                            }
+
                             // ref
                             //     .read(
                             //         shouldShowLockscreenOnResumeStateProvider
@@ -480,14 +576,14 @@ class _TransactionDetailsViewState
                                 mode: LaunchMode.externalApplication,
                               );
                             } catch (_) {
-                              showDialog<void>(
+                              unawaited(showDialog<void>(
                                 context: context,
                                 builder: (_) => StackOkDialog(
                                   title: "Could not open in block explorer",
                                   message:
                                       "Failed to open \"${uri.toString()}\"",
                                 ),
-                              );
+                              ));
                             } finally {
                               // Future<void>.delayed(
                               //   const Duration(seconds: 1),
@@ -505,83 +601,83 @@ class _TransactionDetailsViewState
                     ],
                   ),
                 ),
-                if ((coin == Coin.firoTestNet || coin == Coin.firo) &&
-                    _transaction.subType == "mint")
-                  const SizedBox(
-                    height: 12,
-                  ),
-                if ((coin == Coin.firoTestNet || coin == Coin.firo) &&
-                    _transaction.subType == "mint")
-                  RoundedWhiteContainer(
-                    child: Column(
-                      crossAxisAlignment: CrossAxisAlignment.start,
-                      children: [
-                        Row(
-                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                          children: [
-                            Text(
-                              "Mint Transaction ID",
-                              style: STextStyles.itemSubtitle,
-                            ),
-                          ],
-                        ),
-                        const SizedBox(
-                          height: 8,
-                        ),
-                        // Flexible(
-                        //   child: FittedBox(
-                        //     fit: BoxFit.scaleDown,
-                        //     child:
-                        SelectableText(
-                          _transaction.otherData ?? "Unknown",
-                          style: STextStyles.itemSubtitle12,
-                        ),
-                        //   ),
-                        // ),
-                        const SizedBox(
-                          height: 8,
-                        ),
-                        BlueTextButton(
-                          text: "Open in block explorer",
-                          onTap: () async {
-                            final uri = getBlockExplorerTransactionUrlFor(
-                              coin: coin,
-                              txid: _transaction.otherData ?? "Unknown",
-                            );
-                            // ref
-                            //     .read(
-                            //         shouldShowLockscreenOnResumeStateProvider
-                            //             .state)
-                            //     .state = false;
-                            try {
-                              await launchUrl(
-                                uri,
-                                mode: LaunchMode.externalApplication,
-                              );
-                            } catch (_) {
-                              showDialog<void>(
-                                context: context,
-                                builder: (_) => StackOkDialog(
-                                  title: "Could not open in block explorer",
-                                  message:
-                                      "Failed to open \"${uri.toString()}\"",
-                                ),
-                              );
-                            } finally {
-                              // Future<void>.delayed(
-                              //   const Duration(seconds: 1),
-                              //   () => ref
-                              //       .read(
-                              //           shouldShowLockscreenOnResumeStateProvider
-                              //               .state)
-                              //       .state = true,
-                              // );
-                            }
-                          },
-                        ),
-                      ],
-                    ),
-                  ),
+                // if ((coin == Coin.firoTestNet || coin == Coin.firo) &&
+                //     _transaction.subType == "mint")
+                //   const SizedBox(
+                //     height: 12,
+                //   ),
+                // if ((coin == Coin.firoTestNet || coin == Coin.firo) &&
+                //     _transaction.subType == "mint")
+                //   RoundedWhiteContainer(
+                //     child: Column(
+                //       crossAxisAlignment: CrossAxisAlignment.start,
+                //       children: [
+                //         Row(
+                //           mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                //           children: [
+                //             Text(
+                //               "Mint Transaction ID",
+                //               style: STextStyles.itemSubtitle,
+                //             ),
+                //           ],
+                //         ),
+                //         const SizedBox(
+                //           height: 8,
+                //         ),
+                //         // Flexible(
+                //         //   child: FittedBox(
+                //         //     fit: BoxFit.scaleDown,
+                //         //     child:
+                //         SelectableText(
+                //           _transaction.otherData ?? "Unknown",
+                //           style: STextStyles.itemSubtitle12,
+                //         ),
+                //         //   ),
+                //         // ),
+                //         const SizedBox(
+                //           height: 8,
+                //         ),
+                //         BlueTextButton(
+                //           text: "Open in block explorer",
+                //           onTap: () async {
+                //             final uri = getBlockExplorerTransactionUrlFor(
+                //               coin: coin,
+                //               txid: _transaction.otherData ?? "Unknown",
+                //             );
+                //             // ref
+                //             //     .read(
+                //             //         shouldShowLockscreenOnResumeStateProvider
+                //             //             .state)
+                //             //     .state = false;
+                //             try {
+                //               await launchUrl(
+                //                 uri,
+                //                 mode: LaunchMode.externalApplication,
+                //               );
+                //             } catch (_) {
+                //               unawaited(showDialog<void>(
+                //                 context: context,
+                //                 builder: (_) => StackOkDialog(
+                //                   title: "Could not open in block explorer",
+                //                   message:
+                //                       "Failed to open \"${uri.toString()}\"",
+                //                 ),
+                //               ));
+                //             } finally {
+                //               // Future<void>.delayed(
+                //               //   const Duration(seconds: 1),
+                //               //   () => ref
+                //               //       .read(
+                //               //           shouldShowLockscreenOnResumeStateProvider
+                //               //               .state)
+                //               //       .state = true,
+                //               // );
+                //             }
+                //           },
+                //         ),
+                //       ],
+                //     ),
+                //   ),
                 if (coin == Coin.epicCash)
                   const SizedBox(
                     height: 12,
@@ -637,20 +733,20 @@ class _TransactionDetailsViewState
                   if (manager.wallet is EpicCashWallet) {
                     final String? id = _transaction.slateId;
                     if (id == null) {
-                      showFloatingFlushBar(
+                      unawaited(showFloatingFlushBar(
                         type: FlushBarType.warning,
                         message: "Could not find Epic transaction ID",
                         context: context,
-                      );
+                      ));
                       return;
                     }
 
-                    showDialog<dynamic>(
+                    unawaited(showDialog<dynamic>(
                       barrierDismissible: false,
                       context: context,
                       builder: (_) =>
                           const CancellingTransactionProgressDialog(),
-                    );
+                    ));
 
                     final result = await (manager.wallet as EpicCashWallet)
                         .cancelPendingTransactionAndPost(id);
@@ -681,11 +777,11 @@ class _TransactionDetailsViewState
                       }
                     }
                   } else {
-                    showFloatingFlushBar(
+                    unawaited(showFloatingFlushBar(
                       type: FlushBarType.warning,
                       message: "ERROR: Wallet type is not Epic Cash",
                       context: context,
-                    );
+                    ));
                     return;
                   }
                 },
diff --git a/lib/pages/wallet_view/wallet_view.dart b/lib/pages/wallet_view/wallet_view.dart
index 3f097ddf3..94228bee7 100644
--- a/lib/pages/wallet_view/wallet_view.dart
+++ b/lib/pages/wallet_view/wallet_view.dart
@@ -1,9 +1,11 @@
 import 'dart:async';
 
+import 'package:decimal/decimal.dart';
 import 'package:event_bus/event_bus.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:flutter_svg/svg.dart';
+import 'package:stackwallet/notifications/show_flush_bar.dart';
 import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart';
 import 'package:stackwallet/pages/exchange_view/wallet_initiated_exchange_view.dart';
 import 'package:stackwallet/pages/home_view/home_view.dart';
@@ -22,6 +24,7 @@ import 'package:stackwallet/providers/global/auto_swb_service_provider.dart';
 import 'package:stackwallet/providers/providers.dart';
 import 'package:stackwallet/providers/ui/transaction_filter_provider.dart';
 import 'package:stackwallet/providers/ui/unread_notifications_provider.dart';
+import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
 import 'package:stackwallet/services/coins/manager.dart';
 import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
 import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
@@ -31,12 +34,18 @@ import 'package:stackwallet/utilities/cfcolors.dart';
 import 'package:stackwallet/utilities/constants.dart';
 import 'package:stackwallet/utilities/enums/backup_frequency_type.dart';
 import 'package:stackwallet/utilities/enums/coin_enum.dart';
+import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
 import 'package:stackwallet/utilities/text_styles.dart';
 import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
 import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
+import 'package:stackwallet/widgets/custom_loading_overlay.dart';
 import 'package:stackwallet/widgets/stack_dialog.dart';
 import 'package:tuple/tuple.dart';
 
+import '../../providers/wallet/public_private_balance_state_provider.dart';
+import '../../providers/wallet/wallet_balance_toggle_state_provider.dart';
+import '../../utilities/enums/wallet_balance_toggle_state.dart';
+
 /// [eventBus] should only be set during testing
 class WalletView extends ConsumerStatefulWidget {
   const WalletView({
@@ -155,7 +164,7 @@ class _WalletViewState extends ConsumerState<WalletView> {
     const timeout = Duration(milliseconds: 1500);
     if (_cachedTime == null || now.difference(_cachedTime!) > timeout) {
       _cachedTime = now;
-      showDialog<dynamic>(
+      unawaited(showDialog<dynamic>(
         context: context,
         barrierDismissible: false,
         builder: (_) => WillPopScope(
@@ -173,7 +182,7 @@ class _WalletViewState extends ConsumerState<WalletView> {
         onTimeout: () => Navigator.of(context).popUntil(
           ModalRoute.withName(WalletView.routeName),
         ),
-      );
+      ));
     }
     return false;
   }
@@ -222,14 +231,14 @@ class _WalletViewState extends ConsumerState<WalletView> {
     final coin = ref.read(managerProvider).coin;
 
     if (coin == Coin.epicCash) {
-      showDialog<void>(
+      await showDialog<void>(
         context: context,
         builder: (_) => const StackOkDialog(
           title: "ChangeNOW not available for Epic Cash",
         ),
       );
     } else if (coin.name.endsWith("TestNet")) {
-      showDialog<void>(
+      await showDialog<void>(
         context: context,
         builder: (_) => const StackOkDialog(
           title: "ChangeNOW not available for test net coins",
@@ -247,10 +256,10 @@ class _WalletViewState extends ConsumerState<WalletView> {
               element.ticker.toLowerCase() == coin.ticker.toLowerCase());
 
       if (currencies.isNotEmpty) {
-        ref
+        unawaited(ref
             .read(estimatedRateExchangeFormProvider)
-            .updateFrom(currencies.first, false);
-        ref.read(estimatedRateExchangeFormProvider).updateTo(
+            .updateFrom(currencies.first, false));
+        unawaited(ref.read(estimatedRateExchangeFormProvider).updateTo(
             ref
                 .read(availableChangeNowCurrenciesStateProvider.state)
                 .state
@@ -258,16 +267,82 @@ class _WalletViewState extends ConsumerState<WalletView> {
                   (element) =>
                       element.ticker.toLowerCase() != coin.ticker.toLowerCase(),
                 ),
-            false);
+            false));
       }
 
-      Navigator.of(context).pushNamed(
+      unawaited(Navigator.of(context).pushNamed(
         WalletInitiatedExchangeView.routeName,
         arguments: Tuple2(
           walletId,
           coin,
         ),
-      );
+      ));
+    }
+  }
+
+  Future<void> attemptAnonymize() async {
+    bool shouldPop = false;
+    unawaited(
+      showDialog(
+        context: context,
+        builder: (context) => WillPopScope(
+          child: const CustomLoadingOverlay(
+            message: "Anonymizing balance",
+            eventBus: null,
+          ),
+          onWillPop: () async => shouldPop,
+        ),
+      ),
+    );
+    final firoWallet = ref.read(managerProvider).wallet as FiroWallet;
+
+    final publicBalance = await firoWallet.availablePublicBalance();
+    if (publicBalance <= Decimal.zero) {
+      shouldPop = true;
+      if (mounted) {
+        Navigator.of(context).popUntil(
+          ModalRoute.withName(WalletView.routeName),
+        );
+        unawaited(
+          showFloatingFlushBar(
+            type: FlushBarType.info,
+            message: "No funds available to anonymize!",
+            context: context,
+          ),
+        );
+      }
+      return;
+    }
+
+    try {
+      await firoWallet.anonymizeAllPublicFunds();
+      shouldPop = true;
+      if (mounted) {
+        Navigator.of(context).popUntil(
+          ModalRoute.withName(WalletView.routeName),
+        );
+        unawaited(
+          showFloatingFlushBar(
+            type: FlushBarType.success,
+            message: "Anonymize transaction submitted",
+            context: context,
+          ),
+        );
+      }
+    } catch (e) {
+      shouldPop = true;
+      if (mounted) {
+        Navigator.of(context).popUntil(
+          ModalRoute.withName(WalletView.routeName),
+        );
+        await showDialog<dynamic>(
+          context: context,
+          builder: (_) => StackOkDialog(
+            title: "Anonymize all failed",
+            message: "Reason: $e",
+          ),
+        );
+      }
     }
   }
 
@@ -275,6 +350,8 @@ class _WalletViewState extends ConsumerState<WalletView> {
   Widget build(BuildContext context) {
     debugPrint("BUILD: $runtimeType");
 
+    final coin = ref.watch(managerProvider.select((value) => value.coin));
+
     return WillPopScope(
       onWillPop: _onWillPop,
       child: Scaffold(
@@ -283,9 +360,7 @@ class _WalletViewState extends ConsumerState<WalletView> {
           title: Row(
             children: [
               SvgPicture.asset(
-                Assets.svg.iconFor(
-                    coin: ref
-                        .watch(managerProvider.select((value) => value.coin))),
+                Assets.svg.iconFor(coin: coin),
                 // color: CFColors.stackAccent,
                 width: 24,
                 height: 24,
@@ -440,6 +515,69 @@ class _WalletViewState extends ConsumerState<WalletView> {
                     ),
                   ),
                 ),
+                if (coin == Coin.firo)
+                  const SizedBox(
+                    height: 10,
+                  ),
+                if (coin == Coin.firo)
+                  Padding(
+                    padding: const EdgeInsets.symmetric(horizontal: 16),
+                    child: Row(
+                      children: [
+                        Expanded(
+                          child: TextButton(
+                            onPressed: () async {
+                              await showDialog<void>(
+                                context: context,
+                                builder: (context) => StackDialog(
+                                  title: "Attention!",
+                                  message:
+                                      "You're about to anonymize all of your public funds.",
+                                  leftButton: TextButton(
+                                    onPressed: () {
+                                      Navigator.of(context).pop();
+                                    },
+                                    child: Text(
+                                      "Cancel",
+                                      style: STextStyles.button.copyWith(
+                                        color: CFColors.stackAccent,
+                                      ),
+                                    ),
+                                  ),
+                                  rightButton: TextButton(
+                                    onPressed: () async {
+                                      Navigator.of(context).pop();
+
+                                      unawaited(attemptAnonymize());
+                                    },
+                                    style: Theme.of(context)
+                                        .textButtonTheme
+                                        .style
+                                        ?.copyWith(
+                                          backgroundColor:
+                                              MaterialStateProperty.all<Color>(
+                                            CFColors.stackAccent,
+                                          ),
+                                        ),
+                                    child: Text(
+                                      "Continue",
+                                      style: STextStyles.button,
+                                    ),
+                                  ),
+                                ),
+                              );
+                            },
+                            child: Text(
+                              "Anonymize funds",
+                              style: STextStyles.button.copyWith(
+                                color: CFColors.stackAccent,
+                              ),
+                            ),
+                          ),
+                        ),
+                      ],
+                    ),
+                  ),
                 const SizedBox(
                   height: 20,
                 ),
@@ -532,19 +670,17 @@ class _WalletViewState extends ConsumerState<WalletView> {
                                     onExchangePressed: () =>
                                         _onExchangePressed(context),
                                     onReceivePressed: () async {
-                                      final address = await ref
-                                          .read(managerProvider)
-                                          .currentReceivingAddress;
                                       final coin =
                                           ref.read(managerProvider).coin;
                                       if (mounted) {
-                                        Navigator.of(context).pushNamed(
+                                        unawaited(
+                                            Navigator.of(context).pushNamed(
                                           ReceiveView.routeName,
                                           arguments: Tuple2(
-                                            address,
+                                            walletId,
                                             coin,
                                           ),
-                                        );
+                                        ));
                                       }
                                     },
                                     onSendPressed: () {
@@ -552,6 +688,25 @@ class _WalletViewState extends ConsumerState<WalletView> {
                                           ref.read(managerProvider).walletId;
                                       final coin =
                                           ref.read(managerProvider).coin;
+                                      switch (ref
+                                          .read(walletBalanceToggleStateProvider
+                                              .state)
+                                          .state) {
+                                        case WalletBalanceToggleState.full:
+                                          ref
+                                              .read(
+                                                  publicPrivateBalanceStateProvider
+                                                      .state)
+                                              .state = "Public";
+                                          break;
+                                        case WalletBalanceToggleState.available:
+                                          ref
+                                              .read(
+                                                  publicPrivateBalanceStateProvider
+                                                      .state)
+                                              .state = "Private";
+                                          break;
+                                      }
                                       Navigator.of(context).pushNamed(
                                         SendView.routeName,
                                         arguments: Tuple2(
diff --git a/lib/providers/exchange/available_currencies_state_provider.dart b/lib/providers/exchange/available_currencies_state_provider.dart
index dee8cfa60..5b8395201 100644
--- a/lib/providers/exchange/available_currencies_state_provider.dart
+++ b/lib/providers/exchange/available_currencies_state_provider.dart
@@ -2,4 +2,4 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:stackwallet/models/exchange/change_now/currency.dart';
 
 final availableChangeNowCurrenciesStateProvider =
-    StateProvider<List<Currency>>((ref) => []);
+    StateProvider<List<Currency>>((ref) => <Currency>[]);
diff --git a/lib/providers/exchange/available_floating_rate_pairs_state_provider.dart b/lib/providers/exchange/available_floating_rate_pairs_state_provider.dart
index 5620d1d91..a157b0727 100644
--- a/lib/providers/exchange/available_floating_rate_pairs_state_provider.dart
+++ b/lib/providers/exchange/available_floating_rate_pairs_state_provider.dart
@@ -2,4 +2,5 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:stackwallet/models/exchange/change_now/available_floating_rate_pair.dart';
 
 final availableFloatingRatePairsStateProvider =
-    StateProvider<List<AvailableFloatingRatePair>>((ref) => []);
+    StateProvider<List<AvailableFloatingRatePair>>(
+        (ref) => <AvailableFloatingRatePair>[]);
diff --git a/lib/providers/wallet/public_private_balance_state_provider.dart b/lib/providers/wallet/public_private_balance_state_provider.dart
new file mode 100644
index 000000000..351489f04
--- /dev/null
+++ b/lib/providers/wallet/public_private_balance_state_provider.dart
@@ -0,0 +1,4 @@
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+final publicPrivateBalanceStateProvider =
+    StateProvider<String>((_) => "Private");
diff --git a/lib/route_generator.dart b/lib/route_generator.dart
index 329018d9a..001c21b0d 100644
--- a/lib/route_generator.dart
+++ b/lib/route_generator.dart
@@ -681,7 +681,7 @@ class RouteGenerator {
           return getRoute(
             shouldUseMaterialRoute: useMaterialPageRoute,
             builder: (_) => ReceiveView(
-              receivingAddress: args.item1,
+              walletId: args.item1,
               coin: args.item2,
             ),
             settings: RouteSettings(
diff --git a/lib/services/change_now/change_now.dart b/lib/services/change_now/change_now.dart
index af70b83e4..4b8dc5810 100644
--- a/lib/services/change_now/change_now.dart
+++ b/lib/services/change_now/change_now.dart
@@ -6,6 +6,7 @@ import 'package:http/http.dart' as http;
 import 'package:stackwallet/external_api_keys.dart';
 import 'package:stackwallet/models/exchange/change_now/available_floating_rate_pair.dart';
 import 'package:stackwallet/models/exchange/change_now/change_now_response.dart';
+import 'package:stackwallet/models/exchange/change_now/cn_exchange_estimate.dart';
 import 'package:stackwallet/models/exchange/change_now/currency.dart';
 import 'package:stackwallet/models/exchange/change_now/estimated_exchange_amount.dart';
 import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
@@ -17,6 +18,7 @@ class ChangeNow {
   static const String scheme = "https";
   static const String authority = "api.changenow.io";
   static const String apiVersion = "/v1";
+  static const String apiVersionV2 = "/v2";
 
   ChangeNow._();
   static final ChangeNow _instance = ChangeNow._();
@@ -29,6 +31,10 @@ class ChangeNow {
     return Uri.https(authority, apiVersion + path, params);
   }
 
+  Uri _buildUriV2(String path, Map<String, dynamic>? params) {
+    return Uri.https(authority, apiVersionV2 + path, params);
+  }
+
   Future<dynamic> _makeGetRequest(Uri uri) async {
     final client = this.client ?? http.Client();
     try {
@@ -47,6 +53,27 @@ class ChangeNow {
     }
   }
 
+  Future<dynamic> _makeGetRequestV2(Uri uri, String apiKey) async {
+    final client = this.client ?? http.Client();
+    try {
+      final response = await client.get(
+        uri,
+        headers: {
+          // 'Content-Type': 'application/json',
+          'x-changenow-api-key': apiKey,
+        },
+      );
+
+      final parsed = jsonDecode(response.body);
+
+      return parsed;
+    } catch (e, s) {
+      Logging.instance
+          .log("_makeRequestV2($uri) threw: $e\n$s", level: LogLevel.Error);
+      rethrow;
+    }
+  }
+
   Future<dynamic> _makePostRequest(
     Uri uri,
     Map<String, String> body,
@@ -283,37 +310,109 @@ class ChangeNow {
     }
   }
 
+  // old v1 version
   /// This API endpoint returns fixed-rate estimated exchange amount of
   /// [toTicker] cryptocurrency to receive for [fromAmount] of [fromTicker]
-  Future<ChangeNowResponse<EstimatedExchangeAmount>>
-      getEstimatedFixedRateExchangeAmount({
+  // Future<ChangeNowResponse<EstimatedExchangeAmount>>
+  //     getEstimatedFixedRateExchangeAmount({
+  //   required String fromTicker,
+  //   required String toTicker,
+  //   required Decimal fromAmount,
+  //   // (Optional) Use rateId for fixed-rate flow. If this field is true, you
+  //   // could use returned field "rateId" in next method for creating transaction
+  //   // to freeze estimated amount that you got in this method. Current estimated
+  //   // amount would be valid until time in field "validUntil"
+  //   bool useRateId = true,
+  //   String? apiKey,
+  // }) async {
+  //   Map<String, dynamic> params = {
+  //     "api_key": apiKey ?? kChangeNowApiKey,
+  //     "useRateId": useRateId.toString(),
+  //   };
+  //
+  //   final uri = _buildUri(
+  //     "/exchange-amount/fixed-rate/${fromAmount.toString()}/${fromTicker}_$toTicker",
+  //     params,
+  //   );
+  //
+  //   try {
+  //     // simple json object is expected here
+  //     final json = await _makeGetRequest(uri);
+  //
+  //     try {
+  //       final value = EstimatedExchangeAmount.fromJson(
+  //           Map<String, dynamic>.from(json as Map));
+  //       return ChangeNowResponse(value: value);
+  //     } catch (_) {
+  //       return ChangeNowResponse(
+  //         exception: ChangeNowException(
+  //           "Failed to serialize $json",
+  //           ChangeNowExceptionType.serializeResponseError,
+  //         ),
+  //       );
+  //     }
+  //   } catch (e, s) {
+  //     Logging.instance.log(
+  //         "getEstimatedFixedRateExchangeAmount exception: $e\n$s",
+  //         level: LogLevel.Error);
+  //     return ChangeNowResponse(
+  //       exception: ChangeNowException(
+  //         e.toString(),
+  //         ChangeNowExceptionType.generic,
+  //       ),
+  //     );
+  //   }
+  // }
+
+  /// Get estimated amount of [toTicker] cryptocurrency to receive
+  /// for [fromAmount] of [fromTicker]
+  Future<ChangeNowResponse<CNExchangeEstimate>> getEstimatedExchangeAmountV2({
     required String fromTicker,
     required String toTicker,
-    required Decimal fromAmount,
-    // (Optional) Use rateId for fixed-rate flow. If this field is true, you
-    // could use returned field "rateId" in next method for creating transaction
-    // to freeze estimated amount that you got in this method. Current estimated
-    // amount would be valid until time in field "validUntil"
-    bool useRateId = true,
+    required CNEstimateType fromOrTo,
+    required Decimal amount,
+    String? fromNetwork,
+    String? toNetwork,
+    CNFlowType flow = CNFlowType.standard,
     String? apiKey,
   }) async {
-    Map<String, dynamic> params = {
-      "api_key": apiKey ?? kChangeNowApiKey,
-      "useRateId": useRateId.toString(),
+    Map<String, dynamic>? params = {
+      "fromCurrency": fromTicker,
+      "toCurrency": toTicker,
+      "flow": flow.value,
+      "type": fromOrTo.name,
     };
 
-    final uri = _buildUri(
-      "/exchange-amount/fixed-rate/${fromAmount.toString()}/${fromTicker}_$toTicker",
-      params,
-    );
+    switch (fromOrTo) {
+      case CNEstimateType.direct:
+        params["fromAmount"] = amount.toString();
+        break;
+      case CNEstimateType.reverse:
+        params["toAmount"] = amount.toString();
+        break;
+    }
+
+    if (fromNetwork != null) {
+      params["fromNetwork"] = fromNetwork;
+    }
+
+    if (toNetwork != null) {
+      params["toNetwork"] = toNetwork;
+    }
+
+    if (flow == CNFlowType.fixedRate) {
+      params["useRateId"] = "true";
+    }
+
+    final uri = _buildUriV2("/exchange/estimated-amount", params);
 
     try {
       // simple json object is expected here
-      final json = await _makeGetRequest(uri);
+      final json = await _makeGetRequestV2(uri, apiKey ?? kChangeNowApiKey);
 
       try {
-        final value = EstimatedExchangeAmount.fromJson(
-            Map<String, dynamic>.from(json as Map));
+        final value =
+            CNExchangeEstimate.fromJson(Map<String, dynamic>.from(json as Map));
         return ChangeNowResponse(value: value);
       } catch (_) {
         return ChangeNowResponse(
@@ -324,8 +423,7 @@ class ChangeNow {
         );
       }
     } catch (e, s) {
-      Logging.instance.log(
-          "getEstimatedFixedRateExchangeAmount exception: $e\n$s",
+      Logging.instance.log("getEstimatedExchangeAmountV2 exception: $e\n$s",
           level: LogLevel.Error);
       return ChangeNowResponse(
         exception: ChangeNowException(
diff --git a/lib/services/coins/bitcoin/bitcoin_wallet.dart b/lib/services/coins/bitcoin/bitcoin_wallet.dart
index 0750e9b93..bc40c8f0c 100644
--- a/lib/services/coins/bitcoin/bitcoin_wallet.dart
+++ b/lib/services/coins/bitcoin/bitcoin_wallet.dart
@@ -43,7 +43,7 @@ import 'package:tuple/tuple.dart';
 import 'package:uuid/uuid.dart';
 
 const int MINIMUM_CONFIRMATIONS = 2;
-const int DUST_LIMIT = 546;
+const int DUST_LIMIT = 294;
 
 const String GENESIS_HASH_MAINNET =
     "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f";
@@ -2715,11 +2715,11 @@ class BitcoinWallet extends CoinServiceAPI {
 
     final txModel = TransactionData.fromMap(transactionsMap);
 
-    DB.instance.put<dynamic>(
+    await DB.instance.put<dynamic>(
         boxName: walletId,
         key: 'storedTxnDataHeight',
         value: latestTxnBlockHeight);
-    DB.instance.put<dynamic>(
+    await DB.instance.put<dynamic>(
         boxName: walletId, key: 'latest_tx_model', value: txModel);
 
     return txModel;
@@ -2897,7 +2897,7 @@ class BitcoinWallet extends CoinServiceAPI {
         int changeOutputSize =
             satoshisBeingUsed - satoshiAmountToSend - feeForTwoOutputs;
         // We check to see if the user can pay for the new transaction with 2 outputs instead of one. If they can and
-        // the second output's size > 546 satoshis, we perform the mechanics required to properly generate and use a new
+        // the second output's size > DUST_LIMIT satoshis, we perform the mechanics required to properly generate and use a new
         // change address.
         if (changeOutputSize > DUST_LIMIT &&
             satoshisBeingUsed - satoshiAmountToSend - changeOutputSize ==
@@ -2972,7 +2972,7 @@ class BitcoinWallet extends CoinServiceAPI {
           return transactionObject;
         } else {
           // Something went wrong here. It either overshot or undershot the estimated fee amount or the changeOutputSize
-          // is smaller than or equal to 546. Revert to single output transaction.
+          // is smaller than or equal to DUST_LIMIT. Revert to single output transaction.
           Logging.instance.log('1 output in tx', level: LogLevel.Info);
           Logging.instance
               .log('Input size: $satoshisBeingUsed', level: LogLevel.Info);
@@ -2999,7 +2999,7 @@ class BitcoinWallet extends CoinServiceAPI {
           return transactionObject;
         }
       } else {
-        // No additional outputs needed since adding one would mean that it'd be smaller than 546 sats
+        // No additional outputs needed since adding one would mean that it'd be smaller than DUST_LIMIT sats
         // which makes it uneconomical to add to the transaction. Here, we pass data directly to instruct
         // the wallet to begin crafting the transaction that the user requested.
         Logging.instance.log('1 output in tx', level: LogLevel.Info);
@@ -3825,4 +3825,34 @@ class BitcoinWallet extends CoinServiceAPI {
 
     return available - estimatedFee;
   }
+
+  @override
+  Future<bool> generateNewAddress() async {
+    try {
+      await _incrementAddressIndexForChain(
+          0, DerivePathType.bip84); // First increment the receiving index
+      final newReceivingIndex = DB.instance.get<dynamic>(
+          boxName: walletId,
+          key: 'receivingIndexP2WPKH') as int; // Check the new receiving index
+      final newReceivingAddress = await _generateAddressForChain(
+          0,
+          newReceivingIndex,
+          DerivePathType
+              .bip84); // Use new index to derive a new receiving address
+      await _addToAddressesArrayForChain(
+          newReceivingAddress,
+          0,
+          DerivePathType
+              .bip84); // Add that new receiving address to the array of receiving addresses
+      _currentReceivingAddress = Future(() =>
+          newReceivingAddress); // Set the new receiving address that the service
+
+      return true;
+    } catch (e, s) {
+      Logging.instance.log(
+          "Exception rethrown from generateNewAddress(): $e\n$s",
+          level: LogLevel.Error);
+      return false;
+    }
+  }
 }
diff --git a/lib/services/coins/coin_service.dart b/lib/services/coins/coin_service.dart
index 3d8b1bd10..bc0e4be28 100644
--- a/lib/services/coins/coin_service.dart
+++ b/lib/services/coins/coin_service.dart
@@ -212,4 +212,6 @@ abstract class CoinServiceAPI {
   bool get isConnected;
 
   Future<int> estimateFeeFor(int satoshiAmount, int feeRate);
+
+  Future<bool> generateNewAddress();
 }
diff --git a/lib/services/coins/dogecoin/dogecoin_wallet.dart b/lib/services/coins/dogecoin/dogecoin_wallet.dart
index 7a3a70a96..a7b2132ad 100644
--- a/lib/services/coins/dogecoin/dogecoin_wallet.dart
+++ b/lib/services/coins/dogecoin/dogecoin_wallet.dart
@@ -3011,6 +3011,35 @@ class DogecoinWallet extends CoinServiceAPI {
 
     return available - estimatedFee;
   }
+
+  Future<bool> generateNewAddress() async {
+    try {
+      await _incrementAddressIndexForChain(
+          0, DerivePathType.bip44); // First increment the receiving index
+      final newReceivingIndex = DB.instance.get<dynamic>(
+          boxName: walletId,
+          key: 'receivingIndexP2PKH') as int; // Check the new receiving index
+      final newReceivingAddress = await _generateAddressForChain(
+          0,
+          newReceivingIndex,
+          DerivePathType
+              .bip44); // Use new index to derive a new receiving address
+      await _addToAddressesArrayForChain(
+          newReceivingAddress,
+          0,
+          DerivePathType
+              .bip44); // Add that new receiving address to the array of receiving addresses
+      _currentReceivingAddressP2PKH = Future(() =>
+          newReceivingAddress); // Set the new receiving address that the service
+
+      return true;
+    } catch (e, s) {
+      Logging.instance.log(
+          "Exception rethrown from generateNewAddress(): $e\n$s",
+          level: LogLevel.Error);
+      return false;
+    }
+  }
 }
 
 // Dogecoin Network
diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart
index b57244009..514ddb79f 100644
--- a/lib/services/coins/epiccash/epiccash_wallet.dart
+++ b/lib/services/coins/epiccash/epiccash_wallet.dart
@@ -77,11 +77,8 @@ Future<void> executeNative(Map<String, dynamic> arguments) async {
       final startHeight = arguments['startHeight'] as int?;
       final numberOfBlocks = arguments['numberOfBlocks'] as int?;
       Map<String, dynamic> result = {};
-      if (!(wallet == null ||
-          startHeight == null ||
-          numberOfBlocks == null)) {
-        var outputs =
-            await scanOutPuts(wallet, startHeight, numberOfBlocks);
+      if (!(wallet == null || startHeight == null || numberOfBlocks == null)) {
+        var outputs = await scanOutPuts(wallet, startHeight, numberOfBlocks);
         result['outputs'] = outputs;
         sendPort.send(result);
         return;
@@ -111,8 +108,8 @@ Future<void> executeNative(Map<String, dynamic> arguments) async {
           epicboxConfig == null)) {
         Logging.instance
             .log("SECRET_KEY_INDEX_IS $secretKeyIndex", level: LogLevel.Info);
-        result['result'] = await getSubscribeRequest(
-            wallet, secretKeyIndex, epicboxConfig);
+        result['result'] =
+            await getSubscribeRequest(wallet, secretKeyIndex, epicboxConfig);
         sendPort.send(result);
         return;
       }
@@ -122,8 +119,7 @@ Future<void> executeNative(Map<String, dynamic> arguments) async {
       Map<String, dynamic> result = {};
 
       if (!(wallet == null || slates == null)) {
-        result['result'] =
-            await processSlates(wallet, slates.toString());
+        result['result'] = await processSlates(wallet, slates.toString());
         sendPort.send(result);
         return;
       }
@@ -135,8 +131,8 @@ Future<void> executeNative(Map<String, dynamic> arguments) async {
       if (!(wallet == null ||
           refreshFromNode == null ||
           minimumConfirmations == null)) {
-        var res = await getWalletInfo(
-            wallet, refreshFromNode, minimumConfirmations);
+        var res =
+            await getWalletInfo(wallet, refreshFromNode, minimumConfirmations);
         result['result'] = res;
         sendPort.send(result);
         return;
@@ -166,11 +162,9 @@ Future<void> executeNative(Map<String, dynamic> arguments) async {
       final amount = arguments['amount'] as int?;
       final minimumConfirmations = arguments['minimumConfirmations'] as int?;
       Map<String, dynamic> result = {};
-      if (!(wallet == null ||
-          amount == null ||
-          minimumConfirmations == null)) {
-        var res = await getTransactionFees(
-            wallet, amount, minimumConfirmations);
+      if (!(wallet == null || amount == null || minimumConfirmations == null)) {
+        var res =
+            await getTransactionFees(wallet, amount, minimumConfirmations);
         result['result'] = res;
         sendPort.send(result);
         return;
@@ -198,7 +192,8 @@ Future<void> executeNative(Map<String, dynamic> arguments) async {
       }
     } else if (function == "txHttpSend") {
       final wallet = arguments['wallet'] as String?;
-      final selectionStrategyIsAll = arguments['selectionStrategyIsAll'] as int?;
+      final selectionStrategyIsAll =
+          arguments['selectionStrategyIsAll'] as int?;
       final minimumConfirmations = arguments['minimumConfirmations'] as int?;
       final message = arguments['message'] as String?;
       final amount = arguments['amount'] as int?;
@@ -218,7 +213,6 @@ Future<void> executeNative(Map<String, dynamic> arguments) async {
         sendPort.send(result);
         return;
       }
-
     }
     Logging.instance.log(
         "Error Arguments for $function not formatted correctly",
@@ -245,8 +239,7 @@ void stop(ReceivePort port) {
 
 // Keep Wrapper functions outside of the class to avoid memory leaks and errors about receive ports and illegal arguments.
 // TODO: Can get rid of this wrapper and call it in a full isolate instead of compute() if we want more control over this
-Future<String> _cancelTransactionWrapper(
-    Tuple2<String, String> data) async {
+Future<String> _cancelTransactionWrapper(Tuple2<String, String> data) async {
   // assuming this returns an empty string on success
   // or an error message string on failure
   return cancelTransaction(data.item1, data.item2);
@@ -290,8 +283,7 @@ Future<String> _initWalletWrapper(
 
 Future<String> _initGetAddressInfoWrapper(
     Tuple3<String, int, String> data) async {
-  String walletAddress =
-  getAddressInfo(data.item1, data.item2, data.item3);
+  String walletAddress = getAddressInfo(data.item1, data.item2, data.item3);
   return walletAddress;
 }
 
@@ -727,7 +719,7 @@ class EpicCashWallet extends CoinServiceAPI {
   /// returns an empty String on success, error message on failure
   Future<String> cancelPendingTransaction(String tx_slate_id) async {
     final String wallet =
-    (await _secureStore.read(key: '${_walletId}_wallet'))!;
+        (await _secureStore.read(key: '${_walletId}_wallet'))!;
 
     String? result;
     await m.protect(() async {
@@ -754,7 +746,8 @@ class EpicCashWallet extends CoinServiceAPI {
 
       String receiverAddress = txData['addresss'] as String;
       await m.protect(() async {
-        if (receiverAddress.startsWith("http://") || receiverAddress.startsWith("https://")) {
+        if (receiverAddress.startsWith("http://") ||
+            receiverAddress.startsWith("https://")) {
           const int selectionStrategyIsAll = 0;
           ReceivePort receivePort = await getIsolate({
             "function": "txHttpSend",
@@ -774,9 +767,8 @@ class EpicCashWallet extends CoinServiceAPI {
             throw Exception("txHttpSend isolate failed");
           }
           stop(receivePort);
-          Logging.instance.log('Closing txHttpSend!\n  $message',
-              level: LogLevel.Info);
-
+          Logging.instance
+              .log('Closing txHttpSend!\n  $message', level: LogLevel.Info);
         } else {
           ReceivePort receivePort = await getIsolate({
             "function": "createTransaction",
@@ -809,7 +801,6 @@ class EpicCashWallet extends CoinServiceAPI {
 
       await putSendToAddresses(sendTx);
 
-
       Logging.instance.log("CONFIRM_RESULT_IS $sendTx", level: LogLevel.Info);
 
       final decodeData = json.decode(sendTx);
@@ -818,9 +809,9 @@ class EpicCashWallet extends CoinServiceAPI {
         String errorMessage = decodeData[1] as String;
         throw Exception("Transaction failed with error code $errorMessage");
       } else {
-
         //If it's HTTP send no need to post to epicbox
-        if (!(receiverAddress.startsWith("http://") || receiverAddress.startsWith("https://"))) {
+        if (!(receiverAddress.startsWith("http://") ||
+            receiverAddress.startsWith("https://"))) {
           final postSlateRequest = decodeData[1];
           final postToServer = await postSlate(
               txData['addresss'] as String, postSlateRequest as String);
@@ -969,10 +960,9 @@ class EpicCashWallet extends CoinServiceAPI {
         level: LogLevel.Info);
 
     final config = await getRealConfig();
-    final password =
-    await _secureStore.read(key: '${_walletId}_password');
+    final password = await _secureStore.read(key: '${_walletId}_password');
 
-    final walletOpen = openWallet(config!, password!);
+    final walletOpen = openWallet(config, password!);
     await _secureStore.write(key: '${_walletId}_wallet', value: walletOpen);
 
     if ((DB.instance.get<dynamic>(boxName: walletId, key: "id")) == null) {
@@ -1297,7 +1287,6 @@ class EpicCashWallet extends CoinServiceAPI {
 
   Future<bool> startScans() async {
     try {
-
       final wallet = await _secureStore.read(key: '${_walletId}_wallet');
 
       var restoreHeight =
@@ -1445,7 +1434,6 @@ class EpicCashWallet extends CoinServiceAPI {
 
       //Store Epic box address info
       await storeEpicboxInfo();
-
     } catch (e, s) {
       Logging.instance
           .log("Error recovering wallet $e\n$s", level: LogLevel.Error);
@@ -1724,11 +1712,13 @@ class EpicCashWallet extends CoinServiceAPI {
                     subscribeRequest['signature'] as String, slate as String);
               }
 
-              if (response.contains("Error Wallet store error: DB Not Found Error")) {
+              if (response
+                  .contains("Error Wallet store error: DB Not Found Error")) {
                 //Already processed - to be deleted
-                Logging.instance.log("DELETING_PROCESSED_SLATE",
-                    level: LogLevel.Info);
-                final slateDelete = await deleteSlate(currentAddress, subscribeRequest['signature'] as String, slate as String);
+                Logging.instance
+                    .log("DELETING_PROCESSED_SLATE", level: LogLevel.Info);
+                final slateDelete = await deleteSlate(currentAddress,
+                    subscribeRequest['signature'] as String, slate as String);
                 Logging.instance.log("DELETE_SLATE_RESPONSE $slateDelete",
                     level: LogLevel.Info);
               } else {
@@ -1738,14 +1728,14 @@ class EpicCashWallet extends CoinServiceAPI {
                 if (slateStatus == "PendingProcessing") {
                   //Encrypt slate
                   String encryptedSlate = await getEncryptedSlate(
-                      wallet!,
+                      wallet,
                       slateSender,
                       currentReceivingIndex,
                       epicboxConfig!,
                       decodedResponse[1] as String);
 
                   final postSlateToServer =
-                  await postSlate(slateSender, encryptedSlate);
+                      await postSlate(slateSender, encryptedSlate);
 
                   await deleteSlate(currentAddress,
                       subscribeRequest['signature'] as String, slate as String);
@@ -1753,7 +1743,8 @@ class EpicCashWallet extends CoinServiceAPI {
                       level: LogLevel.Info);
                 } else {
                   //Finalise Slate
-                  final processSlate = json.decode(decodedResponse[1] as String);
+                  final processSlate =
+                      json.decode(decodedResponse[1] as String);
                   Logging.instance.log(
                       "PROCESSED_SLATE_TO_FINALIZE $processSlate",
                       level: LogLevel.Info);
@@ -1762,8 +1753,7 @@ class EpicCashWallet extends CoinServiceAPI {
                   String txSlateId = tx[0]['tx_slate_id'] as String;
                   Logging.instance
                       .log("TX_SLATE_ID_IS $txSlateId", level: LogLevel.Info);
-                  final postToNode = await postSlateToNode(
-                      wallet!, txSlateId);
+                  final postToNode = await postSlateToNode(wallet, txSlateId);
                   await deleteSlate(currentAddress,
                       subscribeRequest['signature'] as String, slate as String);
                   Logging.instance.log("POST_SLATE_RESPONSE $postToNode",
@@ -2316,4 +2306,29 @@ class EpicCashWallet extends CoinServiceAPI {
     // TODO: implement this
     return currentFee;
   }
+
+  // not used in epic currently
+  @override
+  Future<bool> generateNewAddress() async {
+    try {
+      // await incrementAddressIndexForChain(
+      //     0); // First increment the receiving index
+      // final newReceivingIndex =
+      // DB.instance.get<dynamic>(boxName: walletId, key: 'receivingIndex')
+      // as int; // Check the new receiving index
+      // final newReceivingAddress = await _generateAddressForChain(0,
+      //     newReceivingIndex); // Use new index to derive a new receiving address
+      // await addToAddressesArrayForChain(newReceivingAddress,
+      //     0); // Add that new receiving address to the array of receiving addresses
+      // _currentReceivingAddress = Future(() =>
+      // newReceivingAddress); // Set the new receiving address that the service
+
+      return true;
+    } catch (e, s) {
+      Logging.instance.log(
+          "Exception rethrown from generateNewAddress(): $e\n$s",
+          level: LogLevel.Error);
+      return false;
+    }
+  }
 }
diff --git a/lib/services/coins/firo/firo_wallet.dart b/lib/services/coins/firo/firo_wallet.dart
index c8bd9be24..006655cf2 100644
--- a/lib/services/coins/firo/firo_wallet.dart
+++ b/lib/services/coins/firo/firo_wallet.dart
@@ -37,12 +37,14 @@ import 'package:stackwallet/utilities/assets.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';
 import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
 import 'package:stackwallet/utilities/format.dart';
 import 'package:stackwallet/utilities/logger.dart';
 import 'package:stackwallet/utilities/prefs.dart';
 import 'package:tuple/tuple.dart';
 
+const DUST_LIMIT = 1000;
 const MINIMUM_CONFIRMATIONS = 1;
 const MINT_LIMIT = 100100000000;
 const int LELANTUS_VALUE_SPEND_LIMIT_PER_TRANSACTION = 5001 * 100000000;
@@ -186,7 +188,7 @@ Future<void> executeNative(Map<String, dynamic> arguments) async {
         level: LogLevel.Error);
     sendPort.send("Error");
   } finally {
-    Logging.instance.isar?.close();
+    await Logging.instance.isar?.close();
   }
 }
 
@@ -375,7 +377,7 @@ Future<Map<String, dynamic>> isolateRestore(
   // Edit the receive transactions with the mint fees.
   Map<String, models.Transaction> editedTransactions =
       <String, models.Transaction>{};
-  lelantusCoins.forEach((item) {
+  for (var item in lelantusCoins) {
     item.forEach((key, value) {
       String txid = value.txId;
       var tx = data.findTransaction(txid);
@@ -420,7 +422,7 @@ Future<Map<String, dynamic>> isolateRestore(
         );
       }
     });
-  });
+  }
   // Logging.instance.log(editedTransactions, addToDebugMessagesDB: false);
 
   Map<String, models.Transaction> transactionMap = data.getAllTransactions();
@@ -729,6 +731,39 @@ Future<void> _setTestnetWrapper(bool isTestnet) async {
   // setTestnet(isTestnet);
 }
 
+Future<Map<String, dynamic>?> getInitialAnonymitySetCache(
+  String groupID,
+) async {
+  Logging.instance.log("getInitialAnonymitySetCache", level: LogLevel.Info);
+  final Client client = Client();
+  try {
+    final uri = Uri.parse("$kStackCommunityNodesEndpoint/getAnonymity");
+
+    final anonSetResult = await client.post(
+      uri,
+      headers: {'Content-Type': 'application/json'},
+      body: jsonEncode({
+        "jsonrpc": "2.0",
+        "id": "0",
+        'aset': groupID,
+      }),
+    );
+
+    final response = jsonDecode(anonSetResult.body.toString());
+    if (response['status'] == 'success') {
+      final anonResponse = jsonDecode(response['result'] as String);
+
+      final setData = Map<String, dynamic>.from(anonResponse["result"] as Map);
+      return setData;
+    } else {
+      return null;
+    }
+  } catch (e, s) {
+    Logging.instance.log("$e $s", level: LogLevel.Error);
+    return null;
+  }
+}
+
 /// Handles a single instance of a firo wallet
 class FiroWallet extends CoinServiceAPI {
   static const integrationTestFlag =
@@ -973,14 +1008,128 @@ class FiroWallet extends CoinServiceAPI {
   @override
   bool get isConnected => _isConnected;
 
-  @override
-  Future<Map<String, dynamic>> prepareSend(
-      {required String address,
-      required int satoshiAmount,
-      Map<String, dynamic>? args}) async {
+  Future<Map<String, dynamic>> prepareSendPublic({
+    required String address,
+    required int satoshiAmount,
+    Map<String, dynamic>? args,
+  }) async {
     try {
+      final feeRateType = args?["feeRate"];
+      final feeRateAmount = args?["feeRateAmount"];
+      if (feeRateType is FeeRateType || feeRateAmount is int) {
+        late final int rate;
+        if (feeRateType is FeeRateType) {
+          int fee = 0;
+          final feeObject = await fees;
+          switch (feeRateType) {
+            case FeeRateType.fast:
+              fee = feeObject.fast;
+              break;
+            case FeeRateType.average:
+              fee = feeObject.medium;
+              break;
+            case FeeRateType.slow:
+              fee = feeObject.slow;
+              break;
+          }
+          rate = fee;
+        } else {
+          rate = feeRateAmount as int;
+        }
+
+        // check for send all
+        bool isSendAll = false;
+        final balance =
+            Format.decimalAmountToSatoshis(await availablePublicBalance());
+        if (satoshiAmount == balance) {
+          isSendAll = true;
+        }
+
+        final txData =
+            await coinSelection(satoshiAmount, rate, address, isSendAll);
+
+        Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
+        try {
+          if (txData is int) {
+            switch (txData) {
+              case 1:
+                throw Exception("Insufficient balance!");
+              case 2:
+                throw Exception(
+                    "Insufficient funds to pay for transaction fee!");
+              default:
+                throw Exception("Transaction failed with error code $txData");
+            }
+          } else {
+            final hex = txData["hex"];
+
+            if (hex is String) {
+              final fee = txData["fee"] as int;
+              final vSize = txData["vSize"] as int;
+
+              Logging.instance
+                  .log("prepared txHex: $hex", level: LogLevel.Info);
+              Logging.instance.log("prepared fee: $fee", level: LogLevel.Info);
+              Logging.instance
+                  .log("prepared vSize: $vSize", level: LogLevel.Info);
+
+              // fee should never be less than vSize sanity check
+              if (fee < vSize) {
+                throw Exception(
+                    "Error in fee calculation: Transaction fee cannot be less than vSize");
+              }
+
+              return txData as Map<String, dynamic>;
+            } else {
+              throw Exception("prepared hex is not a String!!!");
+            }
+          }
+        } catch (e, s) {
+          Logging.instance.log("Exception rethrown from prepareSend(): $e\n$s",
+              level: LogLevel.Error);
+          rethrow;
+        }
+      } else {
+        throw ArgumentError("Invalid fee rate argument provided!");
+      }
+    } catch (e, s) {
+      Logging.instance.log("Exception rethrown from prepareSend(): $e\n$s",
+          level: LogLevel.Error);
+      rethrow;
+    }
+  }
+
+  Future<String> confirmSendPublic({dynamic txData}) async {
+    try {
+      Logging.instance.log("confirmSend txData: $txData", level: LogLevel.Info);
+      final txHash = await _electrumXClient.broadcastTransaction(
+          rawTx: txData["hex"] as String);
+      Logging.instance.log("Sent txHash: $txHash", level: LogLevel.Info);
+      return txHash;
+    } catch (e, s) {
+      Logging.instance.log("Exception rethrown from confirmSend(): $e\n$s",
+          level: LogLevel.Error);
+      rethrow;
+    }
+  }
+
+  @override
+  Future<Map<String, dynamic>> prepareSend({
+    required String address,
+    required int satoshiAmount,
+    Map<String, dynamic>? args,
+  }) async {
+    try {
+      // check for send all
+      bool isSendAll = false;
+      final balance =
+          Format.decimalAmountToSatoshis(await availablePrivateBalance());
+      if (satoshiAmount == balance) {
+        print("is send all");
+        isSendAll = true;
+      }
       dynamic txHexOrError =
-          await _createJoinSplitTransaction(satoshiAmount, address, false);
+          await _createJoinSplitTransaction(satoshiAmount, address, isSendAll);
       Logging.instance.log("txHexOrError $txHexOrError", level: LogLevel.Error);
       if (txHexOrError is int) {
         // Here, we assume that transaction crafting returned an error
@@ -1129,6 +1278,531 @@ class FiroWallet extends CoinServiceAPI {
     isolates.clear();
   }
 
+  int estimateTxFee({required int vSize, required int feeRatePerKB}) {
+    return vSize * (feeRatePerKB / 1000).ceil();
+  }
+
+  /// The coinselection algorithm decides whether or not the user is eligible to make the transaction
+  /// with [satoshiAmountToSend] and [selectedTxFeeRate]. If so, it will call buildTrasaction() and return
+  /// a map containing the tx hex along with other important information. If not, then it will return
+  /// an integer (1 or 2)
+  dynamic coinSelection(
+    int satoshiAmountToSend,
+    int selectedTxFeeRate,
+    String _recipientAddress,
+    bool isSendAll, {
+    int additionalOutputs = 0,
+    List<UtxoObject>? utxos,
+  }) async {
+    Logging.instance
+        .log("Starting coinSelection ----------", level: LogLevel.Info);
+    final List<UtxoObject> availableOutputs = utxos ?? _outputsList;
+    final List<UtxoObject> spendableOutputs = [];
+    int spendableSatoshiValue = 0;
+
+    // Build list of spendable outputs and totaling their satoshi amount
+    for (var i = 0; i < availableOutputs.length; i++) {
+      if (availableOutputs[i].blocked == false &&
+          availableOutputs[i].status.confirmed == true) {
+        spendableOutputs.add(availableOutputs[i]);
+        spendableSatoshiValue += availableOutputs[i].value;
+      }
+    }
+
+    // sort spendable by age (oldest first)
+    spendableOutputs.sort(
+        (a, b) => b.status.confirmations.compareTo(a.status.confirmations));
+
+    Logging.instance.log("spendableOutputs.length: ${spendableOutputs.length}",
+        level: LogLevel.Info);
+    Logging.instance
+        .log("spendableOutputs: $spendableOutputs", level: LogLevel.Info);
+    Logging.instance.log("spendableSatoshiValue: $spendableSatoshiValue",
+        level: LogLevel.Info);
+    Logging.instance
+        .log("satoshiAmountToSend: $satoshiAmountToSend", level: LogLevel.Info);
+    // If the amount the user is trying to send is smaller than the amount that they have spendable,
+    // then return 1, which indicates that they have an insufficient balance.
+    if (spendableSatoshiValue < satoshiAmountToSend) {
+      return 1;
+      // If the amount the user wants to send is exactly equal to the amount they can spend, then return
+      // 2, which indicates that they are not leaving enough over to pay the transaction fee
+    } else if (spendableSatoshiValue == satoshiAmountToSend && !isSendAll) {
+      return 2;
+    }
+    // If neither of these statements pass, we assume that the user has a spendable balance greater
+    // than the amount they're attempting to send. Note that this value still does not account for
+    // the added transaction fee, which may require an extra input and will need to be checked for
+    // later on.
+
+    // Possible situation right here
+    int satoshisBeingUsed = 0;
+    int inputsBeingConsumed = 0;
+    List<UtxoObject> utxoObjectsToUse = [];
+
+    for (var i = 0;
+        satoshisBeingUsed < satoshiAmountToSend && i < spendableOutputs.length;
+        i++) {
+      utxoObjectsToUse.add(spendableOutputs[i]);
+      satoshisBeingUsed += spendableOutputs[i].value;
+      inputsBeingConsumed += 1;
+    }
+    for (int i = 0;
+        i < additionalOutputs && inputsBeingConsumed < spendableOutputs.length;
+        i++) {
+      utxoObjectsToUse.add(spendableOutputs[inputsBeingConsumed]);
+      satoshisBeingUsed += spendableOutputs[inputsBeingConsumed].value;
+      inputsBeingConsumed += 1;
+    }
+
+    Logging.instance
+        .log("satoshisBeingUsed: $satoshisBeingUsed", level: LogLevel.Info);
+    Logging.instance
+        .log("inputsBeingConsumed: $inputsBeingConsumed", level: LogLevel.Info);
+    Logging.instance
+        .log('utxoObjectsToUse: $utxoObjectsToUse', level: LogLevel.Info);
+
+    // numberOfOutputs' length must always be equal to that of recipientsArray and recipientsAmtArray
+    List<String> recipientsArray = [_recipientAddress];
+    List<int> recipientsAmtArray = [satoshiAmountToSend];
+
+    // gather required signing data
+    final utxoSigningData = await fetchBuildTxData(utxoObjectsToUse);
+
+    if (isSendAll) {
+      Logging.instance
+          .log("Attempting to send all $coin", level: LogLevel.Info);
+
+      final int vSizeForOneOutput = (await buildTransaction(
+        utxosToUse: utxoObjectsToUse,
+        utxoSigningData: utxoSigningData,
+        recipients: [_recipientAddress],
+        satoshiAmounts: [satoshisBeingUsed - 1],
+      ))["vSize"] as int;
+      int feeForOneOutput = estimateTxFee(
+        vSize: vSizeForOneOutput,
+        feeRatePerKB: selectedTxFeeRate,
+      );
+
+      if (feeForOneOutput < vSizeForOneOutput + 1) {
+        feeForOneOutput = vSizeForOneOutput + 1;
+      }
+
+      final int amount = satoshiAmountToSend - feeForOneOutput;
+      dynamic txn = await buildTransaction(
+        utxosToUse: utxoObjectsToUse,
+        utxoSigningData: utxoSigningData,
+        recipients: recipientsArray,
+        satoshiAmounts: [amount],
+      );
+      Map<String, dynamic> transactionObject = {
+        "hex": txn["hex"],
+        "recipient": recipientsArray[0],
+        "recipientAmt": amount,
+        "fee": feeForOneOutput,
+        "vSize": txn["vSize"],
+      };
+      return transactionObject;
+    }
+
+    final int vSizeForOneOutput = (await buildTransaction(
+      utxosToUse: utxoObjectsToUse,
+      utxoSigningData: utxoSigningData,
+      recipients: [_recipientAddress],
+      satoshiAmounts: [satoshisBeingUsed - 1],
+    ))["vSize"] as int;
+    final int vSizeForTwoOutPuts = (await buildTransaction(
+      utxosToUse: utxoObjectsToUse,
+      utxoSigningData: utxoSigningData,
+      recipients: [
+        _recipientAddress,
+        await _getCurrentAddressForChain(1),
+      ],
+      satoshiAmounts: [
+        satoshiAmountToSend,
+        satoshisBeingUsed - satoshiAmountToSend - 1,
+      ], // dust limit is the minimum amount a change output should be
+    ))["vSize"] as int;
+    debugPrint("vSizeForOneOutput $vSizeForOneOutput");
+    debugPrint("vSizeForTwoOutPuts $vSizeForTwoOutPuts");
+
+    // Assume 1 output, only for recipient and no change
+    var feeForOneOutput = estimateTxFee(
+      vSize: vSizeForOneOutput,
+      feeRatePerKB: selectedTxFeeRate,
+    );
+    // Assume 2 outputs, one for recipient and one for change
+    var feeForTwoOutputs = estimateTxFee(
+      vSize: vSizeForTwoOutPuts,
+      feeRatePerKB: selectedTxFeeRate,
+    );
+
+    Logging.instance
+        .log("feeForTwoOutputs: $feeForTwoOutputs", level: LogLevel.Info);
+    Logging.instance
+        .log("feeForOneOutput: $feeForOneOutput", level: LogLevel.Info);
+    if (feeForOneOutput < (vSizeForOneOutput + 1)) {
+      feeForOneOutput = (vSizeForOneOutput + 1);
+    }
+    if (feeForTwoOutputs < ((vSizeForTwoOutPuts + 1))) {
+      feeForTwoOutputs = ((vSizeForTwoOutPuts + 1));
+    }
+
+    Logging.instance
+        .log("feeForTwoOutputs: $feeForTwoOutputs", level: LogLevel.Info);
+    Logging.instance
+        .log("feeForOneOutput: $feeForOneOutput", level: LogLevel.Info);
+
+    if (satoshisBeingUsed - satoshiAmountToSend > feeForOneOutput) {
+      if (satoshisBeingUsed - satoshiAmountToSend >
+          feeForOneOutput + DUST_LIMIT) {
+        // Here, we know that theoretically, we may be able to include another output(change) but we first need to
+        // factor in the value of this output in satoshis.
+        int changeOutputSize =
+            satoshisBeingUsed - satoshiAmountToSend - feeForTwoOutputs;
+        // We check to see if the user can pay for the new transaction with 2 outputs instead of one. If they can and
+        // the second output's size > DUST_LIMIT satoshis, we perform the mechanics required to properly generate and use a new
+        // change address.
+        if (changeOutputSize > DUST_LIMIT &&
+            satoshisBeingUsed - satoshiAmountToSend - changeOutputSize ==
+                feeForTwoOutputs) {
+          // generate new change address if current change address has been used
+          await checkChangeAddressForTransactions();
+          final String newChangeAddress = await _getCurrentAddressForChain(1);
+
+          int feeBeingPaid =
+              satoshisBeingUsed - satoshiAmountToSend - changeOutputSize;
+
+          recipientsArray.add(newChangeAddress);
+          recipientsAmtArray.add(changeOutputSize);
+          // At this point, we have the outputs we're going to use, the amounts to send along with which addresses
+          // we intend to send these amounts to. We have enough to send instructions to build the transaction.
+          Logging.instance.log('2 outputs in tx', level: LogLevel.Info);
+          Logging.instance
+              .log('Input size: $satoshisBeingUsed', level: LogLevel.Info);
+          Logging.instance.log('Recipient output size: $satoshiAmountToSend',
+              level: LogLevel.Info);
+          Logging.instance.log('Change Output Size: $changeOutputSize',
+              level: LogLevel.Info);
+          Logging.instance.log(
+              'Difference (fee being paid): $feeBeingPaid sats',
+              level: LogLevel.Info);
+          Logging.instance
+              .log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
+          dynamic txn = await buildTransaction(
+            utxosToUse: utxoObjectsToUse,
+            utxoSigningData: utxoSigningData,
+            recipients: recipientsArray,
+            satoshiAmounts: recipientsAmtArray,
+          );
+
+          // make sure minimum fee is accurate if that is being used
+          if (txn["vSize"] - feeBeingPaid == 1) {
+            int changeOutputSize =
+                satoshisBeingUsed - satoshiAmountToSend - (txn["vSize"] as int);
+            feeBeingPaid =
+                satoshisBeingUsed - satoshiAmountToSend - changeOutputSize;
+            recipientsAmtArray.removeLast();
+            recipientsAmtArray.add(changeOutputSize);
+            Logging.instance.log('Adjusted Input size: $satoshisBeingUsed',
+                level: LogLevel.Info);
+            Logging.instance.log(
+                'Adjusted Recipient output size: $satoshiAmountToSend',
+                level: LogLevel.Info);
+            Logging.instance.log(
+                'Adjusted Change Output Size: $changeOutputSize',
+                level: LogLevel.Info);
+            Logging.instance.log(
+                'Adjusted Difference (fee being paid): $feeBeingPaid sats',
+                level: LogLevel.Info);
+            Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs',
+                level: LogLevel.Info);
+            txn = await buildTransaction(
+              utxosToUse: utxoObjectsToUse,
+              utxoSigningData: utxoSigningData,
+              recipients: recipientsArray,
+              satoshiAmounts: recipientsAmtArray,
+            );
+          }
+
+          Map<String, dynamic> transactionObject = {
+            "hex": txn["hex"],
+            "recipient": recipientsArray[0],
+            "recipientAmt": recipientsAmtArray[0],
+            "fee": feeBeingPaid,
+            "vSize": txn["vSize"],
+          };
+          return transactionObject;
+        } else {
+          // Something went wrong here. It either overshot or undershot the estimated fee amount or the changeOutputSize
+          // is smaller than or equal to [DUST_LIMIT]. Revert to single output transaction.
+          Logging.instance.log('1 output in tx', level: LogLevel.Info);
+          Logging.instance
+              .log('Input size: $satoshisBeingUsed', level: LogLevel.Info);
+          Logging.instance.log('Recipient output size: $satoshiAmountToSend',
+              level: LogLevel.Info);
+          Logging.instance.log(
+              'Difference (fee being paid): ${satoshisBeingUsed - satoshiAmountToSend} sats',
+              level: LogLevel.Info);
+          Logging.instance
+              .log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
+          dynamic txn = await buildTransaction(
+            utxosToUse: utxoObjectsToUse,
+            utxoSigningData: utxoSigningData,
+            recipients: recipientsArray,
+            satoshiAmounts: recipientsAmtArray,
+          );
+          Map<String, dynamic> transactionObject = {
+            "hex": txn["hex"],
+            "recipient": recipientsArray[0],
+            "recipientAmt": recipientsAmtArray[0],
+            "fee": satoshisBeingUsed - satoshiAmountToSend,
+            "vSize": txn["vSize"],
+          };
+          return transactionObject;
+        }
+      } else {
+        // No additional outputs needed since adding one would mean that it'd be smaller than 546 sats
+        // which makes it uneconomical to add to the transaction. Here, we pass data directly to instruct
+        // the wallet to begin crafting the transaction that the user requested.
+        Logging.instance.log('1 output in tx', level: LogLevel.Info);
+        Logging.instance
+            .log('Input size: $satoshisBeingUsed', level: LogLevel.Info);
+        Logging.instance.log('Recipient output size: $satoshiAmountToSend',
+            level: LogLevel.Info);
+        Logging.instance.log(
+            'Difference (fee being paid): ${satoshisBeingUsed - satoshiAmountToSend} sats',
+            level: LogLevel.Info);
+        Logging.instance
+            .log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
+        dynamic txn = await buildTransaction(
+          utxosToUse: utxoObjectsToUse,
+          utxoSigningData: utxoSigningData,
+          recipients: recipientsArray,
+          satoshiAmounts: recipientsAmtArray,
+        );
+        Map<String, dynamic> transactionObject = {
+          "hex": txn["hex"],
+          "recipient": recipientsArray[0],
+          "recipientAmt": recipientsAmtArray[0],
+          "fee": satoshisBeingUsed - satoshiAmountToSend,
+          "vSize": txn["vSize"],
+        };
+        return transactionObject;
+      }
+    } else if (satoshisBeingUsed - satoshiAmountToSend == feeForOneOutput) {
+      // In this scenario, no additional change output is needed since inputs - outputs equal exactly
+      // what we need to pay for fees. Here, we pass data directly to instruct the wallet to begin
+      // crafting the transaction that the user requested.
+      Logging.instance.log('1 output in tx', level: LogLevel.Info);
+      Logging.instance
+          .log('Input size: $satoshisBeingUsed', level: LogLevel.Info);
+      Logging.instance.log('Recipient output size: $satoshiAmountToSend',
+          level: LogLevel.Info);
+      Logging.instance.log(
+          'Fee being paid: ${satoshisBeingUsed - satoshiAmountToSend} sats',
+          level: LogLevel.Info);
+      Logging.instance
+          .log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
+      dynamic txn = await buildTransaction(
+        utxosToUse: utxoObjectsToUse,
+        utxoSigningData: utxoSigningData,
+        recipients: recipientsArray,
+        satoshiAmounts: recipientsAmtArray,
+      );
+      Map<String, dynamic> transactionObject = {
+        "hex": txn["hex"],
+        "recipient": recipientsArray[0],
+        "recipientAmt": recipientsAmtArray[0],
+        "fee": feeForOneOutput,
+        "vSize": txn["vSize"],
+      };
+      return transactionObject;
+    } else {
+      // Remember that returning 2 indicates that the user does not have a sufficient balance to
+      // pay for the transaction fee. Ideally, at this stage, we should check if the user has any
+      // additional outputs they're able to spend and then recalculate fees.
+      Logging.instance.log(
+          'Cannot pay tx fee - checking for more outputs and trying again',
+          level: LogLevel.Warning);
+      // try adding more outputs
+      if (spendableOutputs.length > inputsBeingConsumed) {
+        return coinSelection(satoshiAmountToSend, selectedTxFeeRate,
+            _recipientAddress, isSendAll,
+            additionalOutputs: additionalOutputs + 1, utxos: utxos);
+      }
+      return 2;
+    }
+  }
+
+  Future<Map<String, dynamic>> fetchBuildTxData(
+    List<UtxoObject> utxosToUse,
+  ) async {
+    // return data
+    Map<String, dynamic> results = {};
+    Map<String, List<String>> addressTxid = {};
+
+    // addresses to check
+    List<String> addresses = [];
+
+    try {
+      // Populating the addresses to check
+      for (var i = 0; i < utxosToUse.length; i++) {
+        final txid = utxosToUse[i].txid;
+        final tx = await _cachedElectrumXClient.getTransaction(
+          txHash: txid,
+          coin: coin,
+        );
+
+        for (final output in tx["vout"] as List) {
+          final n = output["n"];
+          if (n != null && n == utxosToUse[i].vout) {
+            final address = output["scriptPubKey"]["addresses"][0] as String;
+
+            if (!addressTxid.containsKey(address)) {
+              addressTxid[address] = <String>[];
+            }
+            (addressTxid[address] as List).add(txid);
+
+            addresses.add(address);
+          }
+        }
+      }
+
+      // p2pkh / bip44
+      final addressesLength = addresses.length;
+      if (addressesLength > 0) {
+        final receiveDerivationsString =
+            await _secureStore.read(key: "${walletId}_receiveDerivations");
+        final receiveDerivations = Map<String, dynamic>.from(
+            jsonDecode(receiveDerivationsString ?? "{}") as Map);
+
+        final changeDerivationsString =
+            await _secureStore.read(key: "${walletId}_changeDerivations");
+        final changeDerivations = Map<String, dynamic>.from(
+            jsonDecode(changeDerivationsString ?? "{}") as Map);
+
+        for (int i = 0; i < addressesLength; i++) {
+          // receives
+
+          dynamic receiveDerivation;
+
+          for (int j = 0; j < receiveDerivations.length; j++) {
+            if (receiveDerivations["$j"]["address"] == addresses[i]) {
+              receiveDerivation = receiveDerivations["$j"];
+            }
+          }
+
+          // receiveDerivation = receiveDerivations[addresses[i]];
+          // if a match exists it will not be null
+          if (receiveDerivation != null) {
+            final data = P2PKH(
+              data: PaymentData(
+                  pubkey: Format.stringToUint8List(
+                      receiveDerivation["publicKey"] as String)),
+              network: _network,
+            ).data;
+
+            for (String tx in addressTxid[addresses[i]]!) {
+              results[tx] = {
+                "output": data.output,
+                "keyPair": ECPair.fromWIF(
+                  receiveDerivation["wif"] as String,
+                  network: _network,
+                ),
+              };
+            }
+          } else {
+            // if its not a receive, check change
+
+            dynamic changeDerivation;
+
+            for (int j = 0; j < changeDerivations.length; j++) {
+              if (changeDerivations["$j"]["address"] == addresses[i]) {
+                changeDerivation = changeDerivations["$j"];
+              }
+            }
+
+            // final changeDerivation = changeDerivations[addresses[i]];
+            // if a match exists it will not be null
+            if (changeDerivation != null) {
+              final data = P2PKH(
+                data: PaymentData(
+                    pubkey: Format.stringToUint8List(
+                        changeDerivation["publicKey"] as String)),
+                network: _network,
+              ).data;
+
+              for (String tx in addressTxid[addresses[i]]!) {
+                results[tx] = {
+                  "output": data.output,
+                  "keyPair": ECPair.fromWIF(
+                    changeDerivation["wif"] as String,
+                    network: _network,
+                  ),
+                };
+              }
+            }
+          }
+        }
+      }
+
+      return results;
+    } catch (e, s) {
+      Logging.instance
+          .log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error);
+      rethrow;
+    }
+  }
+
+  /// Builds and signs a transaction
+  Future<Map<String, dynamic>> buildTransaction({
+    required List<UtxoObject> utxosToUse,
+    required Map<String, dynamic> utxoSigningData,
+    required List<String> recipients,
+    required List<int> satoshiAmounts,
+  }) async {
+    Logging.instance
+        .log("Starting buildTransaction ----------", level: LogLevel.Info);
+
+    final txb = TransactionBuilder(network: _network);
+    txb.setVersion(1);
+
+    // Add transaction inputs
+    for (var i = 0; i < utxosToUse.length; i++) {
+      final txid = utxosToUse[i].txid;
+      txb.addInput(txid, utxosToUse[i].vout, null,
+          utxoSigningData[txid]["output"] as Uint8List);
+    }
+
+    // Add transaction output
+    for (var i = 0; i < recipients.length; i++) {
+      txb.addOutput(recipients[i], satoshiAmounts[i]);
+    }
+
+    try {
+      // Sign the transaction accordingly
+      for (var i = 0; i < utxosToUse.length; i++) {
+        final txid = utxosToUse[i].txid;
+        txb.sign(
+          vin: i,
+          keyPair: utxoSigningData[txid]["keyPair"] as ECPair,
+          witnessValue: utxosToUse[i].value,
+          redeemScript: utxoSigningData[txid]["redeemScript"] as Uint8List?,
+        );
+      }
+    } catch (e, s) {
+      Logging.instance.log("Caught exception while signing transaction: $e\n$s",
+          level: LogLevel.Error);
+      rethrow;
+    }
+
+    final builtTx = txb.build();
+    final vSize = builtTx.virtualSize();
+
+    return {"hex": builtTx.toHex(), "vSize": vSize};
+  }
+
   @override
   Future<void> updateNode(bool shouldRefresh) async {
     final failovers = NodeService()
@@ -1156,7 +1830,7 @@ class FiroWallet extends CoinServiceAPI {
     );
 
     if (shouldRefresh) {
-      refresh();
+      unawaited(refresh());
     }
   }
 
@@ -1333,32 +2007,36 @@ class FiroWallet extends CoinServiceAPI {
     for (final tx in unconfirmedTxnsToNotifyPending) {
       switch (tx.txType) {
         case "Received":
-          NotificationApi.showNotification(
-            title: "Incoming transaction",
-            body: walletName,
-            walletId: walletId,
-            iconAssetName: Assets.svg.iconFor(coin: coin),
-            date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000),
-            shouldWatchForUpdates: tx.confirmations < MINIMUM_CONFIRMATIONS,
-            coinName: coin.name,
-            txid: tx.txid,
-            confirmations: tx.confirmations,
-            requiredConfirmations: MINIMUM_CONFIRMATIONS,
+          unawaited(
+            NotificationApi.showNotification(
+              title: "Incoming transaction",
+              body: walletName,
+              walletId: walletId,
+              iconAssetName: Assets.svg.iconFor(coin: coin),
+              date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000),
+              shouldWatchForUpdates: tx.confirmations < MINIMUM_CONFIRMATIONS,
+              coinName: coin.name,
+              txid: tx.txid,
+              confirmations: tx.confirmations,
+              requiredConfirmations: MINIMUM_CONFIRMATIONS,
+            ),
           );
           await txTracker.addNotifiedPending(tx.txid);
           break;
         case "Sent":
-          NotificationApi.showNotification(
-            title: "Outgoing transaction",
-            body: walletName,
-            walletId: walletId,
-            iconAssetName: Assets.svg.iconFor(coin: coin),
-            date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000),
-            shouldWatchForUpdates: tx.confirmations < MINIMUM_CONFIRMATIONS,
-            coinName: coin.name,
-            txid: tx.txid,
-            confirmations: tx.confirmations,
-            requiredConfirmations: MINIMUM_CONFIRMATIONS,
+          unawaited(
+            NotificationApi.showNotification(
+              title: "Outgoing transaction",
+              body: walletName,
+              walletId: walletId,
+              iconAssetName: Assets.svg.iconFor(coin: coin),
+              date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000),
+              shouldWatchForUpdates: tx.confirmations < MINIMUM_CONFIRMATIONS,
+              coinName: coin.name,
+              txid: tx.txid,
+              confirmations: tx.confirmations,
+              requiredConfirmations: MINIMUM_CONFIRMATIONS,
+            ),
           );
           await txTracker.addNotifiedPending(tx.txid);
           break;
@@ -1369,25 +2047,29 @@ class FiroWallet extends CoinServiceAPI {
 
     for (final tx in unconfirmedTxnsToNotifyConfirmed) {
       if (tx.txType == "Received") {
-        NotificationApi.showNotification(
-          title: "Incoming transaction confirmed",
-          body: walletName,
-          walletId: walletId,
-          iconAssetName: Assets.svg.iconFor(coin: coin),
-          date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000),
-          shouldWatchForUpdates: false,
-          coinName: coin.name,
+        unawaited(
+          NotificationApi.showNotification(
+            title: "Incoming transaction confirmed",
+            body: walletName,
+            walletId: walletId,
+            iconAssetName: Assets.svg.iconFor(coin: coin),
+            date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000),
+            shouldWatchForUpdates: false,
+            coinName: coin.name,
+          ),
         );
         await txTracker.addNotifiedConfirmed(tx.txid);
       } else if (tx.txType == "Sent" && tx.subType == "join") {
-        NotificationApi.showNotification(
-          title: "Outgoing transaction confirmed",
-          body: walletName,
-          walletId: walletId,
-          iconAssetName: Assets.svg.iconFor(coin: coin),
-          date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000),
-          shouldWatchForUpdates: false,
-          coinName: coin.name,
+        unawaited(
+          NotificationApi.showNotification(
+            title: "Outgoing transaction confirmed",
+            body: walletName,
+            walletId: walletId,
+            iconAssetName: Assets.svg.iconFor(coin: coin),
+            date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000),
+            shouldWatchForUpdates: false,
+            coinName: coin.name,
+          ),
         );
         await txTracker.addNotifiedConfirmed(tx.txid);
       }
@@ -1520,14 +2202,14 @@ class FiroWallet extends CoinServiceAPI {
       GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.60, walletId));
 
       final lelantusCoins = getLelantusCoinMap();
-      Logging.instance.log("_lelantus_coins at refresh: ${lelantusCoins}",
+      Logging.instance.log("_lelantus_coins at refresh: $lelantusCoins",
           level: LogLevel.Warning, printFullLength: true);
       GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.70, walletId));
 
       await _refreshLelantusData();
       GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.80, walletId));
 
-      await autoMint();
+      // await autoMint();
       GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.90, walletId));
 
       var balance = await _getFullBalance();
@@ -1590,7 +2272,7 @@ class FiroWallet extends CoinServiceAPI {
     final balance = await availableBalance;
     int spendAmount =
         (balance * Decimal.fromInt(Constants.satsPerCoin)).toBigInt().toInt();
-    int fee = await EstimateJoinSplitFee(spendAmount);
+    int fee = await estimateJoinSplitFee(spendAmount);
     return fee;
   }
 
@@ -1643,7 +2325,7 @@ class FiroWallet extends CoinServiceAPI {
 
   Future<List<LelantusCoin>> _getUnspentCoins() async {
     final List<Map<dynamic, LelantusCoin>> lelantusCoins = getLelantusCoinMap();
-    if (lelantusCoins != null && lelantusCoins.isNotEmpty) {
+    if (lelantusCoins.isNotEmpty) {
       lelantusCoins.removeWhere((element) =>
           element.values.any((elementCoin) => elementCoin.value == 0));
     }
@@ -1652,9 +2334,6 @@ class FiroWallet extends CoinServiceAPI {
     final data = await _txnData;
     final lelantusData = await lelantusTransactionData;
     List<LelantusCoin> coins = [];
-    if (lelantusCoins == null) {
-      return coins;
-    }
 
     List<LelantusCoin> lelantusCoinsList =
         lelantusCoins.fold(<LelantusCoin>[], (previousValue, element) {
@@ -1699,7 +2378,7 @@ class FiroWallet extends CoinServiceAPI {
     try {
       final List<Map<dynamic, LelantusCoin>> lelantusCoins =
           getLelantusCoinMap();
-      if (lelantusCoins != null && lelantusCoins.isNotEmpty) {
+      if (lelantusCoins.isNotEmpty) {
         lelantusCoins.removeWhere((element) =>
             element.values.any((elementCoin) => elementCoin.value == 0));
       }
@@ -1711,32 +2390,32 @@ class FiroWallet extends CoinServiceAPI {
           DB.instance.get<dynamic>(boxName: walletId, key: 'jindex') as List?;
       int intLelantusBalance = 0;
       int unconfirmedLelantusBalance = 0;
-      if (lelantusCoins != null) {
-        lelantusCoins.forEach((element) {
-          element.forEach((key, value) {
-            final tx = data.findTransaction(value.txId);
-            models.Transaction? ltx;
-            ltx = lData.findTransaction(value.txId);
-            // Logging.instance.log("$value $tx $ltx");
-            if (!jindexes!.contains(value.index) && tx == null) {
-              // This coin is not confirmed and may be replaced
-            } else if (jindexes.contains(value.index) &&
-                tx == null &&
-                !value.isUsed &&
-                ltx != null &&
-                !ltx.confirmedStatus) {
-              unconfirmedLelantusBalance += value.value;
-            } else if (jindexes.contains(value.index) && !value.isUsed) {
-              intLelantusBalance += value.value;
-            } else if (!value.isUsed &&
-                (tx == null ? true : tx.confirmedStatus != false)) {
-              intLelantusBalance += value.value;
-            } else if (tx != null && tx.confirmedStatus == false) {
-              unconfirmedLelantusBalance += value.value;
-            }
-          });
+
+      for (var element in lelantusCoins) {
+        element.forEach((key, value) {
+          final tx = data.findTransaction(value.txId);
+          models.Transaction? ltx;
+          ltx = lData.findTransaction(value.txId);
+          // Logging.instance.log("$value $tx $ltx");
+          if (!jindexes!.contains(value.index) && tx == null) {
+            // This coin is not confirmed and may be replaced
+          } else if (jindexes.contains(value.index) &&
+              tx == null &&
+              !value.isUsed &&
+              ltx != null &&
+              !ltx.confirmedStatus) {
+            unconfirmedLelantusBalance += value.value;
+          } else if (jindexes.contains(value.index) && !value.isUsed) {
+            intLelantusBalance += value.value;
+          } else if (!value.isUsed &&
+              (tx == null ? true : tx.confirmedStatus != false)) {
+            intLelantusBalance += value.value;
+          } else if (tx != null && tx.confirmedStatus == false) {
+            unconfirmedLelantusBalance += value.value;
+          }
         });
       }
+
       final int utxosIntValue = utxos.satoshiBalance;
       final Decimal utxosValue = Format.satoshisToAmount(utxosIntValue);
 
@@ -1756,6 +2435,13 @@ class FiroWallet extends CoinServiceAPI {
       balances.add(
           (lelantusBalance + utxosValue + _unconfirmedLelantusBalance) * price);
 
+      int availableSats =
+          utxos.satoshiBalance - utxos.satoshiBalanceUnconfirmed;
+      if (availableSats < 0) {
+        availableSats = 0;
+      }
+      balances.add(Format.satoshisToAmount(availableSats));
+
       Logging.instance.log("balances $balances", level: LogLevel.Info);
       await DB.instance.put<dynamic>(
           boxName: walletId,
@@ -1769,7 +2455,7 @@ class FiroWallet extends CoinServiceAPI {
     }
   }
 
-  Future<void> autoMint() async {
+  Future<void> anonymizeAllPublicFunds() async {
     try {
       var mintResult = await _mintSelection();
       if (mintResult.isEmpty) {
@@ -1777,9 +2463,12 @@ class FiroWallet extends CoinServiceAPI {
         return;
       }
       await _submitLelantusToNetwork(mintResult);
+      unawaited(refresh());
     } catch (e, s) {
-      Logging.instance.log("Exception caught in _autoMint(): $e\n$s",
-          level: LogLevel.Error);
+      Logging.instance.log(
+          "Exception caught in anonymizeAllPublicFunds(): $e\n$s",
+          level: LogLevel.Warning);
+      rethrow;
     }
   }
 
@@ -1799,29 +2488,27 @@ class FiroWallet extends CoinServiceAPI {
     }
 
     final List<Map<dynamic, LelantusCoin>> lelantusCoins = getLelantusCoinMap();
-    if (lelantusCoins != null && lelantusCoins.isNotEmpty) {
+    if (lelantusCoins.isNotEmpty) {
       lelantusCoins.removeWhere((element) =>
           element.values.any((elementCoin) => elementCoin.value == 0));
     }
     final data = await _txnData;
-    if (lelantusCoins != null) {
-      final dataMap = data.getAllTransactions();
-      dataMap.forEach((key, value) {
-        if (value.inputs.isNotEmpty) {
-          for (var element in value.inputs) {
-            if (lelantusCoins
-                    .any((element) => element.keys.contains(value.txid)) &&
-                spendableOutputs.firstWhere(
-                        (output) => output?.txid == element.txid,
-                        orElse: () => null) !=
-                    null) {
-              spendableOutputs
-                  .removeWhere((output) => output!.txid == element.txid);
-            }
+    final dataMap = data.getAllTransactions();
+    dataMap.forEach((key, value) {
+      if (value.inputs.isNotEmpty) {
+        for (var element in value.inputs) {
+          if (lelantusCoins
+                  .any((element) => element.keys.contains(value.txid)) &&
+              spendableOutputs.firstWhere(
+                      (output) => output?.txid == element.txid,
+                      orElse: () => null) !=
+                  null) {
+            spendableOutputs
+                .removeWhere((output) => output!.txid == element.txid);
           }
         }
-      });
-    }
+      }
+    });
 
     // If there is no Utxos to mint then stop the function.
     if (spendableOutputs.isEmpty) {
@@ -1876,18 +2563,18 @@ class FiroWallet extends CoinServiceAPI {
     var tmpTotal = total;
     var index = 0;
     var mints = <Map<String, dynamic>>[];
-    final next_free_mint_index =
+    final nextFreeMintIndex =
         DB.instance.get<dynamic>(boxName: walletId, key: 'mintIndex') as int;
     while (tmpTotal > 0) {
       final mintValue = min(tmpTotal, MINT_LIMIT);
       final mint = await _getMintHex(
         mintValue,
-        next_free_mint_index + index,
+        nextFreeMintIndex + index,
       );
       mints.add({
         "value": mintValue,
         "script": mint,
-        "index": next_free_mint_index + index,
+        "index": nextFreeMintIndex + index,
         "publicCoin": "",
       });
       tmpTotal = tmpTotal - MINT_LIMIT;
@@ -2072,17 +2759,14 @@ class FiroWallet extends CoinServiceAPI {
         joinsplits.add(tx.txid);
       }
     }
-    if (lelantusCoins != null) {
-      for (final coin
-          in lelantusCoins.fold(<LelantusCoin>[], (previousValue, element) {
-        (previousValue as List<LelantusCoin>).add(element.values.first);
-        return previousValue;
-      })) {
-        if (jindexes != null) {
-          if (jindexes.contains(coin.index) &&
-              !joinsplits.contains(coin.txId)) {
-            joinsplits.add(coin.txId);
-          }
+    for (final coin
+        in lelantusCoins.fold(<LelantusCoin>[], (previousValue, element) {
+      (previousValue as List<LelantusCoin>).add(element.values.first);
+      return previousValue;
+    })) {
+      if (jindexes != null) {
+        if (jindexes.contains(coin.index) && !joinsplits.contains(coin.txId)) {
+          joinsplits.add(coin.txId);
         }
       }
     }
@@ -2096,13 +2780,13 @@ class FiroWallet extends CoinServiceAPI {
 
     // update all of joinsplits that are now confirmed.
     for (final tx in updatedJSplit) {
-      final currenttx = listLelantusTxData[tx.txid];
-      if (currenttx == null) {
+      final currentTx = listLelantusTxData[tx.txid];
+      if (currentTx == null) {
         // this send was accidentally not included in the list
         listLelantusTxData[tx.txid] = tx;
         continue;
       }
-      if (currenttx.confirmedStatus != tx.confirmedStatus) {
+      if (currentTx.confirmedStatus != tx.confirmedStatus) {
         listLelantusTxData[tx.txid] = tx;
       }
     }
@@ -2113,43 +2797,25 @@ class FiroWallet extends CoinServiceAPI {
     final listTxData = txData.getAllTransactions();
     listTxData.forEach((key, value) {
       // ignore change addresses
-      bool hasAtLeastOneRecieve = false;
-      int howManyRecieveInputs = 0;
+      bool hasAtLeastOneReceive = false;
+      // int howManyReceiveInputs = 0;
       for (var element in value.inputs) {
         if (listLelantusTxData.containsKey(element.txid) &&
                 listLelantusTxData[element.txid]!.txType == "Received"
             // &&
             // listLelantusTxData[element.txid].subType != "mint"
             ) {
-          hasAtLeastOneRecieve = true;
-          howManyRecieveInputs++;
+          hasAtLeastOneReceive = true;
+          // howManyReceiveInputs++;
         }
       }
 
-      if (value.txType == "Received" &&
-          !listLelantusTxData.containsKey(value.txid)) {
-        // Every receive should be listed whether minted or not.
+      if (value.txType == "Received" && value.subType != "mint") {
+        // Every receive other than a mint should be shown. Mints will be collected and shown from the send side
+        listLelantusTxData[value.txid] = value;
+      } else if (value.txType == "Sent") {
+        // all sends should be shown, mints will be displayed correctly in the ui
         listLelantusTxData[value.txid] = value;
-      } else if (value.txType == "Sent" &&
-          hasAtLeastOneRecieve &&
-          value.subType == "mint") {
-        // use mint sends to update receives with user readable values.
-
-        int sharedFee = value.fees ~/ howManyRecieveInputs;
-
-        for (var element in value.inputs) {
-          if (listLelantusTxData.containsKey(element.txid) &&
-              listLelantusTxData[element.txid]!.txType == "Received") {
-            listLelantusTxData[element.txid] =
-                listLelantusTxData[element.txid]!.copyWith(
-              fees: sharedFee,
-              subType: "mint",
-              height: value.height,
-              confirmedStatus: value.confirmedStatus,
-              otherData: value.txid,
-            );
-          }
-        }
       }
     });
 
@@ -2191,6 +2857,7 @@ class FiroWallet extends CoinServiceAPI {
 
   Future<bool> _submitLelantusToNetwork(
       Map<String, dynamic> transactionInfo) async {
+    final latestSetId = await getLatestSetId();
     final txid = await submitHexToNetwork(transactionInfo['txHex'] as String);
     // success if txid matches the generated txid
     Logging.instance.log(
@@ -2202,7 +2869,7 @@ class FiroWallet extends CoinServiceAPI {
       final List<Map<dynamic, LelantusCoin>> lelantusCoins =
           getLelantusCoinMap();
       List<Map<dynamic, LelantusCoin>> coins;
-      if (lelantusCoins == null || lelantusCoins.isEmpty) {
+      if (lelantusCoins.isEmpty) {
         coins = [];
       } else {
         coins = [...lelantusCoins];
@@ -2212,16 +2879,16 @@ class FiroWallet extends CoinServiceAPI {
         // This is a joinsplit
 
         // Update all of the coins that have been spent.
-        for (final lcoinmap in coins) {
-          final lcoin = lcoinmap.values.first;
+        for (final lCoinMap in coins) {
+          final lCoin = lCoinMap.values.first;
           if ((transactionInfo['spendCoinIndexes'] as List<int>)
-              .contains(lcoin.index)) {
-            lcoinmap[lcoinmap.keys.first] = LelantusCoin(
-                lcoin.index,
-                lcoin.value,
-                lcoin.publicCoin,
-                lcoin.txId,
-                lcoin.anonymitySetId,
+              .contains(lCoin.index)) {
+            lCoinMap[lCoinMap.keys.first] = LelantusCoin(
+                lCoin.index,
+                lCoin.value,
+                lCoin.publicCoin,
+                lCoin.txId,
+                lCoin.anonymitySetId,
                 true);
           }
         }
@@ -2232,7 +2899,7 @@ class FiroWallet extends CoinServiceAPI {
             transactionInfo['jmintValue'] as int? ?? 0,
             transactionInfo['publicCoin'] as String,
             transactionInfo['txid'] as String,
-            1,
+            latestSetId,
             false);
         if (jmint.value > 0) {
           coins.add({jmint.txId: jmint});
@@ -2276,7 +2943,7 @@ class FiroWallet extends CoinServiceAPI {
             mintMap['value'] as int,
             mintMap['publicCoin'] as String,
             transactionInfo['txid'] as String,
-            1,
+            latestSetId,
             false,
           );
           if (mint.value > 0) {
@@ -2389,12 +3056,45 @@ class FiroWallet extends CoinServiceAPI {
       }
     } on SocketException catch (se, s) {
       Logging.instance.log(
-          "SocketException caught in _checkReceivingAddressForTransactions(): $se\n$s",
+          "SocketException caught in checkReceivingAddressForTransactions(): $se\n$s",
           level: LogLevel.Error);
       return;
     } catch (e, s) {
       Logging.instance.log(
-          "Exception rethrown from _checkReceivingAddressForTransactions(): $e\n$s",
+          "Exception rethrown from checkReceivingAddressForTransactions(): $e\n$s",
+          level: LogLevel.Error);
+      rethrow;
+    }
+  }
+
+  Future<void> checkChangeAddressForTransactions() async {
+    try {
+      final String currentExternalAddr = await _getCurrentAddressForChain(1);
+      final int numtxs =
+          await _getReceivedTxCount(address: currentExternalAddr);
+      Logging.instance.log(
+          'Number of txs for current change address: $currentExternalAddr: $numtxs',
+          level: LogLevel.Info);
+
+      if (numtxs >= 1) {
+        await incrementAddressIndexForChain(
+            0); // First increment the change index
+        final newReceivingIndex =
+            DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndex')
+                as int; // Check the new change index
+        final newReceivingAddress = await _generateAddressForChain(0,
+            newReceivingIndex); // Use new index to derive a new change address
+        await addToAddressesArrayForChain(newReceivingAddress,
+            0); // Add that new receiving address to the array of change addresses
+      }
+    } on SocketException catch (se, s) {
+      Logging.instance.log(
+          "SocketException caught in checkChangeAddressForTransactions(): $se\n$s",
+          level: LogLevel.Error);
+      return;
+    } catch (e, s) {
+      Logging.instance.log(
+          "Exception rethrown from checkChangeAddressForTransactions(): $e\n$s",
           level: LogLevel.Error);
       rethrow;
     }
@@ -2624,11 +3324,12 @@ class FiroWallet extends CoinServiceAPI {
         }
       }
 
+      final int confirms = txObject["confirmations"] as int? ?? 0;
+
       // create final tx map
       midSortedTx["txid"] = txObject["txid"];
-      midSortedTx["confirmed_status"] = (txObject["confirmations"] is int) &&
-          (txObject["confirmations"] as int > 0);
-      midSortedTx["confirmations"] = txObject["confirmations"] ?? 0;
+      midSortedTx["confirmed_status"] = confirms >= MINIMUM_CONFIRMATIONS;
+      midSortedTx["confirmations"] = confirms;
       midSortedTx["timestamp"] = txObject["blocktime"] ??
           (DateTime.now().millisecondsSinceEpoch ~/ 1000);
       if (foundInSenders) {
@@ -2774,6 +3475,7 @@ class FiroWallet extends CoinServiceAPI {
       Decimal currentPrice = await firoPrice;
       final List<Map<String, dynamic>> outputArray = [];
       int satoshiBalance = 0;
+      int satoshiBalancePending = 0;
 
       for (int i = 0; i < utxoData.length; i++) {
         for (int j = 0; j < utxoData[i].length; j++) {
@@ -2787,16 +3489,22 @@ class FiroWallet extends CoinServiceAPI {
           );
 
           final Map<String, dynamic> tx = {};
+          final int confirmations = txn["confirmations"] as int? ?? 0;
+          final bool confirmed = confirmations >= MINIMUM_CONFIRMATIONS;
+          if (!confirmed) {
+            satoshiBalancePending += value;
+          }
 
           tx["txid"] = txn["txid"];
           tx["vout"] = utxoData[i][j]["tx_pos"];
           tx["value"] = value;
 
           tx["status"] = <String, dynamic>{};
+          tx["status"]["confirmed"] = confirmed;
+          tx["status"]["confirmations"] = confirmations;
           tx["status"]["confirmed"] =
               txn["confirmations"] == null ? false : txn["confirmations"] > 0;
-          tx["status"]["confirmations"] =
-              txn["confirmations"] == null ? 0 : txn["confirmations"]!;
+
           tx["status"]["block_height"] = txn["height"];
           tx["status"]["block_hash"] = txn["blockhash"];
           tx["status"]["block_time"] = txn["blocktime"];
@@ -2824,6 +3532,7 @@ class FiroWallet extends CoinServiceAPI {
             .toDecimal(scaleOnInfinitePrecision: Constants.decimalPlaces)
             .toString(),
         "outputArray": outputArray,
+        "unconfirmed": satoshiBalancePending,
       };
 
       final dataModel = UtxoData.fromJson(result);
@@ -2834,7 +3543,7 @@ class FiroWallet extends CoinServiceAPI {
       await DB.instance.put<dynamic>(
           boxName: walletId, key: 'latest_utxo_model', value: dataModel);
       return dataModel;
-    } catch (e, s) {
+    } catch (e) {
       // Logging.instance.log("Output fetch unsuccessful: $e\n$s");
       final latestTxModel =
           DB.instance.get<dynamic>(boxName: walletId, key: 'latest_utxo_model')
@@ -3095,7 +3804,7 @@ class FiroWallet extends CoinServiceAPI {
     );
 
     // clear cache
-    _cachedElectrumXClient.clearSharedTransactionCache(coin: coin);
+    await _cachedElectrumXClient.clearSharedTransactionCache(coin: coin);
 
     // back up data
     await _rescanBackup();
@@ -3686,7 +4395,7 @@ class FiroWallet extends CoinServiceAPI {
         this.isActive = isActive;
       };
 
-  Future<dynamic> GetCoinsToJoinSplit(
+  Future<dynamic> getCoinsToJoinSplit(
     int required,
   ) async {
     List<DartLelantusEntry> coins = await _getLelantusEntry();
@@ -3695,7 +4404,7 @@ class FiroWallet extends CoinServiceAPI {
     }
 
     int availableBalance = coins.fold(
-        0, (previousValue, element) => (previousValue as int) + element.amount);
+        0, (previousValue, element) => previousValue + element.amount);
 
     if (required > availableBalance) {
       return false;
@@ -3706,21 +4415,21 @@ class FiroWallet extends CoinServiceAPI {
         (a.amount != b.amount ? a.amount > b.amount : a.height < b.height)
             ? -1
             : 1);
-    int spend_val = 0;
+    int spendVal = 0;
 
     List<DartLelantusEntry> coinsToSpend = [];
 
-    while (spend_val < required) {
+    while (spendVal < required) {
       if (coins.isEmpty) {
         break;
       }
 
-      DartLelantusEntry? choosen;
-      int need = required - spend_val;
+      DartLelantusEntry? chosen;
+      int need = required - spendVal;
 
       var itr = coins.first;
       if (need >= itr.amount) {
-        choosen = itr;
+        chosen = itr;
         coins.remove(itr);
       } else {
         for (int index = coins.length - 1; index != 0; index--) {
@@ -3729,32 +4438,32 @@ class FiroWallet extends CoinServiceAPI {
 
           if (coinIt.amount >= need &&
               (index - 1 == 0 || nextItr.amount != coinIt.amount)) {
-            choosen = coinIt;
-            coins.remove(choosen);
+            chosen = coinIt;
+            coins.remove(chosen);
             break;
           }
         }
       }
 
-      spend_val += choosen!.amount;
-      coinsToSpend.insert(coinsToSpend.length, choosen);
+      spendVal += chosen!.amount;
+      coinsToSpend.insert(coinsToSpend.length, chosen);
     }
 
-    // sort by group id ay ascending order. it is mandatory for creting proper joinsplit
+    // sort by group id ay ascending order. it is mandatory for creating proper joinsplit
     coinsToSpend.sort((a, b) => a.anonymitySetId < b.anonymitySetId ? 1 : -1);
 
-    int changeToMint = spend_val - required;
+    int changeToMint = spendVal - required;
     List<int> indices = [];
     for (var l in coinsToSpend) {
       indices.add(l.index);
     }
-    List<DartLelantusEntry> coinsToBeSpent_out = [];
-    coinsToBeSpent_out.addAll(coinsToSpend);
+    List<DartLelantusEntry> coinsToBeSpentOut = [];
+    coinsToBeSpentOut.addAll(coinsToSpend);
 
-    return {"changeToMint": changeToMint, "coinsToSpend": coinsToBeSpent_out};
+    return {"changeToMint": changeToMint, "coinsToSpend": coinsToBeSpentOut};
   }
 
-  Future<int> EstimateJoinSplitFee(
+  Future<int> estimateJoinSplitFee(
     int spendAmount,
   ) async {
     int fee;
@@ -3763,7 +4472,7 @@ class FiroWallet extends CoinServiceAPI {
     for (fee = 0;;) {
       int currentRequired = spendAmount;
 
-      var map = await GetCoinsToJoinSplit(currentRequired);
+      var map = await getCoinsToJoinSplit(currentRequired);
       if (map is bool && !map) {
         return 0;
       }
@@ -3790,10 +4499,74 @@ class FiroWallet extends CoinServiceAPI {
 
   @override
   Future<int> estimateFeeFor(int satoshiAmount, int feeRate) async {
-    int fee = await EstimateJoinSplitFee(satoshiAmount);
+    int fee = await estimateJoinSplitFee(satoshiAmount);
     return fee;
   }
 
+  Future<int> estimateFeeForPublic(int satoshiAmount, int feeRate) async {
+    final available =
+        Format.decimalAmountToSatoshis(await availablePublicBalance());
+
+    if (available == satoshiAmount) {
+      return satoshiAmount - sweepAllEstimate(feeRate);
+    } else if (satoshiAmount <= 0 || satoshiAmount > available) {
+      return roughFeeEstimate(1, 2, feeRate);
+    }
+
+    int runningBalance = 0;
+    int inputCount = 0;
+    for (final output in _outputsList) {
+      runningBalance += output.value;
+      inputCount++;
+      if (runningBalance > satoshiAmount) {
+        break;
+      }
+    }
+
+    final oneOutPutFee = roughFeeEstimate(inputCount, 1, feeRate);
+    final twoOutPutFee = roughFeeEstimate(inputCount, 2, feeRate);
+
+    if (runningBalance - satoshiAmount > oneOutPutFee) {
+      if (runningBalance - satoshiAmount > oneOutPutFee + DUST_LIMIT) {
+        final change = runningBalance - satoshiAmount - twoOutPutFee;
+        if (change > DUST_LIMIT &&
+            runningBalance - satoshiAmount - change == twoOutPutFee) {
+          return runningBalance - satoshiAmount - change;
+        } else {
+          return runningBalance - satoshiAmount;
+        }
+      } else {
+        return runningBalance - satoshiAmount;
+      }
+    } else if (runningBalance - satoshiAmount == oneOutPutFee) {
+      return oneOutPutFee;
+    } else {
+      return twoOutPutFee;
+    }
+  }
+
+  // TODO: correct formula for firo?
+  int roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
+    return ((181 * inputCount) + (34 * outputCount) + 10) *
+        (feeRatePerKB / 1000).ceil();
+  }
+
+  int sweepAllEstimate(int feeRate) {
+    int available = 0;
+    int inputCount = 0;
+    for (final output in _outputsList) {
+      if (output.status.confirmed) {
+        available += output.value;
+        inputCount++;
+      }
+    }
+
+    // transaction will only have 1 output minus the fee
+    final estimatedFee = roughFeeEstimate(inputCount, 1, feeRate);
+
+    return available - estimatedFee;
+  }
+
   Future<List<models.Transaction>> getJMintTransactions(
     CachedElectrumX cachedClient,
     List<String> transactions,
@@ -3857,4 +4630,36 @@ class FiroWallet extends CoinServiceAPI {
       rethrow;
     }
   }
+
+  @override
+  Future<bool> generateNewAddress() async {
+    try {
+      await incrementAddressIndexForChain(
+          0); // First increment the receiving index
+      final newReceivingIndex =
+          DB.instance.get<dynamic>(boxName: walletId, key: 'receivingIndex')
+              as int; // Check the new receiving index
+      final newReceivingAddress = await _generateAddressForChain(0,
+          newReceivingIndex); // Use new index to derive a new receiving address
+      await addToAddressesArrayForChain(newReceivingAddress,
+          0); // Add that new receiving address to the array of receiving addresses
+      _currentReceivingAddress = Future(() =>
+          newReceivingAddress); // Set the new receiving address that the service
+
+      return true;
+    } catch (e, s) {
+      Logging.instance.log(
+          "Exception rethrown from generateNewAddress(): $e\n$s",
+          level: LogLevel.Error);
+      return false;
+    }
+  }
+
+  Future<Decimal> availablePrivateBalance() async {
+    return (await balances)[0];
+  }
+
+  Future<Decimal> availablePublicBalance() async {
+    return (await balances)[4];
+  }
 }
diff --git a/lib/services/coins/manager.dart b/lib/services/coins/manager.dart
index 659db73bd..c8329ec28 100644
--- a/lib/services/coins/manager.dart
+++ b/lib/services/coins/manager.dart
@@ -266,4 +266,12 @@ class Manager with ChangeNotifier {
   Future<int> estimateFeeFor(int satoshiAmount, int feeRate) async {
     return _currentWallet.estimateFeeFor(satoshiAmount, feeRate);
   }
+
+  Future<bool> generateNewAddress() async {
+    final success = await _currentWallet.generateNewAddress();
+    if (success) {
+      notifyListeners();
+    }
+    return success;
+  }
 }
diff --git a/lib/services/coins/monero/monero_wallet.dart b/lib/services/coins/monero/monero_wallet.dart
index 95794a356..b63e711a4 100644
--- a/lib/services/coins/monero/monero_wallet.dart
+++ b/lib/services/coins/monero/monero_wallet.dart
@@ -1521,4 +1521,33 @@ class MoneroWallet extends CoinServiceAPI {
             10000;
     return fee;
   }
+
+  @override
+  Future<bool> generateNewAddress() async {
+    try {
+      const String indexKey = "receivingIndex";
+      // First increment the receiving index
+      await _incrementAddressIndexForChain(0);
+      final newReceivingIndex =
+          DB.instance.get<dynamic>(boxName: walletId, key: indexKey) as int;
+
+      // Use new index to derive a new receiving address
+      final newReceivingAddress =
+          await _generateAddressForChain(0, newReceivingIndex);
+
+      // Add that new receiving address to the array of receiving addresses
+      await _addToAddressesArrayForChain(newReceivingAddress, 0);
+
+      // Set the new receiving address that the service
+
+      _currentReceivingAddress = Future(() => newReceivingAddress);
+
+      return true;
+    } catch (e, s) {
+      Logging.instance.log(
+          "Exception rethrown from generateNewAddress(): $e\n$s",
+          level: LogLevel.Error);
+      return false;
+    }
+  }
 }
diff --git a/lib/services/notifications_service.dart b/lib/services/notifications_service.dart
index 31d8b664c..977d046a2 100644
--- a/lib/services/notifications_service.dart
+++ b/lib/services/notifications_service.dart
@@ -103,75 +103,79 @@ class NotificationsService extends ChangeNotifier {
 
   void _checkTransactions() async {
     for (final notification in _watchedTransactionNotifications) {
-      final Coin coin = coinFromPrettyName(notification.coinName);
-      final txid = notification.txid!;
+      try {
+        final Coin coin = coinFromPrettyName(notification.coinName);
+        final txid = notification.txid!;
 
-      final node = nodeService.getPrimaryNodeFor(coin: coin);
-      if (node != null) {
-        if (coin.isElectrumXCoin) {
-          final eNode = ElectrumXNode(
-            address: node.host,
-            port: node.port,
-            name: node.name,
-            id: node.id,
-            useSSL: node.useSSL,
-          );
-          final failovers = nodeService
-              .failoverNodesFor(coin: coin)
-              .map((e) => ElectrumXNode(
-                    address: e.host,
-                    port: e.port,
-                    name: e.name,
-                    id: e.id,
-                    useSSL: e.useSSL,
-                  ))
-              .toList();
-
-          final client = ElectrumX.from(
-            node: eNode,
-            failovers: failovers,
-            prefs: prefs,
-          );
-          final tx = await client.getTransaction(txHash: txid);
-
-          int confirmations = tx["confirmations"] as int? ?? 0;
-
-          bool shouldWatchForUpdates = true;
-          // check if the number of confirmations is greater than the number
-          // required by the wallet to count the tx as confirmed and update the
-          // flag on whether this notification should still be monitored
-          if (confirmations >= coin.requiredConfirmations) {
-            shouldWatchForUpdates = false;
-            confirmations = coin.requiredConfirmations;
-          }
-
-          // grab confirms string to compare
-          final String newConfirms =
-              "($confirmations/${coin.requiredConfirmations})";
-          final String oldConfirms =
-              notification.title.substring(notification.title.lastIndexOf("("));
-
-          // only update if they don't match
-          if (oldConfirms != newConfirms) {
-            final String newTitle =
-                notification.title.replaceFirst(oldConfirms, newConfirms);
-
-            final updatedNotification = notification.copyWith(
-              title: newTitle,
-              shouldWatchForUpdates: shouldWatchForUpdates,
+        final node = nodeService.getPrimaryNodeFor(coin: coin);
+        if (node != null) {
+          if (coin.isElectrumXCoin) {
+            final eNode = ElectrumXNode(
+              address: node.host,
+              port: node.port,
+              name: node.name,
+              id: node.id,
+              useSSL: node.useSSL,
             );
+            final failovers = nodeService
+                .failoverNodesFor(coin: coin)
+                .map((e) => ElectrumXNode(
+                      address: e.host,
+                      port: e.port,
+                      name: e.name,
+                      id: e.id,
+                      useSSL: e.useSSL,
+                    ))
+                .toList();
 
-            // remove from watch list if shouldWatchForUpdates was changed
-            if (!shouldWatchForUpdates) {
-              await _deleteWatchedTxNotification(notification);
+            final client = ElectrumX.from(
+              node: eNode,
+              failovers: failovers,
+              prefs: prefs,
+            );
+            final tx = await client.getTransaction(txHash: txid);
+
+            int confirmations = tx["confirmations"] as int? ?? 0;
+
+            bool shouldWatchForUpdates = true;
+            // check if the number of confirmations is greater than the number
+            // required by the wallet to count the tx as confirmed and update the
+            // flag on whether this notification should still be monitored
+            if (confirmations >= coin.requiredConfirmations) {
+              shouldWatchForUpdates = false;
+              confirmations = coin.requiredConfirmations;
             }
 
-            // replaces the current notification with the updated one
-            add(updatedNotification, true);
+            // grab confirms string to compare
+            final String newConfirms =
+                "($confirmations/${coin.requiredConfirmations})";
+            final String oldConfirms = notification.title
+                .substring(notification.title.lastIndexOf("("));
+
+            // only update if they don't match
+            if (oldConfirms != newConfirms) {
+              final String newTitle =
+                  notification.title.replaceFirst(oldConfirms, newConfirms);
+
+              final updatedNotification = notification.copyWith(
+                title: newTitle,
+                shouldWatchForUpdates: shouldWatchForUpdates,
+              );
+
+              // remove from watch list if shouldWatchForUpdates was changed
+              if (!shouldWatchForUpdates) {
+                await _deleteWatchedTxNotification(notification);
+              }
+
+              // replaces the current notification with the updated one
+              add(updatedNotification, true);
+            }
+          } else {
+            // TODO: check non electrumx coins
           }
-        } else {
-          // TODO: check non electrumx coins
         }
+      } catch (e, s) {
+        Logging.instance.log("$e $s", level: LogLevel.Error);
       }
     }
   }
diff --git a/lib/services/wallets_service.dart b/lib/services/wallets_service.dart
index a80bc2f82..b978f1edc 100644
--- a/lib/services/wallets_service.dart
+++ b/lib/services/wallets_service.dart
@@ -126,6 +126,17 @@ class WalletsService extends ChangeNotifier {
     }
     Logging.instance.log("Fetched wallet names: $names", level: LogLevel.Info);
     final mapped = Map<String, dynamic>.from(names);
+    mapped.removeWhere((name, dyn) {
+      final jsonObject = Map<String, dynamic>.from(dyn as Map);
+      try {
+        Coin.values.byName(jsonObject["coin"] as String);
+        return false;
+      } catch (e, s) {
+        Logging.instance.log("Error, ${jsonObject["coin"]} does not exist",
+            level: LogLevel.Error);
+        return true;
+      }
+    });
 
     return mapped.map((name, dyn) => MapEntry(
         name, WalletInfo.fromJson(Map<String, dynamic>.from(dyn as Map))));
diff --git a/lib/utilities/assets.dart b/lib/utilities/assets.dart
index 9adc50e59..72ceac3ca 100644
--- a/lib/utilities/assets.dart
+++ b/lib/utilities/assets.dart
@@ -84,6 +84,10 @@ class _SVG {
   String get solidSliders => "assets/svg/sliders-solid.svg";
   String get questionMessage => "assets/svg/message-question.svg";
   String get envelope => "assets/svg/envelope.svg";
+  String get share => "assets/svg/share-2.svg";
+  String get anonymize => "assets/svg/tx-icon-anonymize.svg";
+  String get anonymizePending => "assets/svg/tx-icon-anonymize-pending.svg";
+  String get anonymizeFailed => "assets/svg/tx-icon-anonymize-failed.svg";
 
   String get receive => "assets/svg/tx-icon-receive.svg";
   String get receivePending => "assets/svg/tx-icon-receive-pending.svg";
diff --git a/lib/utilities/cfcolors.dart b/lib/utilities/cfcolors.dart
index ce6097b7d..741ca1230 100644
--- a/lib/utilities/cfcolors.dart
+++ b/lib/utilities/cfcolors.dart
@@ -8,8 +8,8 @@ class _CoinThemeColor {
   Color get bitcoin => const Color(0xFFFCC17B);
   Color get firo => const Color(0xFFFF897A);
   Color get dogecoin => const Color(0xFFFFE079);
-  Color get epicCash => const Color(0xFFC1C1FF);
-  Color get monero => const Color(0xFFB1C5FF);
+  Color get epicCash => const Color(0xFFC5C7CB);
+  Color get monero => const Color(0xFFFF9E6B);
 
   Color forCoin(Coin coin) {
     switch (coin) {
diff --git a/lib/utilities/constants.dart b/lib/utilities/constants.dart
index b8e5b5bce..3b82cde40 100644
--- a/lib/utilities/constants.dart
+++ b/lib/utilities/constants.dart
@@ -33,7 +33,7 @@ abstract class Constants {
   // Enable Logger.print statements
   static const bool disableLogger = false;
 
-  static const int currentDbVersion = 0;
+  static const int currentHiveDbVersion = 1;
 
   static List<int> possibleLengthsForCoin(Coin coin) {
     final List<int> values = [];
diff --git a/lib/utilities/db_version_migration.dart b/lib/utilities/db_version_migration.dart
index ad92b5a59..e3867ecc4 100644
--- a/lib/utilities/db_version_migration.dart
+++ b/lib/utilities/db_version_migration.dart
@@ -1,5 +1,16 @@
 import 'package:flutter_secure_storage/flutter_secure_storage.dart';
+import 'package:hive/hive.dart';
+import 'package:stackwallet/electrumx_rpc/electrumx.dart';
+import 'package:stackwallet/hive/db.dart';
+import 'package:stackwallet/models/lelantus_coin.dart';
+import 'package:stackwallet/models/node_model.dart';
+import 'package:stackwallet/services/node_service.dart';
+import 'package:stackwallet/services/wallets_service.dart';
+import 'package:stackwallet/utilities/default_nodes.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
 import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/prefs.dart';
 
 class DbVersionMigrator {
   Future<void> migrate(
@@ -8,83 +19,125 @@ class DbVersionMigrator {
       FlutterSecureStorage(),
     ),
   }) async {
-    // final wallets = await Hive.openBox('wallets');
-    // final names = Map<String, String>.from((await wallets.get("names")) ?? {});
-    //
-    // switch (fromVersion) {
-    //   case 0:
-    //     // migrate each
-    //     for (final entry in names.entries) {
-    //       final walletId = entry.value;
-    //       final walletName = entry.key;
-    //
-    //       // move main/test network to walletId based
-    //       final network = await wallets.get("${entry.key}_network");
-    //       await wallets.put("${walletId}_network", network);
-    //       await wallets.delete("${walletName}_network");
-    //
-    //       final old = await Hive.openBox(walletName);
-    //       final wallet = await Hive.openBox(walletId);
-    //
-    //       // notes
-    //       final oldNotes = await old.get("notes");
-    //       await wallet.put("notes", oldNotes);
-    //       await old.delete("notes");
-    //
-    //       // address book
-    //       final addressBook = await old.get("addressBookEntries");
-    //       await wallet.put("addressBookEntries", addressBook);
-    //       await old.put("addressBookEntries", null);
-    //
-    //       // receiveDerivations
-    //       Map<String, dynamic> newReceiveDerivations = {};
-    //       final receiveDerivations =
-    //           Map<int, dynamic>.from(await old.get("receiveDerivations") ?? {});
-    //
-    //       for (int i = 0; i < receiveDerivations.length; i++) {
-    //         receiveDerivations[i].remove("fingerprint");
-    //         receiveDerivations[i].remove("identifier");
-    //         receiveDerivations[i].remove("privateKey");
-    //         newReceiveDerivations["$i"] = receiveDerivations[i];
-    //       }
-    //       final receiveDerivationsString = jsonEncode(newReceiveDerivations);
-    //
-    //       await secureStore.write(
-    //           key: "${walletId}_receiveDerivations",
-    //           value: receiveDerivationsString);
-    //       await old.delete("receiveDerivations");
-    //
-    //       // changeDerivations
-    //       Map<String, dynamic> newChangeDerivations = {};
-    //       final changeDerivations =
-    //           Map<int, dynamic>.from(await old.get("changeDerivations") ?? {});
-    //
-    //       for (int i = 0; i < changeDerivations.length; i++) {
-    //         changeDerivations[i].remove("fingerprint");
-    //         changeDerivations[i].remove("identifier");
-    //         changeDerivations[i].remove("privateKey");
-    //         newChangeDerivations["$i"] = changeDerivations[i];
-    //       }
-    //       final changeDerivationsString = jsonEncode(newChangeDerivations);
-    //
-    //       await secureStore.write(
-    //           key: "${walletId}_changeDerivations",
-    //           value: changeDerivationsString);
-    //       await old.delete("changeDerivations");
-    //     }
-    //
-    //     // finally update version
-    //     await wallets.put("db_version", 1);
-    //
-    //     return;
-    //   // not needed yet
-    //   // return migrate(1);
-    //
-    //   // case 1:
-    //   //   return migrate(2);
-    //
-    //   default:
-    //     return;
-    // }
+    switch (fromVersion) {
+      case 0:
+        await Hive.openBox<dynamic>(DB.boxNameAllWalletsData);
+        await Hive.openBox<dynamic>(DB.boxNamePrefs);
+        final walletsService = WalletsService();
+        final nodeService = NodeService();
+        final prefs = Prefs.instance;
+        final walletInfoList = await walletsService.walletNames;
+        await prefs.init();
+
+        ElectrumX? client;
+        int? latestSetId;
+
+        // only instantiate client if there are firo wallets
+        if (walletInfoList.values.any((element) => element.coin == Coin.firo)) {
+          await Hive.openBox<NodeModel>(DB.boxNameNodeModels);
+          await Hive.openBox<NodeModel>(DB.boxNamePrimaryNodes);
+          final node = nodeService.getPrimaryNodeFor(coin: Coin.firo) ??
+              DefaultNodes.firo;
+          List<ElectrumXNode> failovers = nodeService
+              .failoverNodesFor(coin: Coin.firo)
+              .map(
+                (e) => ElectrumXNode(
+                  address: e.host,
+                  port: e.port,
+                  name: e.name,
+                  id: e.id,
+                  useSSL: e.useSSL,
+                ),
+              )
+              .toList();
+
+          client = ElectrumX.from(
+            node: ElectrumXNode(
+                address: node.host,
+                port: node.port,
+                name: node.name,
+                id: node.id,
+                useSSL: node.useSSL),
+            prefs: prefs,
+            failovers: failovers,
+          );
+
+          try {
+            latestSetId = await client.getLatestCoinId();
+          } catch (e) {
+            // default to 2 for now
+            latestSetId = 2;
+            Logging.instance.log(
+                "Failed to fetch latest coin id during firo db migrate: $e \nUsing a default value of 2",
+                level: LogLevel.Warning);
+          }
+        }
+
+        for (final walletInfo in walletInfoList.values) {
+          // migrate each firo wallet's lelantus coins
+          if (walletInfo.coin == Coin.firo) {
+            await Hive.openBox<dynamic>(walletInfo.walletId);
+            final _lelantusCoins = DB.instance.get<dynamic>(
+                boxName: walletInfo.walletId, key: '_lelantus_coins') as List?;
+            final List<Map<dynamic, LelantusCoin>> lelantusCoins = [];
+            for (var lCoin in _lelantusCoins ?? []) {
+              lelantusCoins
+                  .add({lCoin.keys.first: lCoin.values.first as LelantusCoin});
+            }
+
+            List<Map<dynamic, LelantusCoin>> coins = [];
+            for (final element in lelantusCoins) {
+              LelantusCoin coin = element.values.first;
+              int anonSetId = coin.anonymitySetId;
+              if (coin.anonymitySetId == 1 &&
+                  (coin.publicCoin == '' ||
+                      coin.publicCoin == "jmintData.publicCoin")) {
+                anonSetId = latestSetId!;
+              }
+              coins.add({
+                element.keys.first: LelantusCoin(coin.index, coin.value,
+                    coin.publicCoin, coin.txId, anonSetId, coin.isUsed)
+              });
+            }
+            Logger.print("newcoins $coins", normalLength: false);
+            await DB.instance.put<dynamic>(
+                boxName: walletInfo.walletId,
+                key: '_lelantus_coins',
+                value: coins);
+          }
+        }
+
+        // update version
+        await DB.instance.put<dynamic>(
+            boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 1);
+
+        // try to continue migrating
+        return await migrate(1);
+
+      // case 1:
+      //   await Hive.openBox<dynamic>(DB.boxNameAllWalletsData);
+      //   final walletsService = WalletsService();
+      //   final walletInfoList = await walletsService.walletNames;
+      //   for (final walletInfo in walletInfoList.values) {
+      //     if (walletInfo.coin == Coin.firo) {
+      //       await Hive.openBox<dynamic>(walletInfo.walletId);
+      //       await DB.instance.delete<dynamic>(
+      //           key: "latest_tx_model", boxName: walletInfo.walletId);
+      //       await DB.instance.delete<dynamic>(
+      //           key: "latest_lelantus_tx_model", boxName: walletInfo.walletId);
+      //     }
+      //   }
+      //
+      //   // update version
+      //   await DB.instance.put<dynamic>(
+      //       boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 2);
+      //
+      //   // try to continue migrating
+      //   return await migrate(2);
+
+      default:
+        // finally return
+        return;
+    }
   }
 }
diff --git a/lib/utilities/prefs.dart b/lib/utilities/prefs.dart
index 7f6006502..cd297f121 100644
--- a/lib/utilities/prefs.dart
+++ b/lib/utilities/prefs.dart
@@ -33,6 +33,7 @@ class Prefs extends ChangeNotifier {
       _autoBackupLocation = await _getAutoBackupLocation();
       _backupFrequencyType = await _getBackupFrequencyType();
       _lastAutoBackup = await _getLastAutoBackup();
+      _hideBlockExplorerWarning = await _getHideBlockExplorerWarning();
 
       _initialized = true;
     }
@@ -466,4 +467,32 @@ class Prefs extends ChangeNotifier {
     return await DB.instance.get<dynamic>(
         boxName: DB.boxNamePrefs, key: "autoBackupFileUri") as DateTime?;
   }
+
+
+
+  // auto backup
+
+  bool _hideBlockExplorerWarning = false;
+
+  bool get hideBlockExplorerWarning => _hideBlockExplorerWarning;
+
+  set hideBlockExplorerWarning(bool hideBlockExplorerWarning) {
+    if (_hideBlockExplorerWarning != hideBlockExplorerWarning) {
+      DB.instance
+          .put<dynamic>(
+          boxName: DB.boxNamePrefs,
+          key: "hideBlockExplorerWarning",
+          value: hideBlockExplorerWarning)
+          .then((_) {
+        _hideBlockExplorerWarning = hideBlockExplorerWarning;
+        notifyListeners();
+      });
+    }
+  }
+
+  Future<bool> _getHideBlockExplorerWarning() async {
+    return await DB.instance.get<dynamic>(
+        boxName: DB.boxNamePrefs, key: "hideBlockExplorerWarning") as bool? ??
+        false;
+  }
 }
diff --git a/lib/widgets/transaction_card.dart b/lib/widgets/transaction_card.dart
index 2dd4abdbe..756e3d8f7 100644
--- a/lib/widgets/transaction_card.dart
+++ b/lib/widgets/transaction_card.dart
@@ -1,3 +1,5 @@
+import 'dart:async';
+
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:stackwallet/models/paymint/transactions_model.dart';
@@ -35,10 +37,30 @@ class _TransactionCardState extends ConsumerState<TransactionCard> {
     if (coin == Coin.epicCash && _transaction.slateId == null) {
       return "Restored Funds";
     }
+
+    if (_transaction.subType == "mint") {
+      // if (type == "Received") {
+      if (_transaction.confirmedStatus) {
+        return "Anonymized";
+      } else {
+        return "Anonymizing";
+      }
+      // } else if (type == "Sent") {
+      //   if (_transaction.confirmedStatus) {
+      //     return "Sent MINT";
+      //   } else {
+      //     return "Sending MINT";
+      //   }
+      // } else {
+      //   return type;
+      // }
+    }
+
     if (type == "Received") {
-      if (_transaction.isMinting) {
-        return "Minting";
-      } else if (_transaction.confirmedStatus) {
+      // if (_transaction.isMinting) {
+      //   return "Minting";
+      // } else
+      if (_transaction.confirmedStatus) {
         return "Received";
       } else {
         return "Receiving";
@@ -95,23 +117,23 @@ class _TransactionCardState extends ConsumerState<TransactionCard> {
           ),
           onPressed: () async {
             if (coin == Coin.epicCash && _transaction.slateId == null) {
-              showFloatingFlushBar(
+              unawaited(showFloatingFlushBar(
                 context: context,
                 message:
                     "Restored Epic funds from your Seed have no Data.\nUse Stack Backup to keep your transaction history.",
                 type: FlushBarType.warning,
                 duration: const Duration(seconds: 5),
-              );
+              ));
               return;
             }
-            Navigator.of(context).pushNamed(
+            unawaited(Navigator.of(context).pushNamed(
               TransactionDetailsView.routeName,
               arguments: Tuple3(
                 _transaction,
                 coin,
                 walletId,
               ),
-            );
+            ));
           },
           child: Padding(
             padding: const EdgeInsets.all(8),
diff --git a/pubspec.yaml b/pubspec.yaml
index f2faf1497..e8cbe645f 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -11,7 +11,7 @@ description: Stack Wallet
 # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
 # Read more about iOS versioning at
 # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
-version: 1.4.39+51
+version: 1.4.42+55
 
 environment:
   sdk: ">=2.17.0 <3.0.0"
@@ -255,6 +255,10 @@ flutter:
     - assets/svg/sliders-solid.svg
     - assets/svg/message-question.svg
     - assets/svg/envelope.svg
+    - assets/svg/share-2.svg
+    - assets/svg/tx-icon-anonymize.svg
+    - assets/svg/tx-icon-anonymize-pending.svg
+    - assets/svg/tx-icon-anonymize-failed.svg
     # coin icons
     - assets/svg/coin_icons/Bitcoin.svg
     - assets/svg/coin_icons/Dogecoin.svg
diff --git a/test/cached_electrumx_test.dart b/test/cached_electrumx_test.dart
index 6ae0d0f93..e0f7fd6ca 100644
--- a/test/cached_electrumx_test.dart
+++ b/test/cached_electrumx_test.dart
@@ -10,7 +10,7 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart';
 import 'package:stackwallet/utilities/prefs.dart';
 
 import 'cached_electrumx_test.mocks.dart';
-import 'sample_data/get_anonymity_set_sample_data.dart';
+// import 'sample_data/get_anonymity_set_sample_data.dart';
 
 @GenerateMocks([ElectrumX, Prefs])
 void main() {
@@ -23,36 +23,36 @@ void main() {
       await Hive.openBox<dynamic>(DB.instance.boxNameTxCache(coin: Coin.firo));
     });
     group("getAnonymitySet", () {
-      test("empty set cache call", () async {
-        final client = MockElectrumX();
-        when(
-          client.getAnonymitySet(
-            groupId: "1",
-            blockhash: "",
-          ),
-        ).thenAnswer(
-          (_) async => GetAnonymitySetSampleData.data,
-        );
-
-        final cachedClient = CachedElectrumX(
-            electrumXClient: client,
-            port: 0,
-            failovers: [],
-            server: '',
-            useSSL: true,
-            prefs: Prefs.instance);
-
-        final result = await cachedClient.getAnonymitySet(
-          groupId: "1",
-          coin: Coin.firo,
-        );
-
-        final expected =
-            Map<String, dynamic>.from(GetAnonymitySetSampleData.data);
-        expected["setId"] = "1";
-
-        expect(result, expected);
-      });
+      // test("empty set cache call", () async {
+      //   final client = MockElectrumX();
+      //   when(
+      //     client.getAnonymitySet(
+      //       groupId: "1",
+      //       blockhash: "",
+      //     ),
+      //   ).thenAnswer(
+      //     (_) async => GetAnonymitySetSampleData.data,
+      //   );
+      //
+      //   final cachedClient = CachedElectrumX(
+      //       electrumXClient: client,
+      //       port: 0,
+      //       failovers: [],
+      //       server: '',
+      //       useSSL: true,
+      //       prefs: Prefs.instance);
+      //
+      //   final result = await cachedClient.getAnonymitySet(
+      //     groupId: "1",
+      //     coin: Coin.firo,
+      //   );
+      //
+      //   final expected =
+      //       Map<String, dynamic>.from(GetAnonymitySetSampleData.data);
+      //   expected["setId"] = "1";
+      //
+      //   expect(result, expected);
+      // });
       //
       // test("use and update set cache call", () async {
       //   final storedData = Map.from(GetAnonymitySetSampleData.initialData);
@@ -91,30 +91,30 @@ void main() {
       //   fail("This test needs updating");
       // });
 
-      test("getAnonymitySet throws", () async {
-        final client = MockElectrumX();
-        when(
-          client.getAnonymitySet(
-            groupId: "1",
-            blockhash: "",
-          ),
-        ).thenThrow(Exception());
-
-        final cachedClient = CachedElectrumX(
-            electrumXClient: client,
-            port: 0,
-            failovers: [],
-            server: '',
-            useSSL: true,
-            prefs: Prefs.instance);
-
-        expect(
-            () async => await cachedClient.getAnonymitySet(
-                  groupId: "1",
-                  coin: Coin.firo,
-                ),
-            throwsA(isA<Exception>()));
-      });
+      // test("getAnonymitySet throws", () async {
+      //   final client = MockElectrumX();
+      //   when(
+      //     client.getAnonymitySet(
+      //       groupId: "1",
+      //       blockhash: "",
+      //     ),
+      //   ).thenThrow(Exception());
+      //
+      //   final cachedClient = CachedElectrumX(
+      //       electrumXClient: client,
+      //       port: 0,
+      //       failovers: [],
+      //       server: '',
+      //       useSSL: true,
+      //       prefs: Prefs.instance);
+      //
+      //   expect(
+      //       () async => await cachedClient.getAnonymitySet(
+      //             groupId: "1",
+      //             coin: Coin.firo,
+      //           ),
+      //       throwsA(isA<Exception>()));
+      // });
     });
 
     test("getTransaction throws", () async {
diff --git a/test/hive/db_test.dart b/test/hive/db_test.dart
new file mode 100644
index 000000000..a87f568bd
--- /dev/null
+++ b/test/hive/db_test.dart
@@ -0,0 +1,69 @@
+import 'package:flutter_test/flutter_test.dart';
+import 'package:hive_test/hive_test.dart';
+import 'package:stackwallet/hive/db.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
+
+void main() {
+  group("DB box names", () {
+    test("address book", () => expect(DB.boxNameAddressBook, "addressBook"));
+    test("debug info", () => expect(DB.boxNameDebugInfo, "debugInfoBox"));
+    test("nodes", () => expect(DB.boxNameNodeModels, "nodeModels"));
+    test("primary nodes", () => expect(DB.boxNamePrimaryNodes, "primaryNodes"));
+    test("wallets info", () => expect(DB.boxNameAllWalletsData, "wallets"));
+    test("notifications",
+        () => expect(DB.boxNameNotifications, "notificationModels"));
+    test(
+        "watched transactions",
+        () => expect(
+            DB.boxNameWatchedTransactions, "watchedTxNotificationModels"));
+    test(
+        "watched trades",
+        () =>
+            expect(DB.boxNameWatchedTrades, "watchedTradesNotificationModels"));
+    test("trades", () => expect(DB.boxNameTrades, "exchangeTransactionsBox"));
+    test("trade notes", () => expect(DB.boxNameTradeNotes, "tradeNotesBox"));
+    test("tx <> trade lookup table",
+        () => expect(DB.boxNameTradeLookup, "tradeToTxidLookUpBox"));
+    test("favorite wallets",
+        () => expect(DB.boxNameFavoriteWallets, "favoriteWallets"));
+    test("preferences", () => expect(DB.boxNamePrefs, "prefs"));
+    test(
+        "deleted wallets to clear out on start",
+        () =>
+            expect(DB.boxNameWalletsToDeleteOnStart, "walletsToDeleteOnStart"));
+    test("price cache",
+        () => expect(DB.boxNamePriceCache, "priceAPIPrice24hCache"));
+
+    test("boxNameTxCache", () {
+      for (final coin in Coin.values) {
+        expect(DB.instance.boxNameTxCache(coin: coin), "${coin.name}_txCache");
+      }
+    });
+
+    test("boxNameSetCache", () {
+      for (final coin in Coin.values) {
+        expect(DB.instance.boxNameSetCache(coin: coin),
+            "${coin.name}_anonymitySetCache");
+      }
+    });
+
+    test("boxNameUsedSerialsCache", () {
+      for (final coin in Coin.values) {
+        expect(DB.instance.boxNameUsedSerialsCache(coin: coin),
+            "${coin.name}_usedSerialsCache");
+      }
+    });
+  });
+
+  group("tests requiring test hive environment", () {
+    setUp(() async {
+      await setUpTestHive();
+    });
+
+    test("DB init", () async {});
+
+    tearDown(() async {
+      await tearDownTestHive();
+    });
+  });
+}
diff --git a/test/models/exchange/estimated_rate_exchange_form_state_test.dart b/test/models/exchange/estimated_rate_exchange_form_state_test.dart
new file mode 100644
index 000000000..3c6c869e5
--- /dev/null
+++ b/test/models/exchange/estimated_rate_exchange_form_state_test.dart
@@ -0,0 +1,215 @@
+import 'package:decimal/decimal.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:mockito/annotations.dart';
+import 'package:mockito/mockito.dart';
+import 'package:stackwallet/models/exchange/change_now/change_now_response.dart';
+import 'package:stackwallet/models/exchange/change_now/currency.dart';
+import 'package:stackwallet/models/exchange/change_now/estimated_exchange_amount.dart';
+import 'package:stackwallet/models/exchange/estimated_rate_exchange_form_state.dart';
+import 'package:stackwallet/services/change_now/change_now.dart';
+
+import 'estimated_rate_exchange_form_state_test.mocks.dart';
+
+@GenerateMocks([ChangeNow])
+void main() {
+  final currencyA = Currency(
+    ticker: "btc",
+    name: "Bitcoin",
+    image: "image.url",
+    hasExternalId: false,
+    isFiat: false,
+    featured: false,
+    isStable: true,
+    supportsFixedRate: true,
+  );
+  final currencyB = Currency(
+    ticker: "xmr",
+    name: "Monero",
+    image: "image.url",
+    hasExternalId: false,
+    isFiat: false,
+    featured: false,
+    isStable: true,
+    supportsFixedRate: true,
+  );
+  final currencyC = Currency(
+    ticker: "firo",
+    name: "Firo",
+    image: "image.url",
+    hasExternalId: false,
+    isFiat: false,
+    featured: false,
+    isStable: true,
+    supportsFixedRate: true,
+  );
+
+  test("EstimatedRateExchangeFormState constructor", () async {
+    final state = EstimatedRateExchangeFormState();
+
+    expect(state.from, null);
+    expect(state.to, null);
+    expect(state.canExchange, false);
+    expect(state.rate, null);
+    expect(state.rateDisplayString, "N/A");
+    expect(state.fromAmountString, "");
+    expect(state.toAmountString, "");
+    expect(state.minimumSendWarning, "");
+  });
+
+  test("init EstimatedRateExchangeFormState", () async {
+    final state = EstimatedRateExchangeFormState();
+
+    await state.init(currencyA, currencyB);
+
+    expect(state.from, currencyA);
+    expect(state.to, currencyB);
+    expect(state.canExchange, false);
+    expect(state.rate, null);
+    expect(state.rateDisplayString, "N/A");
+    expect(state.fromAmountString, "");
+    expect(state.toAmountString, "");
+    expect(state.minimumSendWarning, "");
+  });
+
+  test("updateTo on fresh state", () async {
+    final state = EstimatedRateExchangeFormState();
+
+    await state.updateTo(currencyA, false);
+
+    expect(state.from, null);
+    expect(state.to, currencyA);
+    expect(state.canExchange, false);
+    expect(state.rate, null);
+    expect(state.rateDisplayString, "N/A");
+    expect(state.fromAmountString, "");
+    expect(state.toAmountString, "");
+    expect(state.minimumSendWarning, "");
+  });
+
+  test(
+      "updateTo after updateFrom where amounts are null and getMinimalExchangeAmount succeeds",
+      () async {
+    final cn = MockChangeNow();
+
+    final state = EstimatedRateExchangeFormState();
+    state.cnTesting = cn;
+
+    when(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
+        .thenAnswer((_) async => ChangeNowResponse(value: Decimal.fromInt(42)));
+
+    await state.updateFrom(currencyA, true);
+    await state.updateTo(currencyB, true);
+
+    expect(state.from, currencyA);
+    expect(state.to, currencyB);
+    expect(state.canExchange, false);
+    expect(state.rate, null);
+    expect(state.rateDisplayString, "N/A");
+    expect(state.fromAmountString, "");
+    expect(state.toAmountString, "");
+    expect(state.minimumSendWarning, "");
+
+    verify(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
+        .called(1);
+  });
+
+  test(
+      "updateTo after updateFrom where amounts are null and getMinimalExchangeAmount fails",
+      () async {
+    final cn = MockChangeNow();
+
+    final state = EstimatedRateExchangeFormState();
+    state.cnTesting = cn;
+
+    when(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
+        .thenAnswer((_) async => ChangeNowResponse());
+
+    await state.updateFrom(currencyA, true);
+    await state.updateTo(currencyB, true);
+
+    expect(state.from, currencyA);
+    expect(state.to, currencyB);
+    expect(state.canExchange, false);
+    expect(state.rate, null);
+    expect(state.rateDisplayString, "N/A");
+    expect(state.fromAmountString, "");
+    expect(state.toAmountString, "");
+    expect(state.minimumSendWarning, "");
+
+    verify(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
+        .called(1);
+  });
+
+  test(
+      "updateTo after updateFrom and setFromAmountAndCalculateToAmount where fromAmount is less than the minimum required exchange amount",
+      () async {
+    final cn = MockChangeNow();
+
+    final state = EstimatedRateExchangeFormState();
+    state.cnTesting = cn;
+
+    when(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
+        .thenAnswer((_) async => ChangeNowResponse(value: Decimal.fromInt(42)));
+
+    await state.updateFrom(currencyA, true);
+    await state.setFromAmountAndCalculateToAmount(Decimal.parse("10.10"), true);
+    await state.updateTo(currencyB, true);
+
+    expect(state.from, currencyA);
+    expect(state.to, currencyB);
+    expect(state.canExchange, false);
+    expect(state.rate, null);
+    expect(state.rateDisplayString, "N/A");
+    expect(state.fromAmountString, "10.10000000");
+    expect(state.toAmountString, "");
+    expect(state.minimumSendWarning, "Minimum amount 42 BTC");
+
+    verify(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
+        .called(1);
+  });
+
+  test(
+      "updateTo after updateFrom and setFromAmountAndCalculateToAmount where fromAmount is greater than the minimum required exchange amount",
+      () async {
+    final cn = MockChangeNow();
+
+    final state = EstimatedRateExchangeFormState();
+    state.cnTesting = cn;
+
+    when(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
+        .thenAnswer((_) async => ChangeNowResponse(value: Decimal.fromInt(42)));
+    when(cn.getEstimatedExchangeAmount(
+            fromTicker: "btc",
+            toTicker: "xmr",
+            fromAmount: Decimal.parse("110.10")))
+        .thenAnswer((_) async => ChangeNowResponse(
+                value: EstimatedExchangeAmount(
+              transactionSpeedForecast: '10-60',
+              rateId: 'some rate id',
+              warningMessage: '',
+              estimatedAmount: Decimal.parse("302.002348"),
+            )));
+
+    await state.updateFrom(currencyA, true);
+    await state.setFromAmountAndCalculateToAmount(
+        Decimal.parse("110.10"), true);
+    await state.updateTo(currencyB, true);
+
+    expect(state.from, currencyA);
+    expect(state.to, currencyB);
+    expect(state.canExchange, true);
+    expect(state.rate, Decimal.parse("2.742982270663"));
+    expect(state.rateDisplayString, "1 BTC ~2.74298227 XMR");
+    expect(state.fromAmountString, "110.10000000");
+    expect(state.toAmountString, "302.00234800");
+    expect(state.minimumSendWarning, "");
+
+    verify(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
+        .called(1);
+    verify(cn.getEstimatedExchangeAmount(
+            fromTicker: "btc",
+            toTicker: "xmr",
+            fromAmount: Decimal.parse("110.10")))
+        .called(1);
+  });
+}
diff --git a/test/models/exchange/estimated_rate_exchange_form_state_test.mocks.dart b/test/models/exchange/estimated_rate_exchange_form_state_test.mocks.dart
new file mode 100644
index 000000000..27aa1a772
--- /dev/null
+++ b/test/models/exchange/estimated_rate_exchange_form_state_test.mocks.dart
@@ -0,0 +1,212 @@
+// Mocks generated by Mockito 5.2.0 from annotations
+// in stackwallet/test/models/exchange/estimated_rate_exchange_form_state_test.dart.
+// Do not manually edit this file.
+
+import 'dart:async' as _i5;
+
+import 'package:decimal/decimal.dart' as _i7;
+import 'package:http/http.dart' as _i4;
+import 'package:mockito/mockito.dart' as _i1;
+import 'package:stackwallet/models/exchange/change_now/available_floating_rate_pair.dart'
+    as _i12;
+import 'package:stackwallet/models/exchange/change_now/change_now_response.dart'
+    as _i2;
+import 'package:stackwallet/models/exchange/change_now/currency.dart' as _i6;
+import 'package:stackwallet/models/exchange/change_now/estimated_exchange_amount.dart'
+    as _i8;
+import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart'
+    as _i10;
+import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart'
+    as _i11;
+import 'package:stackwallet/models/exchange/change_now/fixed_rate_market.dart'
+    as _i9;
+import 'package:stackwallet/services/change_now/change_now.dart' as _i3;
+
+// ignore_for_file: type=lint
+// ignore_for_file: avoid_redundant_argument_values
+// ignore_for_file: avoid_setters_without_getters
+// ignore_for_file: comment_references
+// ignore_for_file: implementation_imports
+// ignore_for_file: invalid_use_of_visible_for_testing_member
+// ignore_for_file: prefer_const_constructors
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: camel_case_types
+
+class _FakeChangeNowResponse_0<T> extends _i1.Fake
+    implements _i2.ChangeNowResponse<T> {}
+
+/// A class which mocks [ChangeNow].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockChangeNow extends _i1.Mock implements _i3.ChangeNow {
+  MockChangeNow() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  set client(_i4.Client? _client) =>
+      super.noSuchMethod(Invocation.setter(#client, _client),
+          returnValueForMissingStub: null);
+  @override
+  _i5.Future<_i2.ChangeNowResponse<List<_i6.Currency>>> getAvailableCurrencies(
+          {bool? fixedRate, bool? active}) =>
+      (super.noSuchMethod(
+          Invocation.method(#getAvailableCurrencies, [],
+              {#fixedRate: fixedRate, #active: active}),
+          returnValue: Future<_i2.ChangeNowResponse<List<_i6.Currency>>>.value(
+              _FakeChangeNowResponse_0<List<_i6.Currency>>())) as _i5
+          .Future<_i2.ChangeNowResponse<List<_i6.Currency>>>);
+  @override
+  _i5.Future<_i2.ChangeNowResponse<List<_i6.Currency>>> getPairedCurrencies(
+          {String? ticker, bool? fixedRate}) =>
+      (super.noSuchMethod(
+          Invocation.method(#getPairedCurrencies, [],
+              {#ticker: ticker, #fixedRate: fixedRate}),
+          returnValue: Future<_i2.ChangeNowResponse<List<_i6.Currency>>>.value(
+              _FakeChangeNowResponse_0<List<_i6.Currency>>())) as _i5
+          .Future<_i2.ChangeNowResponse<List<_i6.Currency>>>);
+  @override
+  _i5.Future<_i2.ChangeNowResponse<_i7.Decimal>> getMinimalExchangeAmount(
+          {String? fromTicker, String? toTicker, String? apiKey}) =>
+      (super.noSuchMethod(
+              Invocation.method(#getMinimalExchangeAmount, [], {
+                #fromTicker: fromTicker,
+                #toTicker: toTicker,
+                #apiKey: apiKey
+              }),
+              returnValue: Future<_i2.ChangeNowResponse<_i7.Decimal>>.value(
+                  _FakeChangeNowResponse_0<_i7.Decimal>()))
+          as _i5.Future<_i2.ChangeNowResponse<_i7.Decimal>>);
+  @override
+  _i5.Future<_i2.ChangeNowResponse<_i8.EstimatedExchangeAmount>>
+      getEstimatedExchangeAmount(
+              {String? fromTicker,
+              String? toTicker,
+              _i7.Decimal? fromAmount,
+              String? apiKey}) =>
+          (super.noSuchMethod(
+                  Invocation.method(#getEstimatedExchangeAmount, [], {
+                    #fromTicker: fromTicker,
+                    #toTicker: toTicker,
+                    #fromAmount: fromAmount,
+                    #apiKey: apiKey
+                  }),
+                  returnValue: Future<
+                          _i2.ChangeNowResponse<
+                              _i8.EstimatedExchangeAmount>>.value(
+                      _FakeChangeNowResponse_0<_i8.EstimatedExchangeAmount>()))
+              as _i5
+                  .Future<_i2.ChangeNowResponse<_i8.EstimatedExchangeAmount>>);
+  @override
+  _i5.Future<_i2.ChangeNowResponse<_i8.EstimatedExchangeAmount>>
+      getEstimatedFixedRateExchangeAmount(
+              {String? fromTicker,
+              String? toTicker,
+              _i7.Decimal? fromAmount,
+              bool? useRateId = true,
+              String? apiKey}) =>
+          (super.noSuchMethod(
+                  Invocation.method(#getEstimatedFixedRateExchangeAmount, [], {
+                    #fromTicker: fromTicker,
+                    #toTicker: toTicker,
+                    #fromAmount: fromAmount,
+                    #useRateId: useRateId,
+                    #apiKey: apiKey
+                  }),
+                  returnValue: Future<
+                          _i2.ChangeNowResponse<
+                              _i8.EstimatedExchangeAmount>>.value(
+                      _FakeChangeNowResponse_0<_i8.EstimatedExchangeAmount>()))
+              as _i5
+                  .Future<_i2.ChangeNowResponse<_i8.EstimatedExchangeAmount>>);
+  @override
+  _i5.Future<_i2.ChangeNowResponse<List<_i9.FixedRateMarket>>>
+      getAvailableFixedRateMarkets({String? apiKey}) => (super.noSuchMethod(
+          Invocation.method(
+              #getAvailableFixedRateMarkets, [], {#apiKey: apiKey}),
+          returnValue:
+              Future<_i2.ChangeNowResponse<List<_i9.FixedRateMarket>>>.value(
+                  _FakeChangeNowResponse_0<List<_i9.FixedRateMarket>>())) as _i5
+          .Future<_i2.ChangeNowResponse<List<_i9.FixedRateMarket>>>);
+  @override
+  _i5.Future<_i2.ChangeNowResponse<_i10.ExchangeTransaction>>
+      createStandardExchangeTransaction(
+              {String? fromTicker,
+              String? toTicker,
+              String? receivingAddress,
+              _i7.Decimal? amount,
+              String? extraId = r'',
+              String? userId = r'',
+              String? contactEmail = r'',
+              String? refundAddress = r'',
+              String? refundExtraId = r'',
+              String? apiKey}) =>
+          (super.noSuchMethod(
+              Invocation.method(#createStandardExchangeTransaction, [], {
+                #fromTicker: fromTicker,
+                #toTicker: toTicker,
+                #receivingAddress: receivingAddress,
+                #amount: amount,
+                #extraId: extraId,
+                #userId: userId,
+                #contactEmail: contactEmail,
+                #refundAddress: refundAddress,
+                #refundExtraId: refundExtraId,
+                #apiKey: apiKey
+              }),
+              returnValue: Future<
+                      _i2.ChangeNowResponse<_i10.ExchangeTransaction>>.value(
+                  _FakeChangeNowResponse_0<_i10.ExchangeTransaction>())) as _i5
+              .Future<_i2.ChangeNowResponse<_i10.ExchangeTransaction>>);
+  @override
+  _i5.Future<_i2.ChangeNowResponse<_i10.ExchangeTransaction>>
+      createFixedRateExchangeTransaction(
+              {String? fromTicker,
+              String? toTicker,
+              String? receivingAddress,
+              _i7.Decimal? amount,
+              String? rateId,
+              String? extraId = r'',
+              String? userId = r'',
+              String? contactEmail = r'',
+              String? refundAddress = r'',
+              String? refundExtraId = r'',
+              String? apiKey}) =>
+          (super.noSuchMethod(
+              Invocation.method(#createFixedRateExchangeTransaction, [], {
+                #fromTicker: fromTicker,
+                #toTicker: toTicker,
+                #receivingAddress: receivingAddress,
+                #amount: amount,
+                #rateId: rateId,
+                #extraId: extraId,
+                #userId: userId,
+                #contactEmail: contactEmail,
+                #refundAddress: refundAddress,
+                #refundExtraId: refundExtraId,
+                #apiKey: apiKey
+              }),
+              returnValue: Future<
+                      _i2.ChangeNowResponse<_i10.ExchangeTransaction>>.value(
+                  _FakeChangeNowResponse_0<_i10.ExchangeTransaction>())) as _i5
+              .Future<_i2.ChangeNowResponse<_i10.ExchangeTransaction>>);
+  @override
+  _i5.Future<_i2.ChangeNowResponse<_i11.ExchangeTransactionStatus>>
+      getTransactionStatus({String? id, String? apiKey}) => (super.noSuchMethod(
+          Invocation.method(
+              #getTransactionStatus, [], {#id: id, #apiKey: apiKey}),
+          returnValue:
+              Future<_i2.ChangeNowResponse<_i11.ExchangeTransactionStatus>>.value(
+                  _FakeChangeNowResponse_0<_i11.ExchangeTransactionStatus>())) as _i5
+          .Future<_i2.ChangeNowResponse<_i11.ExchangeTransactionStatus>>);
+  @override
+  _i5.Future<_i2.ChangeNowResponse<List<_i12.AvailableFloatingRatePair>>>
+      getAvailableFloatingRatePairs({bool? includePartners = false}) => (super
+          .noSuchMethod(
+              Invocation.method(#getAvailableFloatingRatePairs, [],
+                  {#includePartners: includePartners}),
+              returnValue:
+                  Future<_i2.ChangeNowResponse<List<_i12.AvailableFloatingRatePair>>>.value(
+                      _FakeChangeNowResponse_0<List<_i12.AvailableFloatingRatePair>>())) as _i5
+          .Future<_i2.ChangeNowResponse<List<_i12.AvailableFloatingRatePair>>>);
+}
diff --git a/test/models/isar/log_test.dart b/test/models/isar/log_test.dart
new file mode 100644
index 000000000..15e1e245b
--- /dev/null
+++ b/test/models/isar/log_test.dart
@@ -0,0 +1,15 @@
+import 'package:flutter_test/flutter_test.dart';
+import 'package:stackwallet/models/isar/models/log.dart';
+import 'package:stackwallet/utilities/logger.dart';
+
+void main() {
+  test("Log class", () {
+    final log = Log()
+      ..message = "hello"
+      ..timestampInMillisUTC = 100000001
+      ..logLevel = LogLevel.Fatal;
+
+    expect(log.toString(), "[Fatal][1970-01-02 03:46:40.001Z]: hello");
+    expect(log.id, -9223372036854775808);
+  });
+}
diff --git a/test/screen_tests/exchange/exchange_view_test.mocks.dart b/test/screen_tests/exchange/exchange_view_test.mocks.dart
index f659e3104..aa517d09b 100644
--- a/test/screen_tests/exchange/exchange_view_test.mocks.dart
+++ b/test/screen_tests/exchange/exchange_view_test.mocks.dart
@@ -2,20 +2,33 @@
 // in stackwallet/test/screen_tests/exchange/exchange_view_test.dart.
 // Do not manually edit this file.
 
-import 'dart:async' as _i6;
-import 'dart:ui' as _i7;
+import 'dart:async' as _i7;
+import 'dart:ui' as _i8;
 
+import 'package:decimal/decimal.dart' as _i15;
+import 'package:http/http.dart' as _i13;
 import 'package:mockito/mockito.dart' as _i1;
+import 'package:stackwallet/models/exchange/change_now/available_floating_rate_pair.dart'
+    as _i19;
+import 'package:stackwallet/models/exchange/change_now/change_now_response.dart'
+    as _i2;
+import 'package:stackwallet/models/exchange/change_now/currency.dart' as _i14;
+import 'package:stackwallet/models/exchange/change_now/estimated_exchange_amount.dart'
+    as _i16;
 import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart'
-    as _i9;
+    as _i10;
+import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart'
+    as _i18;
+import 'package:stackwallet/models/exchange/change_now/fixed_rate_market.dart'
+    as _i17;
 import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'
-    as _i4;
-import 'package:stackwallet/services/change_now/change_now.dart' as _i11;
-import 'package:stackwallet/services/trade_notes_service.dart' as _i10;
-import 'package:stackwallet/services/trade_service.dart' as _i8;
-import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i5;
-import 'package:stackwallet/utilities/enums/sync_type_enum.dart' as _i3;
-import 'package:stackwallet/utilities/prefs.dart' as _i2;
+    as _i5;
+import 'package:stackwallet/services/change_now/change_now.dart' as _i12;
+import 'package:stackwallet/services/trade_notes_service.dart' as _i11;
+import 'package:stackwallet/services/trade_service.dart' as _i9;
+import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i6;
+import 'package:stackwallet/utilities/enums/sync_type_enum.dart' as _i4;
+import 'package:stackwallet/utilities/prefs.dart' as _i3;
 
 // ignore_for_file: type=lint
 // ignore_for_file: avoid_redundant_argument_values
@@ -27,10 +40,13 @@ import 'package:stackwallet/utilities/prefs.dart' as _i2;
 // ignore_for_file: unnecessary_parenthesis
 // ignore_for_file: camel_case_types
 
+class _FakeChangeNowResponse_0<T> extends _i1.Fake
+    implements _i2.ChangeNowResponse<T> {}
+
 /// A class which mocks [Prefs].
 ///
 /// See the documentation for Mockito's code generation for more information.
-class MockPrefs extends _i1.Mock implements _i2.Prefs {
+class MockPrefs extends _i1.Mock implements _i3.Prefs {
   MockPrefs() {
     _i1.throwOnMissingStub(this);
   }
@@ -69,11 +85,11 @@ class MockPrefs extends _i1.Mock implements _i2.Prefs {
           Invocation.setter(#walletIdsSyncOnStartup, walletIdsSyncOnStartup),
           returnValueForMissingStub: null);
   @override
-  _i3.SyncingType get syncType =>
+  _i4.SyncingType get syncType =>
       (super.noSuchMethod(Invocation.getter(#syncType),
-          returnValue: _i3.SyncingType.currentWalletOnly) as _i3.SyncingType);
+          returnValue: _i4.SyncingType.currentWalletOnly) as _i4.SyncingType);
   @override
-  set syncType(_i3.SyncingType? syncType) =>
+  set syncType(_i4.SyncingType? syncType) =>
       super.noSuchMethod(Invocation.setter(#syncType, syncType),
           returnValueForMissingStub: null);
   @override
@@ -109,11 +125,11 @@ class MockPrefs extends _i1.Mock implements _i2.Prefs {
       super.noSuchMethod(Invocation.setter(#currency, newCurrency),
           returnValueForMissingStub: null);
   @override
-  _i4.ExchangeRateType get exchangeRateType =>
+  _i5.ExchangeRateType get exchangeRateType =>
       (super.noSuchMethod(Invocation.getter(#exchangeRateType),
-          returnValue: _i4.ExchangeRateType.estimated) as _i4.ExchangeRateType);
+          returnValue: _i5.ExchangeRateType.estimated) as _i5.ExchangeRateType);
   @override
-  set exchangeRateType(_i4.ExchangeRateType? exchangeRateType) =>
+  set exchangeRateType(_i5.ExchangeRateType? exchangeRateType) =>
       super.noSuchMethod(Invocation.setter(#exchangeRateType, exchangeRateType),
           returnValueForMissingStub: null);
   @override
@@ -153,12 +169,12 @@ class MockPrefs extends _i1.Mock implements _i2.Prefs {
       Invocation.setter(#autoBackupLocation, autoBackupLocation),
       returnValueForMissingStub: null);
   @override
-  _i5.BackupFrequencyType get backupFrequencyType =>
+  _i6.BackupFrequencyType get backupFrequencyType =>
       (super.noSuchMethod(Invocation.getter(#backupFrequencyType),
-              returnValue: _i5.BackupFrequencyType.everyTenMinutes)
-          as _i5.BackupFrequencyType);
+              returnValue: _i6.BackupFrequencyType.everyTenMinutes)
+          as _i6.BackupFrequencyType);
   @override
-  set backupFrequencyType(_i5.BackupFrequencyType? backupFrequencyType) =>
+  set backupFrequencyType(_i6.BackupFrequencyType? backupFrequencyType) =>
       super.noSuchMethod(
           Invocation.setter(#backupFrequencyType, backupFrequencyType),
           returnValueForMissingStub: null);
@@ -171,20 +187,20 @@ class MockPrefs extends _i1.Mock implements _i2.Prefs {
       (super.noSuchMethod(Invocation.getter(#hasListeners), returnValue: false)
           as bool);
   @override
-  _i6.Future<void> init() => (super.noSuchMethod(Invocation.method(#init, []),
+  _i7.Future<void> init() => (super.noSuchMethod(Invocation.method(#init, []),
       returnValue: Future<void>.value(),
-      returnValueForMissingStub: Future<void>.value()) as _i6.Future<void>);
+      returnValueForMissingStub: Future<void>.value()) as _i7.Future<void>);
   @override
-  _i6.Future<void> incrementCurrentNotificationIndex() => (super.noSuchMethod(
+  _i7.Future<void> incrementCurrentNotificationIndex() => (super.noSuchMethod(
       Invocation.method(#incrementCurrentNotificationIndex, []),
       returnValue: Future<void>.value(),
-      returnValueForMissingStub: Future<void>.value()) as _i6.Future<void>);
+      returnValueForMissingStub: Future<void>.value()) as _i7.Future<void>);
   @override
-  void addListener(_i7.VoidCallback? listener) =>
+  void addListener(_i8.VoidCallback? listener) =>
       super.noSuchMethod(Invocation.method(#addListener, [listener]),
           returnValueForMissingStub: null);
   @override
-  void removeListener(_i7.VoidCallback? listener) =>
+  void removeListener(_i8.VoidCallback? listener) =>
       super.noSuchMethod(Invocation.method(#removeListener, [listener]),
           returnValueForMissingStub: null);
   @override
@@ -199,57 +215,57 @@ class MockPrefs extends _i1.Mock implements _i2.Prefs {
 /// A class which mocks [TradesService].
 ///
 /// See the documentation for Mockito's code generation for more information.
-class MockTradesService extends _i1.Mock implements _i8.TradesService {
+class MockTradesService extends _i1.Mock implements _i9.TradesService {
   MockTradesService() {
     _i1.throwOnMissingStub(this);
   }
 
   @override
-  List<_i9.ExchangeTransaction> get trades =>
+  List<_i10.ExchangeTransaction> get trades =>
       (super.noSuchMethod(Invocation.getter(#trades),
-              returnValue: <_i9.ExchangeTransaction>[])
-          as List<_i9.ExchangeTransaction>);
+              returnValue: <_i10.ExchangeTransaction>[])
+          as List<_i10.ExchangeTransaction>);
   @override
   bool get hasListeners =>
       (super.noSuchMethod(Invocation.getter(#hasListeners), returnValue: false)
           as bool);
   @override
-  _i6.Future<void> add(
-          {_i9.ExchangeTransaction? trade, bool? shouldNotifyListeners}) =>
+  _i7.Future<void> add(
+          {_i10.ExchangeTransaction? trade, bool? shouldNotifyListeners}) =>
       (super.noSuchMethod(
           Invocation.method(#add, [],
               {#trade: trade, #shouldNotifyListeners: shouldNotifyListeners}),
           returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i6.Future<void>);
+          returnValueForMissingStub: Future<void>.value()) as _i7.Future<void>);
   @override
-  _i6.Future<void> edit(
-          {_i9.ExchangeTransaction? trade, bool? shouldNotifyListeners}) =>
+  _i7.Future<void> edit(
+          {_i10.ExchangeTransaction? trade, bool? shouldNotifyListeners}) =>
       (super.noSuchMethod(
           Invocation.method(#edit, [],
               {#trade: trade, #shouldNotifyListeners: shouldNotifyListeners}),
           returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i6.Future<void>);
+          returnValueForMissingStub: Future<void>.value()) as _i7.Future<void>);
   @override
-  _i6.Future<void> delete(
-          {_i9.ExchangeTransaction? trade, bool? shouldNotifyListeners}) =>
+  _i7.Future<void> delete(
+          {_i10.ExchangeTransaction? trade, bool? shouldNotifyListeners}) =>
       (super.noSuchMethod(
           Invocation.method(#delete, [],
               {#trade: trade, #shouldNotifyListeners: shouldNotifyListeners}),
           returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i6.Future<void>);
+          returnValueForMissingStub: Future<void>.value()) as _i7.Future<void>);
   @override
-  _i6.Future<void> deleteByUuid({String? uuid, bool? shouldNotifyListeners}) =>
+  _i7.Future<void> deleteByUuid({String? uuid, bool? shouldNotifyListeners}) =>
       (super.noSuchMethod(
           Invocation.method(#deleteByUuid, [],
               {#uuid: uuid, #shouldNotifyListeners: shouldNotifyListeners}),
           returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i6.Future<void>);
+          returnValueForMissingStub: Future<void>.value()) as _i7.Future<void>);
   @override
-  void addListener(_i7.VoidCallback? listener) =>
+  void addListener(_i8.VoidCallback? listener) =>
       super.noSuchMethod(Invocation.method(#addListener, [listener]),
           returnValueForMissingStub: null);
   @override
-  void removeListener(_i7.VoidCallback? listener) =>
+  void removeListener(_i8.VoidCallback? listener) =>
       super.noSuchMethod(Invocation.method(#removeListener, [listener]),
           returnValueForMissingStub: null);
   @override
@@ -264,7 +280,7 @@ class MockTradesService extends _i1.Mock implements _i8.TradesService {
 /// A class which mocks [TradeNotesService].
 ///
 /// See the documentation for Mockito's code generation for more information.
-class MockTradeNotesService extends _i1.Mock implements _i10.TradeNotesService {
+class MockTradeNotesService extends _i1.Mock implements _i11.TradeNotesService {
   MockTradeNotesService() {
     _i1.throwOnMissingStub(this);
   }
@@ -281,21 +297,21 @@ class MockTradeNotesService extends _i1.Mock implements _i10.TradeNotesService {
       (super.noSuchMethod(Invocation.method(#getNote, [], {#tradeId: tradeId}),
           returnValue: '') as String);
   @override
-  _i6.Future<void> set({String? tradeId, String? note}) => (super.noSuchMethod(
+  _i7.Future<void> set({String? tradeId, String? note}) => (super.noSuchMethod(
       Invocation.method(#set, [], {#tradeId: tradeId, #note: note}),
       returnValue: Future<void>.value(),
-      returnValueForMissingStub: Future<void>.value()) as _i6.Future<void>);
+      returnValueForMissingStub: Future<void>.value()) as _i7.Future<void>);
   @override
-  _i6.Future<void> delete({String? tradeId}) =>
+  _i7.Future<void> delete({String? tradeId}) =>
       (super.noSuchMethod(Invocation.method(#delete, [], {#tradeId: tradeId}),
           returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i6.Future<void>);
+          returnValueForMissingStub: Future<void>.value()) as _i7.Future<void>);
   @override
-  void addListener(_i7.VoidCallback? listener) =>
+  void addListener(_i8.VoidCallback? listener) =>
       super.noSuchMethod(Invocation.method(#addListener, [listener]),
           returnValueForMissingStub: null);
   @override
-  void removeListener(_i7.VoidCallback? listener) =>
+  void removeListener(_i8.VoidCallback? listener) =>
       super.noSuchMethod(Invocation.method(#removeListener, [listener]),
           returnValueForMissingStub: null);
   @override
@@ -310,8 +326,175 @@ class MockTradeNotesService extends _i1.Mock implements _i10.TradeNotesService {
 /// A class which mocks [ChangeNow].
 ///
 /// See the documentation for Mockito's code generation for more information.
-class MockChangeNow extends _i1.Mock implements _i11.ChangeNow {
+class MockChangeNow extends _i1.Mock implements _i12.ChangeNow {
   MockChangeNow() {
     _i1.throwOnMissingStub(this);
   }
+
+  @override
+  set client(_i13.Client? _client) =>
+      super.noSuchMethod(Invocation.setter(#client, _client),
+          returnValueForMissingStub: null);
+  @override
+  _i7.Future<_i2.ChangeNowResponse<List<_i14.Currency>>> getAvailableCurrencies(
+          {bool? fixedRate, bool? active}) =>
+      (super.noSuchMethod(
+          Invocation.method(#getAvailableCurrencies, [],
+              {#fixedRate: fixedRate, #active: active}),
+          returnValue: Future<_i2.ChangeNowResponse<List<_i14.Currency>>>.value(
+              _FakeChangeNowResponse_0<List<_i14.Currency>>())) as _i7
+          .Future<_i2.ChangeNowResponse<List<_i14.Currency>>>);
+  @override
+  _i7.Future<_i2.ChangeNowResponse<List<_i14.Currency>>> getPairedCurrencies(
+          {String? ticker, bool? fixedRate}) =>
+      (super.noSuchMethod(
+          Invocation.method(#getPairedCurrencies, [],
+              {#ticker: ticker, #fixedRate: fixedRate}),
+          returnValue: Future<_i2.ChangeNowResponse<List<_i14.Currency>>>.value(
+              _FakeChangeNowResponse_0<List<_i14.Currency>>())) as _i7
+          .Future<_i2.ChangeNowResponse<List<_i14.Currency>>>);
+  @override
+  _i7.Future<_i2.ChangeNowResponse<_i15.Decimal>> getMinimalExchangeAmount(
+          {String? fromTicker, String? toTicker, String? apiKey}) =>
+      (super.noSuchMethod(
+              Invocation.method(#getMinimalExchangeAmount, [], {
+                #fromTicker: fromTicker,
+                #toTicker: toTicker,
+                #apiKey: apiKey
+              }),
+              returnValue: Future<_i2.ChangeNowResponse<_i15.Decimal>>.value(
+                  _FakeChangeNowResponse_0<_i15.Decimal>()))
+          as _i7.Future<_i2.ChangeNowResponse<_i15.Decimal>>);
+  @override
+  _i7.Future<_i2.ChangeNowResponse<_i16.EstimatedExchangeAmount>>
+      getEstimatedExchangeAmount(
+              {String? fromTicker,
+              String? toTicker,
+              _i15.Decimal? fromAmount,
+              String? apiKey}) =>
+          (super.noSuchMethod(
+                  Invocation.method(#getEstimatedExchangeAmount, [], {
+                    #fromTicker: fromTicker,
+                    #toTicker: toTicker,
+                    #fromAmount: fromAmount,
+                    #apiKey: apiKey
+                  }),
+                  returnValue: Future<
+                          _i2.ChangeNowResponse<
+                              _i16.EstimatedExchangeAmount>>.value(
+                      _FakeChangeNowResponse_0<_i16.EstimatedExchangeAmount>()))
+              as _i7
+                  .Future<_i2.ChangeNowResponse<_i16.EstimatedExchangeAmount>>);
+  @override
+  _i7.Future<_i2.ChangeNowResponse<_i16.EstimatedExchangeAmount>>
+      getEstimatedFixedRateExchangeAmount(
+              {String? fromTicker,
+              String? toTicker,
+              _i15.Decimal? fromAmount,
+              bool? useRateId = true,
+              String? apiKey}) =>
+          (super.noSuchMethod(
+                  Invocation.method(#getEstimatedFixedRateExchangeAmount, [], {
+                    #fromTicker: fromTicker,
+                    #toTicker: toTicker,
+                    #fromAmount: fromAmount,
+                    #useRateId: useRateId,
+                    #apiKey: apiKey
+                  }),
+                  returnValue: Future<
+                          _i2.ChangeNowResponse<
+                              _i16.EstimatedExchangeAmount>>.value(
+                      _FakeChangeNowResponse_0<_i16.EstimatedExchangeAmount>()))
+              as _i7
+                  .Future<_i2.ChangeNowResponse<_i16.EstimatedExchangeAmount>>);
+  @override
+  _i7.Future<_i2.ChangeNowResponse<List<_i17.FixedRateMarket>>>
+      getAvailableFixedRateMarkets({String? apiKey}) => (super.noSuchMethod(
+          Invocation.method(
+              #getAvailableFixedRateMarkets, [], {#apiKey: apiKey}),
+          returnValue:
+              Future<_i2.ChangeNowResponse<List<_i17.FixedRateMarket>>>.value(
+                  _FakeChangeNowResponse_0<List<_i17.FixedRateMarket>>())) as _i7
+          .Future<_i2.ChangeNowResponse<List<_i17.FixedRateMarket>>>);
+  @override
+  _i7.Future<_i2.ChangeNowResponse<_i10.ExchangeTransaction>>
+      createStandardExchangeTransaction(
+              {String? fromTicker,
+              String? toTicker,
+              String? receivingAddress,
+              _i15.Decimal? amount,
+              String? extraId = r'',
+              String? userId = r'',
+              String? contactEmail = r'',
+              String? refundAddress = r'',
+              String? refundExtraId = r'',
+              String? apiKey}) =>
+          (super.noSuchMethod(
+              Invocation.method(#createStandardExchangeTransaction, [], {
+                #fromTicker: fromTicker,
+                #toTicker: toTicker,
+                #receivingAddress: receivingAddress,
+                #amount: amount,
+                #extraId: extraId,
+                #userId: userId,
+                #contactEmail: contactEmail,
+                #refundAddress: refundAddress,
+                #refundExtraId: refundExtraId,
+                #apiKey: apiKey
+              }),
+              returnValue: Future<
+                      _i2.ChangeNowResponse<_i10.ExchangeTransaction>>.value(
+                  _FakeChangeNowResponse_0<_i10.ExchangeTransaction>())) as _i7
+              .Future<_i2.ChangeNowResponse<_i10.ExchangeTransaction>>);
+  @override
+  _i7.Future<_i2.ChangeNowResponse<_i10.ExchangeTransaction>>
+      createFixedRateExchangeTransaction(
+              {String? fromTicker,
+              String? toTicker,
+              String? receivingAddress,
+              _i15.Decimal? amount,
+              String? rateId,
+              String? extraId = r'',
+              String? userId = r'',
+              String? contactEmail = r'',
+              String? refundAddress = r'',
+              String? refundExtraId = r'',
+              String? apiKey}) =>
+          (super.noSuchMethod(
+              Invocation.method(#createFixedRateExchangeTransaction, [], {
+                #fromTicker: fromTicker,
+                #toTicker: toTicker,
+                #receivingAddress: receivingAddress,
+                #amount: amount,
+                #rateId: rateId,
+                #extraId: extraId,
+                #userId: userId,
+                #contactEmail: contactEmail,
+                #refundAddress: refundAddress,
+                #refundExtraId: refundExtraId,
+                #apiKey: apiKey
+              }),
+              returnValue: Future<
+                      _i2.ChangeNowResponse<_i10.ExchangeTransaction>>.value(
+                  _FakeChangeNowResponse_0<_i10.ExchangeTransaction>())) as _i7
+              .Future<_i2.ChangeNowResponse<_i10.ExchangeTransaction>>);
+  @override
+  _i7.Future<_i2.ChangeNowResponse<_i18.ExchangeTransactionStatus>>
+      getTransactionStatus({String? id, String? apiKey}) => (super.noSuchMethod(
+          Invocation.method(
+              #getTransactionStatus, [], {#id: id, #apiKey: apiKey}),
+          returnValue:
+              Future<_i2.ChangeNowResponse<_i18.ExchangeTransactionStatus>>.value(
+                  _FakeChangeNowResponse_0<_i18.ExchangeTransactionStatus>())) as _i7
+          .Future<_i2.ChangeNowResponse<_i18.ExchangeTransactionStatus>>);
+  @override
+  _i7.Future<_i2.ChangeNowResponse<List<_i19.AvailableFloatingRatePair>>>
+      getAvailableFloatingRatePairs({bool? includePartners = false}) => (super
+          .noSuchMethod(
+              Invocation.method(#getAvailableFloatingRatePairs, [],
+                  {#includePartners: includePartners}),
+              returnValue:
+                  Future<_i2.ChangeNowResponse<List<_i19.AvailableFloatingRatePair>>>.value(
+                      _FakeChangeNowResponse_0<List<_i19.AvailableFloatingRatePair>>())) as _i7
+          .Future<_i2.ChangeNowResponse<List<_i19.AvailableFloatingRatePair>>>);
 }
diff --git a/test/services/change_now/change_now_test.dart b/test/services/change_now/change_now_test.dart
index 7a923907b..a5b927298 100644
--- a/test/services/change_now/change_now_test.dart
+++ b/test/services/change_now/change_now_test.dart
@@ -339,80 +339,80 @@ void main() {
     });
   });
 
-  group("getEstimatedFixedRateExchangeAmount", () {
-    test("getEstimatedFixedRateExchangeAmount succeeds", () async {
-      final client = MockClient();
-      ChangeNow.instance.client = client;
-
-      when(client.get(
-        Uri.parse(
-            "https://api.ChangeNow.io/v1/exchange-amount/fixed-rate/10/xmr_btc?api_key=testAPIKEY&useRateId=true"),
-        headers: {'Content-Type': 'application/json'},
-      )).thenAnswer((realInvocation) async =>
-          Response(jsonEncode(estFixedRateExchangeAmountJSON), 200));
-
-      final result =
-          await ChangeNow.instance.getEstimatedFixedRateExchangeAmount(
-        fromTicker: "xmr",
-        toTicker: "btc",
-        fromAmount: Decimal.fromInt(10),
-        apiKey: "testAPIKEY",
-      );
-
-      expect(result.exception, null);
-      expect(result.value == null, false);
-      expect(result.value.toString(),
-          'EstimatedExchangeAmount: {estimatedAmount: 0.07271053, transactionSpeedForecast: 10-60, warningMessage: null, rateId: 1t2W5KBPqhycSJVYpaNZzYWLfMr0kSFe, networkFee: 0.00002408}');
-    });
-
-    test(
-        "getEstimatedFixedRateExchangeAmount fails with ChangeNowExceptionType.serializeResponseError",
-        () async {
-      final client = MockClient();
-      ChangeNow.instance.client = client;
-
-      when(client.get(
-        Uri.parse(
-            "https://api.ChangeNow.io/v1/exchange-amount/fixed-rate/10/xmr_btc?api_key=testAPIKEY&useRateId=true"),
-        headers: {'Content-Type': 'application/json'},
-      )).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
-
-      final result =
-          await ChangeNow.instance.getEstimatedFixedRateExchangeAmount(
-        fromTicker: "xmr",
-        toTicker: "btc",
-        fromAmount: Decimal.fromInt(10),
-        apiKey: "testAPIKEY",
-      );
-
-      expect(result.exception!.type,
-          ChangeNowExceptionType.serializeResponseError);
-      expect(result.value == null, true);
-    });
-
-    test("getEstimatedFixedRateExchangeAmount fails for any other reason",
-        () async {
-      final client = MockClient();
-      ChangeNow.instance.client = client;
-
-      when(client.get(
-        Uri.parse(
-            "https://api.ChangeNow.io/v1/exchange-amount/fixed-rate/10/xmr_btc?api_key=testAPIKEY&useRateId=true"),
-        headers: {'Content-Type': 'application/json'},
-      )).thenAnswer((realInvocation) async => Response('', 400));
-
-      final result =
-          await ChangeNow.instance.getEstimatedFixedRateExchangeAmount(
-        fromTicker: "xmr",
-        toTicker: "btc",
-        fromAmount: Decimal.fromInt(10),
-        apiKey: "testAPIKEY",
-      );
-
-      expect(result.exception!.type, ChangeNowExceptionType.generic);
-      expect(result.value == null, true);
-    });
-  });
+  // group("getEstimatedFixedRateExchangeAmount", () {
+  //   test("getEstimatedFixedRateExchangeAmount succeeds", () async {
+  //     final client = MockClient();
+  //     ChangeNow.instance.client = client;
+  //
+  //     when(client.get(
+  //       Uri.parse(
+  //           "https://api.ChangeNow.io/v1/exchange-amount/fixed-rate/10/xmr_btc?api_key=testAPIKEY&useRateId=true"),
+  //       headers: {'Content-Type': 'application/json'},
+  //     )).thenAnswer((realInvocation) async =>
+  //         Response(jsonEncode(estFixedRateExchangeAmountJSON), 200));
+  //
+  //     final result =
+  //         await ChangeNow.instance.getEstimatedFixedRateExchangeAmount(
+  //       fromTicker: "xmr",
+  //       toTicker: "btc",
+  //       fromAmount: Decimal.fromInt(10),
+  //       apiKey: "testAPIKEY",
+  //     );
+  //
+  //     expect(result.exception, null);
+  //     expect(result.value == null, false);
+  //     expect(result.value.toString(),
+  //         'EstimatedExchangeAmount: {estimatedAmount: 0.07271053, transactionSpeedForecast: 10-60, warningMessage: null, rateId: 1t2W5KBPqhycSJVYpaNZzYWLfMr0kSFe, networkFee: 0.00002408}');
+  //   });
+  //
+  //   test(
+  //       "getEstimatedFixedRateExchangeAmount fails with ChangeNowExceptionType.serializeResponseError",
+  //       () async {
+  //     final client = MockClient();
+  //     ChangeNow.instance.client = client;
+  //
+  //     when(client.get(
+  //       Uri.parse(
+  //           "https://api.ChangeNow.io/v1/exchange-amount/fixed-rate/10/xmr_btc?api_key=testAPIKEY&useRateId=true"),
+  //       headers: {'Content-Type': 'application/json'},
+  //     )).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
+  //
+  //     final result =
+  //         await ChangeNow.instance.getEstimatedFixedRateExchangeAmount(
+  //       fromTicker: "xmr",
+  //       toTicker: "btc",
+  //       fromAmount: Decimal.fromInt(10),
+  //       apiKey: "testAPIKEY",
+  //     );
+  //
+  //     expect(result.exception!.type,
+  //         ChangeNowExceptionType.serializeResponseError);
+  //     expect(result.value == null, true);
+  //   });
+  //
+  //   test("getEstimatedFixedRateExchangeAmount fails for any other reason",
+  //       () async {
+  //     final client = MockClient();
+  //     ChangeNow.instance.client = client;
+  //
+  //     when(client.get(
+  //       Uri.parse(
+  //           "https://api.ChangeNow.io/v1/exchange-amount/fixed-rate/10/xmr_btc?api_key=testAPIKEY&useRateId=true"),
+  //       headers: {'Content-Type': 'application/json'},
+  //     )).thenAnswer((realInvocation) async => Response('', 400));
+  //
+  //     final result =
+  //         await ChangeNow.instance.getEstimatedFixedRateExchangeAmount(
+  //       fromTicker: "xmr",
+  //       toTicker: "btc",
+  //       fromAmount: Decimal.fromInt(10),
+  //       apiKey: "testAPIKEY",
+  //     );
+  //
+  //     expect(result.exception!.type, ChangeNowExceptionType.generic);
+  //     expect(result.value == null, true);
+  //   });
+  // });
 
   group("getAvailableFixedRateMarkets", () {
     test("getAvailableFixedRateMarkets succeeds", () async {
diff --git a/test/services/coins/bitcoin/bitcoin_wallet_test.dart b/test/services/coins/bitcoin/bitcoin_wallet_test.dart
index 7e199bf68..fce994961 100644
--- a/test/services/coins/bitcoin/bitcoin_wallet_test.dart
+++ b/test/services/coins/bitcoin/bitcoin_wallet_test.dart
@@ -30,7 +30,7 @@ void main() {
       expect(MINIMUM_CONFIRMATIONS, 2);
     });
     test("bitcoin dust limit", () async {
-      expect(DUST_LIMIT, 546);
+      expect(DUST_LIMIT, 294);
     });
     test("bitcoin mainnet genesis block hash", () async {
       expect(GENESIS_HASH_MAINNET,
diff --git a/test/services/coins/fake_coin_service_api.dart b/test/services/coins/fake_coin_service_api.dart
index c368db129..a3ae28a4b 100644
--- a/test/services/coins/fake_coin_service_api.dart
+++ b/test/services/coins/fake_coin_service_api.dart
@@ -176,4 +176,10 @@ class FakeCoinServiceAPI extends CoinServiceAPI {
     // TODO: implement testNetworkConnection
     throw UnimplementedError();
   }
+
+  @override
+  Future<bool> generateNewAddress() {
+    // TODO: implement generateNewAddress
+    throw UnimplementedError();
+  }
 }
diff --git a/test/services/coins/firo/firo_wallet_test.dart b/test/services/coins/firo/firo_wallet_test.dart
index 18dd31d24..e6d9f6e74 100644
--- a/test/services/coins/firo/firo_wallet_test.dart
+++ b/test/services/coins/firo/firo_wallet_test.dart
@@ -26,7 +26,6 @@ import 'firo_wallet_test.mocks.dart';
 import 'firo_wallet_test_parameters.dart';
 import 'sample_data/get_anonymity_set_sample_data.dart';
 import 'sample_data/get_used_serials_sample_data.dart';
-import 'sample_data/get_utxos_sample_data.dart';
 import 'sample_data/gethistory_samples.dart';
 import 'sample_data/transaction_data_samples.dart';
 
@@ -3398,224 +3397,224 @@ void main() {
       await firo.exit();
     });
 
-    test("autoMint", () async {
-      TestWidgetsFlutterBinding.ensureInitialized();
-      const MethodChannel('uk.spiralarm.flutter/devicelocale')
-          .setMockMethodCallHandler((methodCall) async => 'en_US');
-
-      final client = MockElectrumX();
-      final cachedClient = MockCachedElectrumX();
-      final secureStore = FakeSecureStorage();
-      final priceAPI = MockPriceAPI();
-
-      // mock electrumx client calls
-      when(client.getServerFeatures()).thenAnswer((_) async => {
-            "hosts": {},
-            "pruning": null,
-            "server_version": "Unit tests",
-            "protocol_min": "1.4",
-            "protocol_max": "1.4.2",
-            "genesis_hash": GENESIS_HASH_MAINNET,
-            "hash_function": "sha256",
-            "services": []
-          });
-
-      when(client.getBlockHeadTip()).thenAnswer(
-          (_) async => {"height": 465873, "hex": "this value not used here"});
-
-      when(client.broadcastTransaction(rawTx: anyNamed("rawTx")))
-          .thenAnswer((realInvocation) async {
-        final rawTx =
-            realInvocation.namedArguments[const Symbol("rawTx")] as String;
-        final rawTxData = Format.stringToUint8List(rawTx);
-
-        final hash = sha256
-            .convert(sha256.convert(rawTxData.toList(growable: false)).bytes);
-
-        final reversedBytes =
-            Uint8List.fromList(hash.bytes.reversed.toList(growable: false));
-
-        final txid = Format.uint8listToString(reversedBytes);
-
-        return txid;
-      });
-
-      when(client.estimateFee(blocks: 1))
-          .thenAnswer((_) async => Decimal.parse("0.00001000"));
-      when(client.estimateFee(blocks: 5))
-          .thenAnswer((_) async => Decimal.parse("0.00001000"));
-      when(client.estimateFee(blocks: 20))
-          .thenAnswer((_) async => Decimal.parse("0.00001000"));
-
-      when(cachedClient.getAnonymitySet(
-              groupId: "1", blockhash: "", coin: Coin.firo))
-          .thenAnswer((_) async => GetAnonymitySetSampleData.data);
-      when(cachedClient.getUsedCoinSerials(startNumber: 0, coin: Coin.firo))
-          .thenAnswer(
-              (_) async => GetUsedSerialsSampleData.serials['serials'] as List);
-
-      when(client.getLatestCoinId()).thenAnswer((_) async => 1);
-      // when(client.getCoinsForRecovery(setId: 1))
-      //     .thenAnswer((_) async => getCoinsForRecoveryResponse);
-      when(client.getUsedCoinSerials(startNumber: 0))
-          .thenAnswer((_) async => GetUsedSerialsSampleData.serials);
-
-      // mock price calls
-      when(priceAPI.getPricesAnd24hChange(baseCurrency: "USD")).thenAnswer(
-          (_) async => {Coin.firo: Tuple2(Decimal.fromInt(10), 1.0)});
-
-      // mock transaction calls
-      when(cachedClient.getTransaction(
-        txHash: SampleGetTransactionData.txHash0,
-        coin: Coin.firo,
-      )).thenAnswer((_) async => SampleGetTransactionData.txData0);
-      when(cachedClient.getTransaction(
-        txHash: SampleGetTransactionData.txHash1,
-        coin: Coin.firo,
-      )).thenAnswer((_) async => SampleGetTransactionData.txData1);
-      when(cachedClient.getTransaction(
-        txHash: SampleGetTransactionData.txHash2,
-        coin: Coin.firo,
-      )).thenAnswer((_) async => SampleGetTransactionData.txData2);
-      when(cachedClient.getTransaction(
-        txHash: SampleGetTransactionData.txHash3,
-        coin: Coin.firo,
-      )).thenAnswer((_) async => SampleGetTransactionData.txData3);
-      when(cachedClient.getTransaction(
-        txHash: SampleGetTransactionData.txHash4,
-        coin: Coin.firo,
-      )).thenAnswer((_) async => SampleGetTransactionData.txData4);
-      when(cachedClient.getTransaction(
-        txHash: SampleGetTransactionData.txHash5,
-        coin: Coin.firo,
-      )).thenAnswer((_) async => SampleGetTransactionData.txData5);
-      when(cachedClient.getTransaction(
-        txHash: SampleGetTransactionData.txHash6,
-        coin: Coin.firo,
-      )).thenAnswer((_) async => SampleGetTransactionData.txData6);
-      when(cachedClient.getTransaction(
-        txHash: SampleGetTransactionData.txHash7,
-        coin: Coin.firo,
-      )).thenAnswer((_) async => SampleGetTransactionData.txData7);
-      when(cachedClient.getTransaction(
-        txHash: SampleGetTransactionData.txHash8,
-        coin: Coin.firo,
-      )).thenAnswer((_) async => SampleGetTransactionData.txData8);
-      when(cachedClient.getTransaction(
-        txHash: SampleGetTransactionData.txHash9,
-        coin: Coin.firo,
-      )).thenAnswer((_) async => SampleGetTransactionData.txData9);
-      when(cachedClient.getTransaction(
-        txHash: SampleGetTransactionData.txHash10,
-        coin: Coin.firo,
-      )).thenAnswer((_) async => SampleGetTransactionData.txData10);
-      when(cachedClient.getTransaction(
-        txHash: SampleGetTransactionData.txHash11,
-        coin: Coin.firo,
-      )).thenAnswer((_) async => SampleGetTransactionData.txData11);
-      when(cachedClient.getTransaction(
-        txHash: SampleGetTransactionData.txHash12,
-        coin: Coin.firo,
-      )).thenAnswer((_) async => SampleGetTransactionData.txData12);
-
-      final firo = FiroWallet(
-        walletName: testWalletName,
-        walletId: "${testWalletId}autoMint",
-        coin: Coin.firo,
-        client: client,
-        cachedClient: cachedClient,
-        secureStore: secureStore,
-        priceAPI: priceAPI,
-        tracker: MockTransactionNotificationTracker(),
-      );
-
-      // pre grab derivations in order to set up mock calls needed later on
-      await firo.fillAddresses(TEST_MNEMONIC);
-      final wallet = await Hive.openBox<dynamic>("${testWalletId}autoMint");
-      await wallet.put(
-          'receivingAddresses', RefreshTestParams.receivingAddresses);
-      await wallet.put('changeAddresses', RefreshTestParams.changeAddresses);
-
-      final rcv = await secureStore.read(
-          key: "${testWalletId}autoMint_receiveDerivations");
-      final chg = await secureStore.read(
-          key: "${testWalletId}autoMint_changeDerivations");
-      final receiveDerivations =
-          Map<String, dynamic>.from(jsonDecode(rcv as String) as Map);
-      final changeDerivations =
-          Map<String, dynamic>.from(jsonDecode(chg as String) as Map);
-
-      for (int i = 0; i < receiveDerivations.length; i++) {
-        final receiveHash = AddressUtils.convertToScriptHash(
-            receiveDerivations["$i"]!["address"] as String, firoNetwork);
-        final changeHash = AddressUtils.convertToScriptHash(
-            changeDerivations["$i"]!["address"] as String, firoNetwork);
-        List<Map<String, dynamic>> data;
-        switch (receiveHash) {
-          case SampleGetHistoryData.scripthash0:
-            data = SampleGetHistoryData.data0;
-            break;
-          case SampleGetHistoryData.scripthash1:
-            data = SampleGetHistoryData.data1;
-            break;
-          case SampleGetHistoryData.scripthash2:
-            data = SampleGetHistoryData.data2;
-            break;
-          case SampleGetHistoryData.scripthash3:
-            data = SampleGetHistoryData.data3;
-            break;
-          default:
-            data = [];
-        }
-        when(client.getHistory(scripthash: receiveHash))
-            .thenAnswer((_) async => data);
-
-        switch (changeHash) {
-          case SampleGetHistoryData.scripthash0:
-            data = SampleGetHistoryData.data0;
-            break;
-          case SampleGetHistoryData.scripthash1:
-            data = SampleGetHistoryData.data1;
-            break;
-          case SampleGetHistoryData.scripthash2:
-            data = SampleGetHistoryData.data2;
-            break;
-          case SampleGetHistoryData.scripthash3:
-            data = SampleGetHistoryData.data3;
-            break;
-          default:
-            data = [];
-        }
-
-        when(client.getHistory(scripthash: changeHash))
-            .thenAnswer((_) async => data);
-      }
-
-      when(client.getUTXOs(scripthash: GetUtxoSampleData.scriptHash0))
-          .thenAnswer((_) async => GetUtxoSampleData.utxos0);
-      when(client.getUTXOs(scripthash: GetUtxoSampleData.scriptHash1))
-          .thenAnswer((_) async => GetUtxoSampleData.utxos1);
-
-      await firo.recoverFromMnemonic(
-          mnemonic: TEST_MNEMONIC,
-          maxUnusedAddressGap: 20,
-          height: 0,
-          maxNumberOfIndexesToCheck: 1000);
-
-      firo.timer = Timer(const Duration(minutes: 3), () {});
-
-      await firo.refresh();
-
-      bool flag = false;
-      try {
-        await firo.autoMint();
-      } catch (_) {
-        flag = true;
-      }
-      expect(flag, false);
-
-      await firo.exit();
-    }, timeout: const Timeout(Duration(minutes: 3)));
+    // test("autoMint", () async {
+    //   TestWidgetsFlutterBinding.ensureInitialized();
+    //   const MethodChannel('uk.spiralarm.flutter/devicelocale')
+    //       .setMockMethodCallHandler((methodCall) async => 'en_US');
+    //
+    //   final client = MockElectrumX();
+    //   final cachedClient = MockCachedElectrumX();
+    //   final secureStore = FakeSecureStorage();
+    //   final priceAPI = MockPriceAPI();
+    //
+    //   // mock electrumx client calls
+    //   when(client.getServerFeatures()).thenAnswer((_) async => {
+    //         "hosts": {},
+    //         "pruning": null,
+    //         "server_version": "Unit tests",
+    //         "protocol_min": "1.4",
+    //         "protocol_max": "1.4.2",
+    //         "genesis_hash": GENESIS_HASH_MAINNET,
+    //         "hash_function": "sha256",
+    //         "services": []
+    //       });
+    //
+    //   when(client.getBlockHeadTip()).thenAnswer(
+    //       (_) async => {"height": 465873, "hex": "this value not used here"});
+    //
+    //   when(client.broadcastTransaction(rawTx: anyNamed("rawTx")))
+    //       .thenAnswer((realInvocation) async {
+    //     final rawTx =
+    //         realInvocation.namedArguments[const Symbol("rawTx")] as String;
+    //     final rawTxData = Format.stringToUint8List(rawTx);
+    //
+    //     final hash = sha256
+    //         .convert(sha256.convert(rawTxData.toList(growable: false)).bytes);
+    //
+    //     final reversedBytes =
+    //         Uint8List.fromList(hash.bytes.reversed.toList(growable: false));
+    //
+    //     final txid = Format.uint8listToString(reversedBytes);
+    //
+    //     return txid;
+    //   });
+    //
+    //   when(client.estimateFee(blocks: 1))
+    //       .thenAnswer((_) async => Decimal.parse("0.00001000"));
+    //   when(client.estimateFee(blocks: 5))
+    //       .thenAnswer((_) async => Decimal.parse("0.00001000"));
+    //   when(client.estimateFee(blocks: 20))
+    //       .thenAnswer((_) async => Decimal.parse("0.00001000"));
+    //
+    //   when(cachedClient.getAnonymitySet(
+    //           groupId: "1", blockhash: "", coin: Coin.firo))
+    //       .thenAnswer((_) async => GetAnonymitySetSampleData.data);
+    //   when(cachedClient.getUsedCoinSerials(startNumber: 0, coin: Coin.firo))
+    //       .thenAnswer(
+    //           (_) async => GetUsedSerialsSampleData.serials['serials'] as List);
+    //
+    //   when(client.getLatestCoinId()).thenAnswer((_) async => 1);
+    //   // when(client.getCoinsForRecovery(setId: 1))
+    //   //     .thenAnswer((_) async => getCoinsForRecoveryResponse);
+    //   when(client.getUsedCoinSerials(startNumber: 0))
+    //       .thenAnswer((_) async => GetUsedSerialsSampleData.serials);
+    //
+    //   // mock price calls
+    //   when(priceAPI.getPricesAnd24hChange(baseCurrency: "USD")).thenAnswer(
+    //       (_) async => {Coin.firo: Tuple2(Decimal.fromInt(10), 1.0)});
+    //
+    //   // mock transaction calls
+    //   when(cachedClient.getTransaction(
+    //     txHash: SampleGetTransactionData.txHash0,
+    //     coin: Coin.firo,
+    //   )).thenAnswer((_) async => SampleGetTransactionData.txData0);
+    //   when(cachedClient.getTransaction(
+    //     txHash: SampleGetTransactionData.txHash1,
+    //     coin: Coin.firo,
+    //   )).thenAnswer((_) async => SampleGetTransactionData.txData1);
+    //   when(cachedClient.getTransaction(
+    //     txHash: SampleGetTransactionData.txHash2,
+    //     coin: Coin.firo,
+    //   )).thenAnswer((_) async => SampleGetTransactionData.txData2);
+    //   when(cachedClient.getTransaction(
+    //     txHash: SampleGetTransactionData.txHash3,
+    //     coin: Coin.firo,
+    //   )).thenAnswer((_) async => SampleGetTransactionData.txData3);
+    //   when(cachedClient.getTransaction(
+    //     txHash: SampleGetTransactionData.txHash4,
+    //     coin: Coin.firo,
+    //   )).thenAnswer((_) async => SampleGetTransactionData.txData4);
+    //   when(cachedClient.getTransaction(
+    //     txHash: SampleGetTransactionData.txHash5,
+    //     coin: Coin.firo,
+    //   )).thenAnswer((_) async => SampleGetTransactionData.txData5);
+    //   when(cachedClient.getTransaction(
+    //     txHash: SampleGetTransactionData.txHash6,
+    //     coin: Coin.firo,
+    //   )).thenAnswer((_) async => SampleGetTransactionData.txData6);
+    //   when(cachedClient.getTransaction(
+    //     txHash: SampleGetTransactionData.txHash7,
+    //     coin: Coin.firo,
+    //   )).thenAnswer((_) async => SampleGetTransactionData.txData7);
+    //   when(cachedClient.getTransaction(
+    //     txHash: SampleGetTransactionData.txHash8,
+    //     coin: Coin.firo,
+    //   )).thenAnswer((_) async => SampleGetTransactionData.txData8);
+    //   when(cachedClient.getTransaction(
+    //     txHash: SampleGetTransactionData.txHash9,
+    //     coin: Coin.firo,
+    //   )).thenAnswer((_) async => SampleGetTransactionData.txData9);
+    //   when(cachedClient.getTransaction(
+    //     txHash: SampleGetTransactionData.txHash10,
+    //     coin: Coin.firo,
+    //   )).thenAnswer((_) async => SampleGetTransactionData.txData10);
+    //   when(cachedClient.getTransaction(
+    //     txHash: SampleGetTransactionData.txHash11,
+    //     coin: Coin.firo,
+    //   )).thenAnswer((_) async => SampleGetTransactionData.txData11);
+    //   when(cachedClient.getTransaction(
+    //     txHash: SampleGetTransactionData.txHash12,
+    //     coin: Coin.firo,
+    //   )).thenAnswer((_) async => SampleGetTransactionData.txData12);
+    //
+    //   final firo = FiroWallet(
+    //     walletName: testWalletName,
+    //     walletId: "${testWalletId}autoMint",
+    //     coin: Coin.firo,
+    //     client: client,
+    //     cachedClient: cachedClient,
+    //     secureStore: secureStore,
+    //     priceAPI: priceAPI,
+    //     tracker: MockTransactionNotificationTracker(),
+    //   );
+    //
+    //   // pre grab derivations in order to set up mock calls needed later on
+    //   await firo.fillAddresses(TEST_MNEMONIC);
+    //   final wallet = await Hive.openBox<dynamic>("${testWalletId}autoMint");
+    //   await wallet.put(
+    //       'receivingAddresses', RefreshTestParams.receivingAddresses);
+    //   await wallet.put('changeAddresses', RefreshTestParams.changeAddresses);
+    //
+    //   final rcv = await secureStore.read(
+    //       key: "${testWalletId}autoMint_receiveDerivations");
+    //   final chg = await secureStore.read(
+    //       key: "${testWalletId}autoMint_changeDerivations");
+    //   final receiveDerivations =
+    //       Map<String, dynamic>.from(jsonDecode(rcv as String) as Map);
+    //   final changeDerivations =
+    //       Map<String, dynamic>.from(jsonDecode(chg as String) as Map);
+    //
+    //   for (int i = 0; i < receiveDerivations.length; i++) {
+    //     final receiveHash = AddressUtils.convertToScriptHash(
+    //         receiveDerivations["$i"]!["address"] as String, firoNetwork);
+    //     final changeHash = AddressUtils.convertToScriptHash(
+    //         changeDerivations["$i"]!["address"] as String, firoNetwork);
+    //     List<Map<String, dynamic>> data;
+    //     switch (receiveHash) {
+    //       case SampleGetHistoryData.scripthash0:
+    //         data = SampleGetHistoryData.data0;
+    //         break;
+    //       case SampleGetHistoryData.scripthash1:
+    //         data = SampleGetHistoryData.data1;
+    //         break;
+    //       case SampleGetHistoryData.scripthash2:
+    //         data = SampleGetHistoryData.data2;
+    //         break;
+    //       case SampleGetHistoryData.scripthash3:
+    //         data = SampleGetHistoryData.data3;
+    //         break;
+    //       default:
+    //         data = [];
+    //     }
+    //     when(client.getHistory(scripthash: receiveHash))
+    //         .thenAnswer((_) async => data);
+    //
+    //     switch (changeHash) {
+    //       case SampleGetHistoryData.scripthash0:
+    //         data = SampleGetHistoryData.data0;
+    //         break;
+    //       case SampleGetHistoryData.scripthash1:
+    //         data = SampleGetHistoryData.data1;
+    //         break;
+    //       case SampleGetHistoryData.scripthash2:
+    //         data = SampleGetHistoryData.data2;
+    //         break;
+    //       case SampleGetHistoryData.scripthash3:
+    //         data = SampleGetHistoryData.data3;
+    //         break;
+    //       default:
+    //         data = [];
+    //     }
+    //
+    //     when(client.getHistory(scripthash: changeHash))
+    //         .thenAnswer((_) async => data);
+    //   }
+    //
+    //   when(client.getUTXOs(scripthash: GetUtxoSampleData.scriptHash0))
+    //       .thenAnswer((_) async => GetUtxoSampleData.utxos0);
+    //   when(client.getUTXOs(scripthash: GetUtxoSampleData.scriptHash1))
+    //       .thenAnswer((_) async => GetUtxoSampleData.utxos1);
+    //
+    //   await firo.recoverFromMnemonic(
+    //       mnemonic: TEST_MNEMONIC,
+    //       maxUnusedAddressGap: 20,
+    //       height: 0,
+    //       maxNumberOfIndexesToCheck: 1000);
+    //
+    //   firo.timer = Timer(const Duration(minutes: 3), () {});
+    //
+    //   await firo.refresh();
+    //
+    //   bool flag = false;
+    //   try {
+    //     await firo.autoMint();
+    //   } catch (_) {
+    //     flag = true;
+    //   }
+    //   expect(flag, false);
+    //
+    //   await firo.exit();
+    // }, timeout: const Timeout(Duration(minutes: 3)));
 
     test("exit", () async {
       final firo = FiroWallet(
diff --git a/test/services/coins/manager_test.mocks.dart b/test/services/coins/manager_test.mocks.dart
index b582f3a88..600707e90 100644
--- a/test/services/coins/manager_test.mocks.dart
+++ b/test/services/coins/manager_test.mocks.dart
@@ -386,11 +386,11 @@ class MockFiroWallet extends _i1.Mock implements _i7.FiroWallet {
       returnValue: Future<void>.value(),
       returnValueForMissingStub: Future<void>.value()) as _i8.Future<void>);
   @override
-  _i8.Future<dynamic> GetCoinsToJoinSplit(int? required) =>
+  _i8.Future<dynamic> getCoinsToJoinSplit(int? required) =>
       (super.noSuchMethod(Invocation.method(#GetCoinsToJoinSplit, [required]),
           returnValue: Future<dynamic>.value()) as _i8.Future<dynamic>);
   @override
-  _i8.Future<int> EstimateJoinSplitFee(int? spendAmount) => (super.noSuchMethod(
+  _i8.Future<int> estimateJoinSplitFee(int? spendAmount) => (super.noSuchMethod(
       Invocation.method(#EstimateJoinSplitFee, [spendAmount]),
       returnValue: Future<int>.value(0)) as _i8.Future<int>);
   @override