From dd0fc6f369139c1e368f3ad519fec7e76af5b8c1 Mon Sep 17 00:00:00 2001
From: julian <julian@cypherstack.com>
Date: Thu, 18 Jan 2024 13:33:50 -0600
Subject: [PATCH 01/57] refactor unnecessary provider watch

---
 .../transaction_views/tx_v2/transaction_v2_list.dart         | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list.dart b/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list.dart
index f47417d99..ac868aee9 100644
--- a/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list.dart
+++ b/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list.dart
@@ -23,6 +23,7 @@ import 'package:stackwallet/providers/db/main_db_provider.dart';
 import 'package:stackwallet/providers/global/wallets_provider.dart';
 import 'package:stackwallet/themes/stack_colors.dart';
 import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
 import 'package:stackwallet/utilities/util.dart';
 import 'package:stackwallet/widgets/loading_indicator.dart';
 
@@ -44,6 +45,7 @@ class _TransactionsV2ListState extends ConsumerState<TransactionsV2List> {
 
   late final StreamSubscription<List<TransactionV2>> _subscription;
   late final Query<TransactionV2> _query;
+  late final Coin coin;
 
   BorderRadius get _borderRadiusFirst {
     return BorderRadius.only(
@@ -69,6 +71,7 @@ class _TransactionsV2ListState extends ConsumerState<TransactionsV2List> {
 
   @override
   void initState() {
+    coin = ref.read(pWallets).getWallet(widget.walletId).info.coin;
     _query = ref
         .read(mainDBProvider)
         .isar
@@ -110,8 +113,6 @@ class _TransactionsV2ListState extends ConsumerState<TransactionsV2List> {
 
   @override
   Widget build(BuildContext context) {
-    final coin = ref.watch(pWallets).getWallet(widget.walletId).info.coin;
-
     return FutureBuilder(
       future: _query.findAll(),
       builder: (fbContext, AsyncSnapshot<List<TransactionV2>> snapshot) {

From fbbd175d0f21b5c94a74ebb4725f0614de10559d Mon Sep 17 00:00:00 2001
From: julian <julian@cypherstack.com>
Date: Thu, 18 Jan 2024 13:34:11 -0600
Subject: [PATCH 02/57] change wording on successful restore

---
 .../sub_widgets/restore_succeeded_dialog.dart                 | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/pages/add_wallet_views/restore_wallet_view/sub_widgets/restore_succeeded_dialog.dart b/lib/pages/add_wallet_views/restore_wallet_view/sub_widgets/restore_succeeded_dialog.dart
index 3963fc139..0b816cbe9 100644
--- a/lib/pages/add_wallet_views/restore_wallet_view/sub_widgets/restore_succeeded_dialog.dart
+++ b/lib/pages/add_wallet_views/restore_wallet_view/sub_widgets/restore_succeeded_dialog.dart
@@ -51,7 +51,7 @@ class RestoreSucceededDialog extends StatelessWidget {
               height: 16,
             ),
             Text(
-              "You can use your wallet now.",
+              "You may access your wallet now.",
               style: STextStyles.desktopTextMedium(context).copyWith(
                 color: Theme.of(context).extension<StackColors>()!.textDark3,
               ),
@@ -80,7 +80,7 @@ class RestoreSucceededDialog extends StatelessWidget {
     } else {
       return StackDialog(
         title: "Wallet restored",
-        message: "You can use your wallet now.",
+        message: "You may access your wallet now.",
         icon: SvgPicture.asset(
           Assets.svg.checkCircle,
           width: 24,

From 755cc049b095bd73e4543c17fa7c693065e5caba Mon Sep 17 00:00:00 2001
From: julian <julian@cypherstack.com>
Date: Thu, 18 Jan 2024 14:02:41 -0600
Subject: [PATCH 03/57] add frostdart dependency

---
 .gitmodules                             | 3 +++
 crypto_plugins/frostdart                | 1 +
 linux/flutter/generated_plugins.cmake   | 1 +
 pubspec.lock                            | 7 +++++++
 pubspec.yaml                            | 3 +++
 scripts/android/build_all.sh            | 6 ++----
 scripts/ios/build_all.sh                | 5 ++---
 scripts/linux/build_all.sh              | 6 ++----
 scripts/macos/build_all.sh              | 2 ++
 scripts/windows/build_all.sh            | 5 ++---
 windows/flutter/generated_plugins.cmake | 1 +
 11 files changed, 26 insertions(+), 14 deletions(-)
 create mode 160000 crypto_plugins/frostdart

diff --git a/.gitmodules b/.gitmodules
index 7474c8a54..98bb17794 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -7,3 +7,6 @@
 [submodule "crypto_plugins/flutter_liblelantus"]
 	path = crypto_plugins/flutter_liblelantus
 	url = https://github.com/cypherstack/flutter_liblelantus.git
+[submodule "crypto_plugins/frostdart"]
+	path = crypto_plugins/frostdart
+	url = https://www.github.com/cypherstack/frostdart
diff --git a/crypto_plugins/frostdart b/crypto_plugins/frostdart
new file mode 160000
index 000000000..2fa7e4666
--- /dev/null
+++ b/crypto_plugins/frostdart
@@ -0,0 +1 @@
+Subproject commit 2fa7e46669a023d270cad4552b5151b138738790
diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake
index bb9965d23..e1af526f4 100644
--- a/linux/flutter/generated_plugins.cmake
+++ b/linux/flutter/generated_plugins.cmake
@@ -17,6 +17,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
 list(APPEND FLUTTER_FFI_PLUGIN_LIST
   coinlib_flutter
   flutter_libsparkmobile
+  frostdart
   tor_ffi_plugin
 )
 
diff --git a/pubspec.lock b/pubspec.lock
index 840efc472..fdb040a28 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -816,6 +816,13 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "3.2.0"
+  frostdart:
+    dependency: "direct main"
+    description:
+      path: "crypto_plugins/frostdart"
+      relative: true
+    source: path
+    version: "0.0.1"
   fuchsia_remote_debug_protocol:
     dependency: transitive
     description: flutter
diff --git a/pubspec.yaml b/pubspec.yaml
index abeb7a821..9a243905b 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -27,6 +27,9 @@ dependencies:
   lelantus:
     path: ./crypto_plugins/flutter_liblelantus
 
+  frostdart:
+    path: ./crypto_plugins/frostdart
+
   flutter_libsparkmobile:
     git:
       url: https://github.com/cypherstack/flutter_libsparkmobile.git
diff --git a/scripts/android/build_all.sh b/scripts/android/build_all.sh
index b67cd92a4..484fb7d03 100755
--- a/scripts/android/build_all.sh
+++ b/scripts/android/build_all.sh
@@ -13,10 +13,8 @@ mkdir -p build
 (cd ../../crypto_plugins/flutter_liblelantus/scripts/android && ./build_all.sh ) &
 (cd ../../crypto_plugins/flutter_libepiccash/scripts/android && ./install_ndk.sh && ./build_all.sh )  &
 (cd ../../crypto_plugins/flutter_libmonero/scripts/android/ && ./build_all.sh  ) &
+set_rust_to_1720 &
+(cd ../../crypto_plugins/frostdart/scripts/android && ./build_all.sh ) &
 
 wait
 echo "Done building"
-
-# set rust (back) to a more recent stable release to allow stack wallet to build tor
-set_rust_to_1720
-
diff --git a/scripts/ios/build_all.sh b/scripts/ios/build_all.sh
index dd6ad38ff..db806c3bb 100755
--- a/scripts/ios/build_all.sh
+++ b/scripts/ios/build_all.sh
@@ -17,13 +17,12 @@ rustup target add x86_64-apple-ios
 (cd ../../crypto_plugins/flutter_liblelantus/scripts/ios && ./build_all.sh ) &
 (cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh )  &
 (cd ../../crypto_plugins/flutter_libmonero/scripts/ios/ && ./build_all.sh  ) &
+set_rust_to_1720 &
+(cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh ) &
 
 wait
 echo "Done building"
 
-# set rust (back) to a more recent stable release to allow stack wallet to build tor
-set_rust_to_1720
-
 # ensure ios rust triples are there
 rustup target add aarch64-apple-ios
 rustup target add x86_64-apple-ios
diff --git a/scripts/linux/build_all.sh b/scripts/linux/build_all.sh
index 672668c13..2b6bd1ffd 100755
--- a/scripts/linux/build_all.sh
+++ b/scripts/linux/build_all.sh
@@ -15,10 +15,8 @@ mkdir -p build
 (cd ../../crypto_plugins/flutter_liblelantus/scripts/linux && ./build_all.sh ) &
 (cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh )  &
 (cd ../../crypto_plugins/flutter_libmonero/scripts/linux && ./build_monero_all.sh && ./build_sharedfile.sh ) &
+set_rust_to_1720 &
+(cd ../../crypto_plugins/frostdart/scripts/linux && ./build_all.sh ) &
 
 wait
 echo "Done building"
-
-# set rust (back) to a more recent stable release to allow stack wallet to build tor
-set_rust_to_1720
-
diff --git a/scripts/macos/build_all.sh b/scripts/macos/build_all.sh
index 0e086fc71..53d6f9bac 100755
--- a/scripts/macos/build_all.sh
+++ b/scripts/macos/build_all.sh
@@ -9,6 +9,8 @@ set_rust_to_1671
 (cd ../../crypto_plugins/flutter_liblelantus/scripts/macos && ./build_all.sh ) &
 (cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh )  &
 (cd ../../crypto_plugins/flutter_libmonero/scripts/macos/ && ./build_all.sh  ) &
+set_rust_to_1720 &
+(cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh ) &
 
 wait
 echo "Done building"
diff --git a/scripts/windows/build_all.sh b/scripts/windows/build_all.sh
index ee3c1b558..1a585e276 100755
--- a/scripts/windows/build_all.sh
+++ b/scripts/windows/build_all.sh
@@ -10,9 +10,8 @@ mkdir -p build
 (cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh )  &
 (cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) &
 (cd ../../crypto_plugins/flutter_libmonero/scripts/windows && ./build_all.sh) &
+set_rust_to_1720 &
+(cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh ) &
 
 wait
 echo "Done building"
-
-# set rust (back) to a more recent stable release to allow stack wallet to build tor
-set_rust_to_1720
diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake
index a774c684a..02d70698f 100644
--- a/windows/flutter/generated_plugins.cmake
+++ b/windows/flutter/generated_plugins.cmake
@@ -18,6 +18,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
 list(APPEND FLUTTER_FFI_PLUGIN_LIST
   coinlib_flutter
   flutter_libsparkmobile
+  frostdart
   tor_ffi_plugin
 )
 

From 85b66fd8493d963c4ee8b9b6514ae5b362df650b Mon Sep 17 00:00:00 2001
From: julian <julian@cypherstack.com>
Date: Thu, 18 Jan 2024 17:47:06 -0600
Subject: [PATCH 04/57] WIP bitcoin frost wallet addition

---
 .../isar/models/blockchain_data/address.dart  |   3 +
 .../models/blockchain_data/address.g.dart     |   2 +
 .../transaction_fee_selection_sheet.dart      |   5 +-
 .../add_edit_node_view.dart                   |   4 +
 .../manage_nodes_views/node_details_view.dart |   2 +
 .../wallet_view/sub_widgets/desktop_send.dart |   4 +-
 lib/services/notifications_service.dart       |   3 +-
 lib/themes/color_theme.dart                   |   2 +
 lib/themes/stack_colors.dart                  |   2 +
 lib/utilities/amount/amount_unit.dart         |   2 +
 lib/utilities/block_explorers.dart            |   2 +
 lib/utilities/constants.dart                  |  14 +
 lib/utilities/default_nodes.dart              |   2 +
 lib/utilities/enums/coin_enum.dart            |  54 +-
 .../enums/derive_path_type_enum.dart          |   2 +
 .../crypto_currency/coins/bitcoin.dart        |  24 +-
 .../crypto_currency/coins/bitcoin_frost.dart  |  65 ++
 .../intermediate/private_key_currency.dart    |   9 +
 .../isar/models/frost_wallet_info.dart        |  38 +
 .../isar/models/frost_wallet_info.g.dart      | 818 ++++++++++++++++++
 lib/wallets/isar/models/wallet_info.g.dart    |   2 +
 .../wallet/impl/bitcoin_frost_wallet.dart     | 475 ++++++++++
 lib/wallets/wallet/wallet.dart                |   6 +
 .../electrumx_interface.dart                  |   9 +-
 lib/widgets/node_card.dart                    |   2 +
 lib/widgets/node_options_sheet.dart           |   2 +
 26 files changed, 1492 insertions(+), 61 deletions(-)
 create mode 100644 lib/wallets/crypto_currency/coins/bitcoin_frost.dart
 create mode 100644 lib/wallets/crypto_currency/intermediate/private_key_currency.dart
 create mode 100644 lib/wallets/isar/models/frost_wallet_info.dart
 create mode 100644 lib/wallets/isar/models/frost_wallet_info.g.dart
 create mode 100644 lib/wallets/wallet/impl/bitcoin_frost_wallet.dart

diff --git a/lib/models/isar/models/blockchain_data/address.dart b/lib/models/isar/models/blockchain_data/address.dart
index e3368a119..8adaa4ce5 100644
--- a/lib/models/isar/models/blockchain_data/address.dart
+++ b/lib/models/isar/models/blockchain_data/address.dart
@@ -163,6 +163,7 @@ enum AddressType {
   spark,
   stellar,
   tezos,
+  frostMS,
   ;
 
   String get readableName {
@@ -193,6 +194,8 @@ enum AddressType {
         return "Stellar";
       case AddressType.tezos:
         return "Tezos";
+      case AddressType.frostMS:
+        return "FrostMS";
     }
   }
 }
diff --git a/lib/models/isar/models/blockchain_data/address.g.dart b/lib/models/isar/models/blockchain_data/address.g.dart
index 796c29f29..7d3aff776 100644
--- a/lib/models/isar/models/blockchain_data/address.g.dart
+++ b/lib/models/isar/models/blockchain_data/address.g.dart
@@ -266,6 +266,7 @@ const _AddresstypeEnumValueMap = {
   'spark': 10,
   'stellar': 11,
   'tezos': 12,
+  'frostMS': 13,
 };
 const _AddresstypeValueEnumMap = {
   0: AddressType.p2pkh,
@@ -281,6 +282,7 @@ const _AddresstypeValueEnumMap = {
   10: AddressType.spark,
   11: AddressType.stellar,
   12: AddressType.tezos,
+  13: AddressType.frostMS,
 };
 
 Id _addressGetId(Address object) {
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 f2178a450..8572d5037 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
@@ -26,6 +26,7 @@ import 'package:stackwallet/utilities/text_styles.dart';
 import 'package:stackwallet/wallets/isar/providers/eth/current_token_wallet_provider.dart';
 import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart';
 import 'package:stackwallet/wallets/wallet/impl/firo_wallet.dart';
+import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart';
 import 'package:stackwallet/widgets/animated_text.dart';
 
 final feeSheetSessionCacheProvider =
@@ -697,7 +698,7 @@ class _TransactionFeeSelectionSheetState
                     const SizedBox(
                       height: 24,
                     ),
-                    if (coin.isElectrumXCoin)
+                    if (wallet is ElectrumXInterface)
                       GestureDetector(
                         onTap: () {
                           final state =
@@ -766,7 +767,7 @@ class _TransactionFeeSelectionSheetState
                           ),
                         ),
                       ),
-                    if (coin.isElectrumXCoin)
+                    if (wallet is ElectrumXInterface)
                       const SizedBox(
                         height: 24,
                       ),
diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
index e03c3ab21..7dc743aab 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
@@ -166,6 +166,8 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
       case Coin.firo:
       case Coin.namecoin:
       case Coin.particl:
+      case Coin.bitcoinFrost:
+      case Coin.bitcoinFrostTestNet:
       case Coin.bitcoinTestNet:
       case Coin.litecoinTestNet:
       case Coin.bitcoincashTestnet:
@@ -757,6 +759,8 @@ class _NodeFormState extends ConsumerState<NodeForm> {
       case Coin.eCash:
       case Coin.stellar:
       case Coin.stellarTestnet:
+      case Coin.bitcoinFrost:
+      case Coin.bitcoinFrostTestNet:
         return false;
 
       case Coin.ethereum:
diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
index 6bf0092e8..3605a2815 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart
@@ -148,6 +148,8 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> {
       case Coin.litecoinTestNet:
       case Coin.bitcoincashTestnet:
       case Coin.eCash:
+      case Coin.bitcoinFrost:
+      case Coin.bitcoinFrostTestNet:
         final client = ElectrumXClient(
           host: node!.host,
           port: node.port,
diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart
index 90c5ae041..160de0367 100644
--- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart
+++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart
@@ -52,6 +52,7 @@ import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart';
 import 'package:stackwallet/wallets/models/tx_data.dart';
 import 'package:stackwallet/wallets/wallet/impl/firo_wallet.dart';
 import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart';
+import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart';
 import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/paynym_interface.dart';
 import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart';
 import 'package:stackwallet/widgets/animated_text.dart';
@@ -1566,7 +1567,8 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
         if (!([Coin.nano, Coin.banano, Coin.epicCash, Coin.tezos]
             .contains(coin)))
           ConditionalParent(
-            condition: coin.isElectrumXCoin &&
+            condition: ref.watch(pWallets).getWallet(walletId)
+                    is ElectrumXInterface &&
                 !(((coin == Coin.firo || coin == Coin.firoTestNet) &&
                     (ref.watch(publicPrivateBalanceStateProvider.state).state ==
                             FiroType.lelantus ||
diff --git a/lib/services/notifications_service.dart b/lib/services/notifications_service.dart
index 1512c12c6..c019768fc 100644
--- a/lib/services/notifications_service.dart
+++ b/lib/services/notifications_service.dart
@@ -24,6 +24,7 @@ import 'package:stackwallet/services/wallets.dart';
 import 'package:stackwallet/utilities/enums/coin_enum.dart';
 import 'package:stackwallet/utilities/logger.dart';
 import 'package:stackwallet/utilities/prefs.dart';
+import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart';
 
 import 'exchange/exchange.dart';
 
@@ -123,7 +124,7 @@ class NotificationsService extends ChangeNotifier {
 
         final node = nodeService.getPrimaryNodeFor(coin: coin);
         if (node != null) {
-          if (coin.isElectrumXCoin) {
+          if (wallet is ElectrumXInterface) {
             final eNode = ElectrumXNode(
               address: node.host,
               port: node.port,
diff --git a/lib/themes/color_theme.dart b/lib/themes/color_theme.dart
index abec28d4e..38de6c636 100644
--- a/lib/themes/color_theme.dart
+++ b/lib/themes/color_theme.dart
@@ -37,6 +37,8 @@ class CoinThemeColorDefault {
     switch (coin) {
       case Coin.bitcoin:
       case Coin.bitcoinTestNet:
+      case Coin.bitcoinFrost:
+      case Coin.bitcoinFrostTestNet:
         return bitcoin;
       case Coin.litecoin:
       case Coin.litecoinTestNet:
diff --git a/lib/themes/stack_colors.dart b/lib/themes/stack_colors.dart
index cbec0077a..0cc83b04f 100644
--- a/lib/themes/stack_colors.dart
+++ b/lib/themes/stack_colors.dart
@@ -1680,6 +1680,8 @@ class StackColors extends ThemeExtension<StackColors> {
     switch (coin) {
       case Coin.bitcoin:
       case Coin.bitcoinTestNet:
+      case Coin.bitcoinFrost:
+      case Coin.bitcoinFrostTestNet:
         return _coin.bitcoin;
       case Coin.litecoin:
       case Coin.litecoinTestNet:
diff --git a/lib/utilities/amount/amount_unit.dart b/lib/utilities/amount/amount_unit.dart
index 6a646fd11..87efcc4cd 100644
--- a/lib/utilities/amount/amount_unit.dart
+++ b/lib/utilities/amount/amount_unit.dart
@@ -40,6 +40,8 @@ enum AmountUnit {
       case Coin.litecoin:
       case Coin.particl:
       case Coin.namecoin:
+      case Coin.bitcoinFrost:
+      case Coin.bitcoinFrostTestNet:
       case Coin.bitcoinTestNet:
       case Coin.litecoinTestNet:
       case Coin.bitcoincashTestnet:
diff --git a/lib/utilities/block_explorers.dart b/lib/utilities/block_explorers.dart
index bb4ac06fb..9f3e92c5d 100644
--- a/lib/utilities/block_explorers.dart
+++ b/lib/utilities/block_explorers.dart
@@ -18,6 +18,7 @@ Uri getDefaultBlockExplorerUrlFor({
   required String txid,
 }) {
   switch (coin) {
+    case Coin.bitcoinFrost:
     case Coin.bitcoin:
       return Uri.parse("https://mempool.space/tx/$txid");
     case Coin.litecoin:
@@ -25,6 +26,7 @@ Uri getDefaultBlockExplorerUrlFor({
     case Coin.litecoinTestNet:
       return Uri.parse("https://chain.so/tx/LTCTEST/$txid");
     case Coin.bitcoinTestNet:
+    case Coin.bitcoinFrostTestNet:
       return Uri.parse("https://mempool.space/testnet/tx/$txid");
     case Coin.dogecoin:
       return Uri.parse("https://chain.so/tx/DOGE/$txid");
diff --git a/lib/utilities/constants.dart b/lib/utilities/constants.dart
index db0543044..f7a6faeb2 100644
--- a/lib/utilities/constants.dart
+++ b/lib/utilities/constants.dart
@@ -69,6 +69,7 @@ abstract class Constants {
   static BigInt satsPerCoin(Coin coin) {
     switch (coin) {
       case Coin.bitcoin:
+      case Coin.bitcoinFrost:
       case Coin.litecoin:
       case Coin.litecoinTestNet:
       case Coin.bitcoincash:
@@ -76,6 +77,7 @@ abstract class Constants {
       case Coin.dogecoin:
       case Coin.firo:
       case Coin.bitcoinTestNet:
+      case Coin.bitcoinFrostTestNet:
       case Coin.dogecoinTestNet:
       case Coin.firoTestNet:
       case Coin.epicCash:
@@ -113,6 +115,7 @@ abstract class Constants {
   static int decimalPlacesForCoin(Coin coin) {
     switch (coin) {
       case Coin.bitcoin:
+      case Coin.bitcoinFrost:
       case Coin.litecoin:
       case Coin.litecoinTestNet:
       case Coin.bitcoincash:
@@ -120,6 +123,7 @@ abstract class Constants {
       case Coin.dogecoin:
       case Coin.firo:
       case Coin.bitcoinTestNet:
+      case Coin.bitcoinFrostTestNet:
       case Coin.dogecoinTestNet:
       case Coin.firoTestNet:
       case Coin.epicCash:
@@ -189,6 +193,10 @@ abstract class Constants {
       case Coin.wownero:
         values.addAll([14, 25]);
         break;
+
+      case Coin.bitcoinFrost:
+      case Coin.bitcoinFrostTestNet:
+        throw ArgumentError("Frost mnemonic lengths unsupported");
     }
     return values;
   }
@@ -198,6 +206,8 @@ abstract class Constants {
     switch (coin) {
       case Coin.bitcoin:
       case Coin.bitcoinTestNet:
+      case Coin.bitcoinFrost:
+      case Coin.bitcoinFrostTestNet:
       case Coin.bitcoincash:
       case Coin.bitcoincashTestnet:
       case Coin.eCash:
@@ -277,6 +287,10 @@ abstract class Constants {
 
       case Coin.monero:
         return 25;
+
+      case Coin.bitcoinFrost:
+      case Coin.bitcoinFrostTestNet:
+        throw ArgumentError("Frost mnemonic length unsupported");
       //
       // default:
       //   -1;
diff --git a/lib/utilities/default_nodes.dart b/lib/utilities/default_nodes.dart
index 5d80784a3..b8f296b68 100644
--- a/lib/utilities/default_nodes.dart
+++ b/lib/utilities/default_nodes.dart
@@ -312,6 +312,7 @@ abstract class DefaultNodes {
   static NodeModel getNodeFor(Coin coin) {
     switch (coin) {
       case Coin.bitcoin:
+      case Coin.bitcoinFrost:
         return bitcoin;
 
       case Coin.litecoin:
@@ -360,6 +361,7 @@ abstract class DefaultNodes {
         return tezos;
 
       case Coin.bitcoinTestNet:
+      case Coin.bitcoinFrostTestNet:
         return bitcoinTestnet;
 
       case Coin.litecoinTestNet:
diff --git a/lib/utilities/enums/coin_enum.dart b/lib/utilities/enums/coin_enum.dart
index c71d39ba4..305183448 100644
--- a/lib/utilities/enums/coin_enum.dart
+++ b/lib/utilities/enums/coin_enum.dart
@@ -13,6 +13,7 @@ import 'package:stackwallet/utilities/constants.dart';
 
 enum Coin {
   bitcoin,
+  bitcoinFrost,
   monero,
   banano,
   bitcoincash,
@@ -35,6 +36,7 @@ enum Coin {
   ///
 
   bitcoinTestNet,
+  bitcoinFrostTestNet,
   bitcoincashTestnet,
   dogecoinTestNet,
   firoTestNet,
@@ -47,6 +49,8 @@ extension CoinExt on Coin {
     switch (this) {
       case Coin.bitcoin:
         return "Bitcoin";
+      case Coin.bitcoinFrost:
+        return "Bitcoin Frost";
       case Coin.litecoin:
         return "Litecoin";
       case Coin.bitcoincash:
@@ -79,6 +83,8 @@ extension CoinExt on Coin {
         return "Banano";
       case Coin.bitcoinTestNet:
         return "tBitcoin";
+      case Coin.bitcoinFrostTestNet:
+        return "tBitcoin Frost";
       case Coin.litecoinTestNet:
         return "tLitecoin";
       case Coin.bitcoincashTestnet:
@@ -95,6 +101,7 @@ extension CoinExt on Coin {
   String get ticker {
     switch (this) {
       case Coin.bitcoin:
+      case Coin.bitcoinFrost:
         return "BTC";
       case Coin.litecoin:
         return "LTC";
@@ -127,6 +134,7 @@ extension CoinExt on Coin {
       case Coin.banano:
         return "BAN";
       case Coin.bitcoinTestNet:
+      case Coin.bitcoinFrostTestNet:
         return "tBTC";
       case Coin.litecoinTestNet:
         return "tLTC";
@@ -144,6 +152,7 @@ extension CoinExt on Coin {
   String get uriScheme {
     switch (this) {
       case Coin.bitcoin:
+      case Coin.bitcoinFrost:
         return "bitcoin";
       case Coin.litecoin:
         return "litecoin";
@@ -177,6 +186,7 @@ extension CoinExt on Coin {
       case Coin.banano:
         return "ban";
       case Coin.bitcoinTestNet:
+      case Coin.bitcoinFrostTestNet:
         return "bitcoin";
       case Coin.litecoinTestNet:
         return "litecoin";
@@ -191,36 +201,6 @@ extension CoinExt on Coin {
     }
   }
 
-  bool get isElectrumXCoin {
-    switch (this) {
-      case Coin.bitcoin:
-      case Coin.litecoin:
-      case Coin.bitcoincash:
-      case Coin.dogecoin:
-      case Coin.firo:
-      case Coin.namecoin:
-      case Coin.particl:
-      case Coin.bitcoinTestNet:
-      case Coin.litecoinTestNet:
-      case Coin.bitcoincashTestnet:
-      case Coin.firoTestNet:
-      case Coin.dogecoinTestNet:
-      case Coin.eCash:
-        return true;
-
-      case Coin.epicCash:
-      case Coin.ethereum:
-      case Coin.monero:
-      case Coin.tezos:
-      case Coin.wownero:
-      case Coin.nano:
-      case Coin.banano:
-      case Coin.stellar:
-      case Coin.stellarTestnet:
-        return false;
-    }
-  }
-
   bool get hasMnemonicPassphraseSupport {
     switch (this) {
       case Coin.bitcoin:
@@ -241,6 +221,8 @@ extension CoinExt on Coin {
       case Coin.stellarTestnet:
         return true;
 
+      case Coin.bitcoinFrost:
+      case Coin.bitcoinFrostTestNet:
       case Coin.epicCash:
       case Coin.monero:
       case Coin.wownero:
@@ -260,6 +242,8 @@ extension CoinExt on Coin {
       case Coin.ethereum:
         return true;
 
+      case Coin.bitcoinFrost:
+      case Coin.bitcoinFrostTestNet:
       case Coin.firo:
       case Coin.namecoin:
       case Coin.particl:
@@ -284,6 +268,7 @@ extension CoinExt on Coin {
   bool get isTestNet {
     switch (this) {
       case Coin.bitcoin:
+      case Coin.bitcoinFrost:
       case Coin.litecoin:
       case Coin.bitcoincash:
       case Coin.dogecoin:
@@ -303,6 +288,7 @@ extension CoinExt on Coin {
 
       case Coin.dogecoinTestNet:
       case Coin.bitcoinTestNet:
+      case Coin.bitcoinFrostTestNet:
       case Coin.litecoinTestNet:
       case Coin.bitcoincashTestnet:
       case Coin.firoTestNet:
@@ -314,6 +300,7 @@ extension CoinExt on Coin {
   Coin get mainNetVersion {
     switch (this) {
       case Coin.bitcoin:
+      case Coin.bitcoinFrost:
       case Coin.litecoin:
       case Coin.bitcoincash:
       case Coin.dogecoin:
@@ -337,6 +324,9 @@ extension CoinExt on Coin {
       case Coin.bitcoinTestNet:
         return Coin.bitcoin;
 
+      case Coin.bitcoinFrostTestNet:
+        return Coin.bitcoinFrost;
+
       case Coin.litecoinTestNet:
         return Coin.litecoin;
 
@@ -364,6 +354,10 @@ extension CoinExt on Coin {
       case Coin.particl:
         return AddressType.p2wpkh;
 
+      case Coin.bitcoinFrost:
+      case Coin.bitcoinFrostTestNet:
+        return AddressType.frostMS;
+
       case Coin.eCash:
       case Coin.bitcoincash:
       case Coin.bitcoincashTestnet:
diff --git a/lib/utilities/enums/derive_path_type_enum.dart b/lib/utilities/enums/derive_path_type_enum.dart
index 5b94f41f6..6d2371735 100644
--- a/lib/utilities/enums/derive_path_type_enum.dart
+++ b/lib/utilities/enums/derive_path_type_enum.dart
@@ -44,6 +44,8 @@ extension DerivePathTypeExt on DerivePathType {
       case Coin.ethereum: // TODO: do we need something here?
         return DerivePathType.eth;
 
+      case Coin.bitcoinFrost:
+      case Coin.bitcoinFrostTestNet:
       case Coin.epicCash:
       case Coin.monero:
       case Coin.wownero:
diff --git a/lib/wallets/crypto_currency/coins/bitcoin.dart b/lib/wallets/crypto_currency/coins/bitcoin.dart
index 2402a977f..d441961a7 100644
--- a/lib/wallets/crypto_currency/coins/bitcoin.dart
+++ b/lib/wallets/crypto_currency/coins/bitcoin.dart
@@ -170,30 +170,10 @@ class Bitcoin extends Bip39HDCurrency with PaynymCurrencyInterface {
   NodeModel get defaultNode {
     switch (network) {
       case CryptoCurrencyNetwork.main:
-        return NodeModel(
-          host: "bitcoin.stackwallet.com",
-          port: 50002,
-          name: DefaultNodes.defaultName,
-          id: DefaultNodes.buildId(Coin.bitcoin),
-          useSSL: true,
-          enabled: true,
-          coinName: Coin.bitcoin.name,
-          isFailover: true,
-          isDown: false,
-        );
+        return DefaultNodes.bitcoin;
 
       case CryptoCurrencyNetwork.test:
-        return NodeModel(
-          host: "bitcoin-testnet.stackwallet.com",
-          port: 51002,
-          name: DefaultNodes.defaultName,
-          id: DefaultNodes.buildId(Coin.bitcoinTestNet),
-          useSSL: true,
-          enabled: true,
-          coinName: Coin.bitcoinTestNet.name,
-          isFailover: true,
-          isDown: false,
-        );
+        return DefaultNodes.bitcoinTestnet;
 
       default:
         throw UnimplementedError();
diff --git a/lib/wallets/crypto_currency/coins/bitcoin_frost.dart b/lib/wallets/crypto_currency/coins/bitcoin_frost.dart
new file mode 100644
index 000000000..f968818e1
--- /dev/null
+++ b/lib/wallets/crypto_currency/coins/bitcoin_frost.dart
@@ -0,0 +1,65 @@
+import 'dart:typed_data';
+
+import 'package:stackwallet/models/node_model.dart';
+import 'package:stackwallet/utilities/default_nodes.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
+import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
+import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_hd_currency.dart';
+import 'package:stackwallet/wallets/crypto_currency/intermediate/private_key_currency.dart';
+
+class BitcoinFrost extends FrostCurrency {
+  BitcoinFrost(super.network) {
+    switch (network) {
+      case CryptoCurrencyNetwork.main:
+        coin = Coin.bitcoin;
+      case CryptoCurrencyNetwork.test:
+        coin = Coin.bitcoinTestNet;
+      default:
+        throw Exception("Unsupported network: $network");
+    }
+  }
+
+  @override
+  int get minConfirms => 1;
+
+  @override
+  NodeModel get defaultNode {
+    switch (network) {
+      case CryptoCurrencyNetwork.main:
+        return DefaultNodes.bitcoin;
+
+      case CryptoCurrencyNetwork.test:
+        return DefaultNodes.bitcoinTestnet;
+
+      default:
+        throw UnimplementedError();
+    }
+  }
+
+  @override
+  String get genesisHash {
+    switch (network) {
+      case CryptoCurrencyNetwork.main:
+        return "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f";
+      case CryptoCurrencyNetwork.test:
+        return "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943";
+      default:
+        throw Exception("Unsupported network: $network");
+    }
+  }
+
+  @override
+  String pubKeyToScriptHash({required Uint8List pubKey}) {
+    try {
+      return Bip39HDCurrency.convertBytesToScriptHash(pubKey);
+    } catch (e) {
+      rethrow;
+    }
+  }
+
+  @override
+  bool validateAddress(String address) {
+    // TODO: implement validateAddress for frost addresses
+    return true;
+  }
+}
diff --git a/lib/wallets/crypto_currency/intermediate/private_key_currency.dart b/lib/wallets/crypto_currency/intermediate/private_key_currency.dart
new file mode 100644
index 000000000..8cbf11b27
--- /dev/null
+++ b/lib/wallets/crypto_currency/intermediate/private_key_currency.dart
@@ -0,0 +1,9 @@
+import 'dart:typed_data';
+
+import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
+
+abstract class FrostCurrency extends CryptoCurrency {
+  FrostCurrency(super.network);
+
+  String pubKeyToScriptHash({required Uint8List pubKey});
+}
diff --git a/lib/wallets/isar/models/frost_wallet_info.dart b/lib/wallets/isar/models/frost_wallet_info.dart
new file mode 100644
index 000000000..817f78f39
--- /dev/null
+++ b/lib/wallets/isar/models/frost_wallet_info.dart
@@ -0,0 +1,38 @@
+import 'package:isar/isar.dart';
+import 'package:stackwallet/wallets/isar/isar_id_interface.dart';
+
+part 'frost_wallet_info.g.dart';
+
+@Collection(accessor: "frostWalletInfo", inheritance: false)
+class FrostWalletInfo implements IsarId {
+  @override
+  Id id = Isar.autoIncrement;
+
+  @Index(unique: true, replace: false)
+  final String walletId;
+
+  final List<String> knownSalts;
+
+  FrostWalletInfo({
+    required this.walletId,
+    required this.knownSalts,
+  });
+
+  FrostWalletInfo copyWith({
+    List<String>? knownSalts,
+  }) {
+    return FrostWalletInfo(
+      walletId: walletId,
+      knownSalts: knownSalts ?? this.knownSalts,
+    );
+  }
+
+  Future<void> updateKnownSalts(
+    List<String> knownSalts, {
+    required Isar isar,
+  }) async {
+    // await isar.writeTxn(() async {
+    //   await isar.
+    // })
+  }
+}
diff --git a/lib/wallets/isar/models/frost_wallet_info.g.dart b/lib/wallets/isar/models/frost_wallet_info.g.dart
new file mode 100644
index 000000000..ce5ae2aae
--- /dev/null
+++ b/lib/wallets/isar/models/frost_wallet_info.g.dart
@@ -0,0 +1,818 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'frost_wallet_info.dart';
+
+// **************************************************************************
+// IsarCollectionGenerator
+// **************************************************************************
+
+// coverage:ignore-file
+// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters
+
+extension GetFrostWalletInfoCollection on Isar {
+  IsarCollection<FrostWalletInfo> get frostWalletInfo => this.collection();
+}
+
+const FrostWalletInfoSchema = CollectionSchema(
+  name: r'FrostWalletInfo',
+  id: -4182879703273806681,
+  properties: {
+    r'knownSalts': PropertySchema(
+      id: 0,
+      name: r'knownSalts',
+      type: IsarType.stringList,
+    ),
+    r'walletId': PropertySchema(
+      id: 1,
+      name: r'walletId',
+      type: IsarType.string,
+    )
+  },
+  estimateSize: _frostWalletInfoEstimateSize,
+  serialize: _frostWalletInfoSerialize,
+  deserialize: _frostWalletInfoDeserialize,
+  deserializeProp: _frostWalletInfoDeserializeProp,
+  idName: r'id',
+  indexes: {
+    r'walletId': IndexSchema(
+      id: -1783113319798776304,
+      name: r'walletId',
+      unique: true,
+      replace: false,
+      properties: [
+        IndexPropertySchema(
+          name: r'walletId',
+          type: IndexType.hash,
+          caseSensitive: true,
+        )
+      ],
+    )
+  },
+  links: {},
+  embeddedSchemas: {},
+  getId: _frostWalletInfoGetId,
+  getLinks: _frostWalletInfoGetLinks,
+  attach: _frostWalletInfoAttach,
+  version: '3.0.5',
+);
+
+int _frostWalletInfoEstimateSize(
+  FrostWalletInfo object,
+  List<int> offsets,
+  Map<Type, List<int>> allOffsets,
+) {
+  var bytesCount = offsets.last;
+  bytesCount += 3 + object.knownSalts.length * 3;
+  {
+    for (var i = 0; i < object.knownSalts.length; i++) {
+      final value = object.knownSalts[i];
+      bytesCount += value.length * 3;
+    }
+  }
+  bytesCount += 3 + object.walletId.length * 3;
+  return bytesCount;
+}
+
+void _frostWalletInfoSerialize(
+  FrostWalletInfo object,
+  IsarWriter writer,
+  List<int> offsets,
+  Map<Type, List<int>> allOffsets,
+) {
+  writer.writeStringList(offsets[0], object.knownSalts);
+  writer.writeString(offsets[1], object.walletId);
+}
+
+FrostWalletInfo _frostWalletInfoDeserialize(
+  Id id,
+  IsarReader reader,
+  List<int> offsets,
+  Map<Type, List<int>> allOffsets,
+) {
+  final object = FrostWalletInfo(
+    knownSalts: reader.readStringList(offsets[0]) ?? [],
+    walletId: reader.readString(offsets[1]),
+  );
+  object.id = id;
+  return object;
+}
+
+P _frostWalletInfoDeserializeProp<P>(
+  IsarReader reader,
+  int propertyId,
+  int offset,
+  Map<Type, List<int>> allOffsets,
+) {
+  switch (propertyId) {
+    case 0:
+      return (reader.readStringList(offset) ?? []) as P;
+    case 1:
+      return (reader.readString(offset)) as P;
+    default:
+      throw IsarError('Unknown property with id $propertyId');
+  }
+}
+
+Id _frostWalletInfoGetId(FrostWalletInfo object) {
+  return object.id;
+}
+
+List<IsarLinkBase<dynamic>> _frostWalletInfoGetLinks(FrostWalletInfo object) {
+  return [];
+}
+
+void _frostWalletInfoAttach(
+    IsarCollection<dynamic> col, Id id, FrostWalletInfo object) {
+  object.id = id;
+}
+
+extension FrostWalletInfoByIndex on IsarCollection<FrostWalletInfo> {
+  Future<FrostWalletInfo?> getByWalletId(String walletId) {
+    return getByIndex(r'walletId', [walletId]);
+  }
+
+  FrostWalletInfo? getByWalletIdSync(String walletId) {
+    return getByIndexSync(r'walletId', [walletId]);
+  }
+
+  Future<bool> deleteByWalletId(String walletId) {
+    return deleteByIndex(r'walletId', [walletId]);
+  }
+
+  bool deleteByWalletIdSync(String walletId) {
+    return deleteByIndexSync(r'walletId', [walletId]);
+  }
+
+  Future<List<FrostWalletInfo?>> getAllByWalletId(List<String> walletIdValues) {
+    final values = walletIdValues.map((e) => [e]).toList();
+    return getAllByIndex(r'walletId', values);
+  }
+
+  List<FrostWalletInfo?> getAllByWalletIdSync(List<String> walletIdValues) {
+    final values = walletIdValues.map((e) => [e]).toList();
+    return getAllByIndexSync(r'walletId', values);
+  }
+
+  Future<int> deleteAllByWalletId(List<String> walletIdValues) {
+    final values = walletIdValues.map((e) => [e]).toList();
+    return deleteAllByIndex(r'walletId', values);
+  }
+
+  int deleteAllByWalletIdSync(List<String> walletIdValues) {
+    final values = walletIdValues.map((e) => [e]).toList();
+    return deleteAllByIndexSync(r'walletId', values);
+  }
+
+  Future<Id> putByWalletId(FrostWalletInfo object) {
+    return putByIndex(r'walletId', object);
+  }
+
+  Id putByWalletIdSync(FrostWalletInfo object, {bool saveLinks = true}) {
+    return putByIndexSync(r'walletId', object, saveLinks: saveLinks);
+  }
+
+  Future<List<Id>> putAllByWalletId(List<FrostWalletInfo> objects) {
+    return putAllByIndex(r'walletId', objects);
+  }
+
+  List<Id> putAllByWalletIdSync(List<FrostWalletInfo> objects,
+      {bool saveLinks = true}) {
+    return putAllByIndexSync(r'walletId', objects, saveLinks: saveLinks);
+  }
+}
+
+extension FrostWalletInfoQueryWhereSort
+    on QueryBuilder<FrostWalletInfo, FrostWalletInfo, QWhere> {
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterWhere> anyId() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addWhereClause(const IdWhereClause.any());
+    });
+  }
+}
+
+extension FrostWalletInfoQueryWhere
+    on QueryBuilder<FrostWalletInfo, FrostWalletInfo, QWhereClause> {
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterWhereClause> idEqualTo(
+      Id id) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addWhereClause(IdWhereClause.between(
+        lower: id,
+        upper: id,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterWhereClause>
+      idNotEqualTo(Id id) {
+    return QueryBuilder.apply(this, (query) {
+      if (query.whereSort == Sort.asc) {
+        return query
+            .addWhereClause(
+              IdWhereClause.lessThan(upper: id, includeUpper: false),
+            )
+            .addWhereClause(
+              IdWhereClause.greaterThan(lower: id, includeLower: false),
+            );
+      } else {
+        return query
+            .addWhereClause(
+              IdWhereClause.greaterThan(lower: id, includeLower: false),
+            )
+            .addWhereClause(
+              IdWhereClause.lessThan(upper: id, includeUpper: false),
+            );
+      }
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterWhereClause>
+      idGreaterThan(Id id, {bool include = false}) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addWhereClause(
+        IdWhereClause.greaterThan(lower: id, includeLower: include),
+      );
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterWhereClause> idLessThan(
+      Id id,
+      {bool include = false}) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addWhereClause(
+        IdWhereClause.lessThan(upper: id, includeUpper: include),
+      );
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterWhereClause> idBetween(
+    Id lowerId,
+    Id upperId, {
+    bool includeLower = true,
+    bool includeUpper = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addWhereClause(IdWhereClause.between(
+        lower: lowerId,
+        includeLower: includeLower,
+        upper: upperId,
+        includeUpper: includeUpper,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterWhereClause>
+      walletIdEqualTo(String walletId) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addWhereClause(IndexWhereClause.equalTo(
+        indexName: r'walletId',
+        value: [walletId],
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterWhereClause>
+      walletIdNotEqualTo(String walletId) {
+    return QueryBuilder.apply(this, (query) {
+      if (query.whereSort == Sort.asc) {
+        return query
+            .addWhereClause(IndexWhereClause.between(
+              indexName: r'walletId',
+              lower: [],
+              upper: [walletId],
+              includeUpper: false,
+            ))
+            .addWhereClause(IndexWhereClause.between(
+              indexName: r'walletId',
+              lower: [walletId],
+              includeLower: false,
+              upper: [],
+            ));
+      } else {
+        return query
+            .addWhereClause(IndexWhereClause.between(
+              indexName: r'walletId',
+              lower: [walletId],
+              includeLower: false,
+              upper: [],
+            ))
+            .addWhereClause(IndexWhereClause.between(
+              indexName: r'walletId',
+              lower: [],
+              upper: [walletId],
+              includeUpper: false,
+            ));
+      }
+    });
+  }
+}
+
+extension FrostWalletInfoQueryFilter
+    on QueryBuilder<FrostWalletInfo, FrostWalletInfo, QFilterCondition> {
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      idEqualTo(Id value) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.equalTo(
+        property: r'id',
+        value: value,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      idGreaterThan(
+    Id value, {
+    bool include = false,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.greaterThan(
+        include: include,
+        property: r'id',
+        value: value,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      idLessThan(
+    Id value, {
+    bool include = false,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.lessThan(
+        include: include,
+        property: r'id',
+        value: value,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      idBetween(
+    Id lower,
+    Id upper, {
+    bool includeLower = true,
+    bool includeUpper = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.between(
+        property: r'id',
+        lower: lower,
+        includeLower: includeLower,
+        upper: upper,
+        includeUpper: includeUpper,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      knownSaltsElementEqualTo(
+    String value, {
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.equalTo(
+        property: r'knownSalts',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      knownSaltsElementGreaterThan(
+    String value, {
+    bool include = false,
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.greaterThan(
+        include: include,
+        property: r'knownSalts',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      knownSaltsElementLessThan(
+    String value, {
+    bool include = false,
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.lessThan(
+        include: include,
+        property: r'knownSalts',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      knownSaltsElementBetween(
+    String lower,
+    String upper, {
+    bool includeLower = true,
+    bool includeUpper = true,
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.between(
+        property: r'knownSalts',
+        lower: lower,
+        includeLower: includeLower,
+        upper: upper,
+        includeUpper: includeUpper,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      knownSaltsElementStartsWith(
+    String value, {
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.startsWith(
+        property: r'knownSalts',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      knownSaltsElementEndsWith(
+    String value, {
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.endsWith(
+        property: r'knownSalts',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      knownSaltsElementContains(String value, {bool caseSensitive = true}) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.contains(
+        property: r'knownSalts',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      knownSaltsElementMatches(String pattern, {bool caseSensitive = true}) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.matches(
+        property: r'knownSalts',
+        wildcard: pattern,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      knownSaltsElementIsEmpty() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.equalTo(
+        property: r'knownSalts',
+        value: '',
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      knownSaltsElementIsNotEmpty() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.greaterThan(
+        property: r'knownSalts',
+        value: '',
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      knownSaltsLengthEqualTo(int length) {
+    return QueryBuilder.apply(this, (query) {
+      return query.listLength(
+        r'knownSalts',
+        length,
+        true,
+        length,
+        true,
+      );
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      knownSaltsIsEmpty() {
+    return QueryBuilder.apply(this, (query) {
+      return query.listLength(
+        r'knownSalts',
+        0,
+        true,
+        0,
+        true,
+      );
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      knownSaltsIsNotEmpty() {
+    return QueryBuilder.apply(this, (query) {
+      return query.listLength(
+        r'knownSalts',
+        0,
+        false,
+        999999,
+        true,
+      );
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      knownSaltsLengthLessThan(
+    int length, {
+    bool include = false,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.listLength(
+        r'knownSalts',
+        0,
+        true,
+        length,
+        include,
+      );
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      knownSaltsLengthGreaterThan(
+    int length, {
+    bool include = false,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.listLength(
+        r'knownSalts',
+        length,
+        include,
+        999999,
+        true,
+      );
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      knownSaltsLengthBetween(
+    int lower,
+    int upper, {
+    bool includeLower = true,
+    bool includeUpper = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.listLength(
+        r'knownSalts',
+        lower,
+        includeLower,
+        upper,
+        includeUpper,
+      );
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      walletIdEqualTo(
+    String value, {
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.equalTo(
+        property: r'walletId',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      walletIdGreaterThan(
+    String value, {
+    bool include = false,
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.greaterThan(
+        include: include,
+        property: r'walletId',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      walletIdLessThan(
+    String value, {
+    bool include = false,
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.lessThan(
+        include: include,
+        property: r'walletId',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      walletIdBetween(
+    String lower,
+    String upper, {
+    bool includeLower = true,
+    bool includeUpper = true,
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.between(
+        property: r'walletId',
+        lower: lower,
+        includeLower: includeLower,
+        upper: upper,
+        includeUpper: includeUpper,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      walletIdStartsWith(
+    String value, {
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.startsWith(
+        property: r'walletId',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      walletIdEndsWith(
+    String value, {
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.endsWith(
+        property: r'walletId',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      walletIdContains(String value, {bool caseSensitive = true}) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.contains(
+        property: r'walletId',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      walletIdMatches(String pattern, {bool caseSensitive = true}) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.matches(
+        property: r'walletId',
+        wildcard: pattern,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      walletIdIsEmpty() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.equalTo(
+        property: r'walletId',
+        value: '',
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      walletIdIsNotEmpty() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.greaterThan(
+        property: r'walletId',
+        value: '',
+      ));
+    });
+  }
+}
+
+extension FrostWalletInfoQueryObject
+    on QueryBuilder<FrostWalletInfo, FrostWalletInfo, QFilterCondition> {}
+
+extension FrostWalletInfoQueryLinks
+    on QueryBuilder<FrostWalletInfo, FrostWalletInfo, QFilterCondition> {}
+
+extension FrostWalletInfoQuerySortBy
+    on QueryBuilder<FrostWalletInfo, FrostWalletInfo, QSortBy> {
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy>
+      sortByWalletId() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addSortBy(r'walletId', Sort.asc);
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy>
+      sortByWalletIdDesc() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addSortBy(r'walletId', Sort.desc);
+    });
+  }
+}
+
+extension FrostWalletInfoQuerySortThenBy
+    on QueryBuilder<FrostWalletInfo, FrostWalletInfo, QSortThenBy> {
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy> thenById() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addSortBy(r'id', Sort.asc);
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy> thenByIdDesc() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addSortBy(r'id', Sort.desc);
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy>
+      thenByWalletId() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addSortBy(r'walletId', Sort.asc);
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy>
+      thenByWalletIdDesc() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addSortBy(r'walletId', Sort.desc);
+    });
+  }
+}
+
+extension FrostWalletInfoQueryWhereDistinct
+    on QueryBuilder<FrostWalletInfo, FrostWalletInfo, QDistinct> {
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QDistinct>
+      distinctByKnownSalts() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addDistinctBy(r'knownSalts');
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QDistinct> distinctByWalletId(
+      {bool caseSensitive = true}) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addDistinctBy(r'walletId', caseSensitive: caseSensitive);
+    });
+  }
+}
+
+extension FrostWalletInfoQueryProperty
+    on QueryBuilder<FrostWalletInfo, FrostWalletInfo, QQueryProperty> {
+  QueryBuilder<FrostWalletInfo, int, QQueryOperations> idProperty() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addPropertyName(r'id');
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, List<String>, QQueryOperations>
+      knownSaltsProperty() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addPropertyName(r'knownSalts');
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, String, QQueryOperations> walletIdProperty() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addPropertyName(r'walletId');
+    });
+  }
+}
diff --git a/lib/wallets/isar/models/wallet_info.g.dart b/lib/wallets/isar/models/wallet_info.g.dart
index db50a581a..0b809ddcb 100644
--- a/lib/wallets/isar/models/wallet_info.g.dart
+++ b/lib/wallets/isar/models/wallet_info.g.dart
@@ -265,6 +265,7 @@ const _WalletInfomainAddressTypeEnumValueMap = {
   'spark': 10,
   'stellar': 11,
   'tezos': 12,
+  'frostMS': 13,
 };
 const _WalletInfomainAddressTypeValueEnumMap = {
   0: AddressType.p2pkh,
@@ -280,6 +281,7 @@ const _WalletInfomainAddressTypeValueEnumMap = {
   10: AddressType.spark,
   11: AddressType.stellar,
   12: AddressType.tezos,
+  13: AddressType.frostMS,
 };
 
 Id _walletInfoGetId(WalletInfo object) {
diff --git a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
new file mode 100644
index 000000000..203ea5877
--- /dev/null
+++ b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
@@ -0,0 +1,475 @@
+import 'dart:async';
+
+import 'package:flutter/foundation.dart';
+import 'package:frostdart/frostdart.dart' as frost;
+import 'package:frostdart/frostdart_bindings_generated.dart';
+import 'package:isar/isar.dart';
+import 'package:stackwallet/electrumx_rpc/cached_electrumx_client.dart';
+import 'package:stackwallet/electrumx_rpc/electrumx_client.dart';
+import 'package:stackwallet/models/balance.dart';
+import 'package:stackwallet/models/isar/models/blockchain_data/address.dart';
+import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart';
+import 'package:stackwallet/models/paymint/fee_object_model.dart';
+import 'package:stackwallet/utilities/amount/amount.dart';
+import 'package:stackwallet/utilities/extensions/extensions.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin_frost.dart';
+import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
+import 'package:stackwallet/wallets/crypto_currency/intermediate/private_key_currency.dart';
+import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart';
+import 'package:stackwallet/wallets/models/tx_data.dart';
+import 'package:stackwallet/wallets/wallet/wallet.dart';
+import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/private_key_interface.dart';
+
+class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T>
+    with PrivateKeyInterface {
+  FrostWalletInfo get frostInfo => throw UnimplementedError();
+
+  late ElectrumXClient electrumXClient;
+  late CachedElectrumXClient electrumXCachedClient;
+
+  @override
+  int get isarTransactionVersion => 2;
+
+  BitcoinFrostWallet(CryptoCurrencyNetwork network)
+      : super(BitcoinFrost(network) as T);
+
+  @override
+  FilterOperation? get changeAddressFilterOperation => FilterGroup.and(
+        [
+          FilterCondition.equalTo(
+            property: r"type",
+            value: info.mainAddressType,
+          ),
+          const FilterCondition.equalTo(
+            property: r"subType",
+            value: AddressSubType.change,
+          ),
+        ],
+      );
+
+  @override
+  FilterOperation? get receivingAddressFilterOperation => FilterGroup.and(
+        [
+          FilterCondition.equalTo(
+            property: r"type",
+            value: info.mainAddressType,
+          ),
+          const FilterCondition.equalTo(
+            property: r"subType",
+            value: AddressSubType.receiving,
+          ),
+        ],
+      );
+
+  // Future<List<Address>> fetchAddressesForElectrumXScan() async {
+  //   final allAddresses = await mainDB
+  //       .getAddresses(walletId)
+  //       .filter()
+  //       .typeEqualTo(AddressType.frostMS)
+  //       .and()
+  //       .group(
+  //         (q) => q
+  //             .subTypeEqualTo(AddressSubType.receiving)
+  //             .or()
+  //             .subTypeEqualTo(AddressSubType.change),
+  //       )
+  //       .findAll();
+  //   return allAddresses;
+  // }
+
+  @override
+  Future<void> updateTransactions() {
+    // TODO: implement updateTransactions
+    throw UnimplementedError();
+  }
+
+  int estimateTxFee({required int vSize, required int feeRatePerKB}) {
+    return vSize * (feeRatePerKB / 1000).ceil();
+  }
+
+  Amount roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
+    return Amount(
+      rawValue: BigInt.from(
+          ((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() *
+              (feeRatePerKB / 1000).ceil()),
+      fractionDigits: cryptoCurrency.fractionDigits,
+    );
+  }
+
+  @override
+  Future<void> checkSaveInitialReceivingAddress() {
+    // TODO: implement checkSaveInitialReceivingAddress
+    throw UnimplementedError();
+  }
+
+  @override
+  Future<TxData> confirmSend({required TxData txData}) {
+    // TODO: implement confirmSend
+    throw UnimplementedError();
+  }
+
+  @override
+  Future<Amount> estimateFeeFor(Amount amount, int feeRate) {
+    // TODO: implement estimateFeeFor
+    throw UnimplementedError();
+  }
+
+  @override
+  // TODO: implement fees
+  Future<FeeObject> get fees => throw UnimplementedError();
+
+  @override
+  Future<TxData> prepareSend({required TxData txData}) {
+    // TODO: implement prepareSendpu
+    throw UnimplementedError();
+  }
+
+  @override
+  Future<void> recover({
+    required bool isRescan,
+    String? serializedKeys,
+    String? multisigConfig,
+  }) async {
+    if (serializedKeys == null || multisigConfig == null) {
+      throw Exception(
+        "Failed to recover $runtimeType: "
+        "Missing serializedKeys and/or multisigConfig.",
+      );
+    }
+
+    try {
+      await refreshMutex.protect(() async {
+        if (!isRescan) {
+          final salt = frost
+              .multisigSalt(
+                multisigConfig: multisigConfig,
+              )
+              .toHex;
+          final knownSalts = frostInfo.knownSalts;
+          if (knownSalts.contains(salt)) {
+            throw Exception("Known frost multisig salt found!");
+          }
+          knownSalts.add(salt);
+          await frostInfo.updateKnownSalts(knownSalts, isar: mainDB.isar);
+        }
+
+        final keys = frost.deserializeKeys(keys: serializedKeys);
+        await _saveSerializedKeys(serializedKeys);
+        await _saveMultisigConfig(multisigConfig);
+
+        final addressString = frost.addressForKeys(
+          network: cryptoCurrency.network == CryptoCurrencyNetwork.main
+              ? Network.Mainnet
+              : Network.Testnet,
+          keys: keys,
+        );
+
+        final publicKey = frost.scriptPubKeyForKeys(keys: keys);
+
+        final address = Address(
+          walletId: walletId,
+          value: addressString,
+          publicKey: publicKey.toUint8ListFromHex,
+          derivationIndex: 0,
+          derivationPath: null,
+          subType: AddressSubType.receiving,
+          type: AddressType.frostMS,
+        );
+
+        await mainDB.updateOrPutAddresses([address]);
+      });
+
+      unawaited(refresh());
+    } catch (e, s) {
+      Logging.instance.log(
+        "recoverFromSerializedKeys failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+
+  @override
+  Future<void> updateBalance() async {
+    final utxos = await mainDB.getUTXOs(walletId).findAll();
+
+    final currentChainHeight = await chainHeight;
+
+    Amount satoshiBalanceTotal = Amount(
+      rawValue: BigInt.zero,
+      fractionDigits: cryptoCurrency.fractionDigits,
+    );
+    Amount satoshiBalancePending = Amount(
+      rawValue: BigInt.zero,
+      fractionDigits: cryptoCurrency.fractionDigits,
+    );
+    Amount satoshiBalanceSpendable = Amount(
+      rawValue: BigInt.zero,
+      fractionDigits: cryptoCurrency.fractionDigits,
+    );
+    Amount satoshiBalanceBlocked = Amount(
+      rawValue: BigInt.zero,
+      fractionDigits: cryptoCurrency.fractionDigits,
+    );
+
+    for (final utxo in utxos) {
+      final utxoAmount = Amount(
+        rawValue: BigInt.from(utxo.value),
+        fractionDigits: cryptoCurrency.fractionDigits,
+      );
+
+      satoshiBalanceTotal += utxoAmount;
+
+      if (utxo.isBlocked) {
+        satoshiBalanceBlocked += utxoAmount;
+      } else {
+        if (utxo.isConfirmed(
+          currentChainHeight,
+          cryptoCurrency.minConfirms,
+        )) {
+          satoshiBalanceSpendable += utxoAmount;
+        } else {
+          satoshiBalancePending += utxoAmount;
+        }
+      }
+    }
+
+    final balance = Balance(
+      total: satoshiBalanceTotal,
+      spendable: satoshiBalanceSpendable,
+      blockedTotal: satoshiBalanceBlocked,
+      pendingSpendable: satoshiBalancePending,
+    );
+
+    await info.updateBalance(newBalance: balance, isar: mainDB.isar);
+  }
+
+  @override
+  Future<void> updateChainHeight() async {
+    final int height;
+    try {
+      final result = await electrumXClient.getBlockHeadTip();
+      height = result["height"] as int;
+    } catch (e) {
+      rethrow;
+    }
+
+    await info.updateCachedChainHeight(
+      newHeight: height,
+      isar: mainDB.isar,
+    );
+  }
+
+  @override
+  Future<bool> pingCheck() async {
+    try {
+      final result = await electrumXClient.ping();
+      return result;
+    } catch (_) {
+      return false;
+    }
+  }
+
+  @override
+  Future<void> updateNode() async {
+    await _updateElectrumX();
+  }
+
+  @override
+  Future<bool> updateUTXOs() async {
+    final address = await getCurrentReceivingAddress();
+
+    try {
+      final scriptHash = cryptoCurrency.pubKeyToScriptHash(
+        pubKey: Uint8List.fromList(address!.publicKey),
+      );
+
+      final utxos = await electrumXClient.getUTXOs(scripthash: scriptHash);
+
+      final List<UTXO> outputArray = [];
+
+      for (int i = 0; i < utxos.length; i++) {
+        final utxo = await _parseUTXO(
+          jsonUTXO: utxos[i],
+        );
+
+        outputArray.add(utxo);
+      }
+
+      return await mainDB.updateUTXOs(walletId, outputArray);
+    } catch (e, s) {
+      Logging.instance.log(
+        "Output fetch unsuccessful: $e\n$s",
+        level: LogLevel.Error,
+      );
+      return false;
+    }
+  }
+
+  // =================== Secure storage ========================================
+
+  Future<String?> get getSerializedKeys async =>
+      await secureStorageInterface.read(
+        key: "{$walletId}_serializedFROSTKeys",
+      );
+  Future<void> _saveSerializedKeys(String keys) async {
+    final current = await getSerializedKeys;
+
+    if (current == null) {
+      // do nothing
+    } else if (current == keys) {
+      // should never occur
+    } else {
+      // save current as prev gen before updating current
+      await secureStorageInterface.write(
+        key: "{$walletId}_serializedFROSTKeysPrevGen",
+        value: current,
+      );
+    }
+
+    await secureStorageInterface.write(
+      key: "{$walletId}_serializedFROSTKeys",
+      value: keys,
+    );
+  }
+
+  Future<String?> get getSerializedKeysPrevGen async =>
+      await secureStorageInterface.read(
+        key: "{$walletId}_serializedFROSTKeysPrevGen",
+      );
+
+  Future<String?> get multisigConfig async => await secureStorageInterface.read(
+        key: "{$walletId}_multisigConfig",
+      );
+  Future<String?> get multisigConfigPrevGen async =>
+      await secureStorageInterface.read(
+        key: "{$walletId}_multisigConfigPrevGen",
+      );
+  Future<void> _saveMultisigConfig(String multisigConfig) async {
+    final current = await this.multisigConfig;
+
+    if (current == null) {
+      // do nothing
+    } else if (current == multisigConfig) {
+      // should never occur
+    } else {
+      // save current as prev gen before updating current
+      await secureStorageInterface.write(
+        key: "{$walletId}_multisigConfigPrevGen",
+        value: current,
+      );
+    }
+
+    await secureStorageInterface.write(
+      key: "{$walletId}_multisigConfig",
+      value: multisigConfig,
+    );
+  }
+
+  Future<Uint8List?> get multisigId async {
+    final id = await secureStorageInterface.read(
+      key: "{$walletId}_multisigIdFROST",
+    );
+    if (id == null) {
+      return null;
+    } else {
+      return id.toUint8ListFromHex;
+    }
+  }
+
+  Future<void> saveMultisigId(Uint8List id) async =>
+      await secureStorageInterface.write(
+        key: "{$walletId}_multisigIdFROST",
+        value: id.toHex,
+      );
+
+  Future<String?> get recoveryString async => await secureStorageInterface.read(
+        key: "{$walletId}_recoveryStringFROST",
+      );
+  Future<void> saveRecoveryString(String recoveryString) async =>
+      await secureStorageInterface.write(
+        key: "{$walletId}_recoveryStringFROST",
+        value: recoveryString,
+      );
+
+  // =================== Private ===============================================
+
+  Future<ElectrumXNode> _getCurrentElectrumXNode() async {
+    final node = getCurrentNode();
+
+    return ElectrumXNode(
+      address: node.host,
+      port: node.port,
+      name: node.name,
+      useSSL: node.useSSL,
+      id: node.id,
+    );
+  }
+
+  Future<void> _updateElectrumX() async {
+    final failovers = nodeService
+        .failoverNodesFor(coin: cryptoCurrency.coin)
+        .map((e) => ElectrumXNode(
+              address: e.host,
+              port: e.port,
+              name: e.name,
+              id: e.id,
+              useSSL: e.useSSL,
+            ))
+        .toList();
+
+    final newNode = await _getCurrentElectrumXNode();
+    electrumXClient = ElectrumXClient.from(
+      node: newNode,
+      prefs: prefs,
+      failovers: failovers,
+    );
+    electrumXCachedClient = CachedElectrumXClient.from(
+      electrumXClient: electrumXClient,
+    );
+  }
+
+  Future<UTXO> _parseUTXO({
+    required Map<String, dynamic> jsonUTXO,
+  }) async {
+    final txn = await electrumXCachedClient.getTransaction(
+      txHash: jsonUTXO["tx_hash"] as String,
+      verbose: true,
+      coin: cryptoCurrency.coin,
+    );
+
+    final vout = jsonUTXO["tx_pos"] as int;
+
+    final outputs = txn["vout"] as List;
+
+    String? scriptPubKey;
+    String? utxoOwnerAddress;
+    // get UTXO owner address
+    for (final output in outputs) {
+      if (output["n"] == vout) {
+        scriptPubKey = output["scriptPubKey"]?["hex"] as String?;
+        utxoOwnerAddress =
+            output["scriptPubKey"]?["addresses"]?[0] as String? ??
+                output["scriptPubKey"]?["address"] as String?;
+      }
+    }
+
+    final utxo = UTXO(
+      walletId: walletId,
+      txid: txn["txid"] as String,
+      vout: vout,
+      value: jsonUTXO["value"] as int,
+      name: "",
+      isBlocked: false,
+      blockedReason: null,
+      isCoinbase: txn["is_coinbase"] as bool? ?? false,
+      blockHash: txn["blockhash"] as String?,
+      blockHeight: jsonUTXO["height"] as int?,
+      blockTime: txn["blocktime"] as int?,
+      address: utxoOwnerAddress,
+    );
+
+    return utxo;
+  }
+}
diff --git a/lib/wallets/wallet/wallet.dart b/lib/wallets/wallet/wallet.dart
index 796760dbd..711a895a1 100644
--- a/lib/wallets/wallet/wallet.dart
+++ b/lib/wallets/wallet/wallet.dart
@@ -25,6 +25,7 @@ import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
 import 'package:stackwallet/wallets/isar/models/wallet_info.dart';
 import 'package:stackwallet/wallets/models/tx_data.dart';
 import 'package:stackwallet/wallets/wallet/impl/banano_wallet.dart';
+import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
 import 'package:stackwallet/wallets/wallet/impl/bitcoin_wallet.dart';
 import 'package:stackwallet/wallets/wallet/impl/bitcoincash_wallet.dart';
 import 'package:stackwallet/wallets/wallet/impl/dogecoin_wallet.dart';
@@ -311,6 +312,11 @@ abstract class Wallet<T extends CryptoCurrency> {
       case Coin.bitcoinTestNet:
         return BitcoinWallet(CryptoCurrencyNetwork.test);
 
+      case Coin.bitcoinFrost:
+        return BitcoinFrostWallet(CryptoCurrencyNetwork.main);
+      case Coin.bitcoinFrostTestNet:
+        return BitcoinFrostWallet(CryptoCurrencyNetwork.test);
+
       case Coin.bitcoincash:
         return BitcoincashWallet(CryptoCurrencyNetwork.main);
       case Coin.bitcoincashTestnet:
diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart
index 1f425d498..2bb78e228 100644
--- a/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart
+++ b/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart
@@ -832,7 +832,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
     }
   }
 
-  Future<ElectrumXNode> getCurrentElectrumXNode() async {
+  Future<ElectrumXNode> _getCurrentElectrumXNode() async {
     final node = getCurrentNode();
 
     return ElectrumXNode(
@@ -844,7 +844,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
     );
   }
 
-  Future<void> updateElectrumX({required ElectrumXNode newNode}) async {
+  Future<void> updateElectrumX() async {
     final failovers = nodeService
         .failoverNodesFor(coin: cryptoCurrency.coin)
         .map((e) => ElectrumXNode(
@@ -856,7 +856,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
             ))
         .toList();
 
-    final newNode = await getCurrentElectrumXNode();
+    final newNode = await _getCurrentElectrumXNode();
     electrumXClient = ElectrumXClient.from(
       node: newNode,
       prefs: prefs,
@@ -1160,8 +1160,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
 
   @override
   Future<void> updateNode() async {
-    final node = await getCurrentElectrumXNode();
-    await updateElectrumX(newNode: node);
+    await updateElectrumX();
   }
 
   FeeObject? _cachedFees;
diff --git a/lib/widgets/node_card.dart b/lib/widgets/node_card.dart
index 7576999de..0e801490f 100644
--- a/lib/widgets/node_card.dart
+++ b/lib/widgets/node_card.dart
@@ -169,6 +169,8 @@ class _NodeCardState extends ConsumerState<NodeCard> {
       case Coin.namecoin:
       case Coin.bitcoincashTestnet:
       case Coin.eCash:
+      case Coin.bitcoinFrost:
+      case Coin.bitcoinFrostTestNet:
         final client = ElectrumXClient(
           host: node.host,
           port: node.port,
diff --git a/lib/widgets/node_options_sheet.dart b/lib/widgets/node_options_sheet.dart
index c14b6a2ec..31fd13c30 100644
--- a/lib/widgets/node_options_sheet.dart
+++ b/lib/widgets/node_options_sheet.dart
@@ -151,6 +151,8 @@ class NodeOptionsSheet extends ConsumerWidget {
       case Coin.namecoin:
       case Coin.bitcoincashTestnet:
       case Coin.eCash:
+      case Coin.bitcoinFrost:
+      case Coin.bitcoinFrostTestNet:
         final client = ElectrumXClient(
           host: node.host,
           port: node.port,

From 8ae2faa91ff255c8860228a846beb0b4fa262cc9 Mon Sep 17 00:00:00 2001
From: julian <julian@cypherstack.com>
Date: Fri, 19 Jan 2024 15:42:38 -0600
Subject: [PATCH 05/57] WIP frost wallet logic

---
 lib/services/frost.dart                       | 613 ++++++++++++++
 .../crypto_currency/coins/bitcoin_frost.dart  |   7 +
 .../intermediate/private_key_currency.dart    |   3 +
 .../isar/models/frost_wallet_info.dart        |  23 +-
 .../isar/models/frost_wallet_info.g.dart      | 552 ++++++++++++-
 .../wallet/impl/bitcoin_frost_wallet.dart     | 768 ++++++++++++++++--
 lib/wallets/wallet/wallet.dart                |   2 +-
 7 files changed, 1889 insertions(+), 79 deletions(-)
 create mode 100644 lib/services/frost.dart

diff --git a/lib/services/frost.dart b/lib/services/frost.dart
new file mode 100644
index 000000000..a420a5b16
--- /dev/null
+++ b/lib/services/frost.dart
@@ -0,0 +1,613 @@
+import 'dart:ffi';
+import 'dart:typed_data';
+
+import 'package:frostdart/frostdart.dart';
+import 'package:frostdart/frostdart_bindings_generated.dart';
+import 'package:frostdart/output.dart';
+import 'package:frostdart/util.dart';
+import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart';
+import 'package:stackwallet/utilities/amount/amount.dart';
+import 'package:stackwallet/utilities/extensions/extensions.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
+
+abstract class Frost {
+  //==================== utility ===============================================
+  static List<String> getParticipants({
+    required String multisigConfig,
+  }) {
+    try {
+      final numberOfParticipants = multisigParticipants(
+        multisigConfig: multisigConfig,
+      );
+
+      final List<String> participants = [];
+      for (int i = 0; i < numberOfParticipants; i++) {
+        participants.add(
+          multisigParticipant(
+            multisigConfig: multisigConfig,
+            index: i,
+          ),
+        );
+      }
+
+      return participants;
+    } catch (e, s) {
+      Logging.instance.log(
+        "getParticipants failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+
+  static bool validateEncodedMultisigConfig({required String encodedConfig}) {
+    try {
+      decodeMultisigConfig(multisigConfig: encodedConfig);
+      return true;
+    } catch (e, s) {
+      Logging.instance.log(
+        "validateEncodedMultisigConfig failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      return false;
+    }
+  }
+
+  static int getThreshold({
+    required String multisigConfig,
+  }) {
+    try {
+      final threshold = multisigThreshold(
+        multisigConfig: multisigConfig,
+      );
+
+      return threshold;
+    } catch (e, s) {
+      Logging.instance.log(
+        "getThreshold failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+
+  static ({
+    List<({String address, Amount amount})> recipients,
+    String changeAddress,
+    int feePerWeight,
+    List<Output> inputs,
+  }) extractDataFromSignConfig({
+    required String signConfig,
+    required CryptoCurrency coin,
+  }) {
+    try {
+      final network = coin.network == CryptoCurrencyNetwork.test
+          ? Network.Testnet
+          : Network.Mainnet;
+      final signConfigPointer = decodedSignConfig(
+        encodedConfig: signConfig,
+        network: network,
+      );
+
+      // get various data from config
+      final feePerWeight =
+          signFeePerWeight(signConfigPointer: signConfigPointer);
+      final changeAddress = signChange(signConfigPointer: signConfigPointer);
+      final recipientsCount = signPayments(
+        signConfigPointer: signConfigPointer,
+      );
+
+      // get tx recipient info
+      final List<({String address, Amount amount})> recipients = [];
+      for (int i = 0; i < recipientsCount; i++) {
+        final String address = signPaymentAddress(
+          signConfigPointer: signConfigPointer,
+          index: i,
+        );
+        final int amount = signPaymentAmount(
+          signConfigPointer: signConfigPointer,
+          index: i,
+        );
+        recipients.add(
+          (
+            address: address,
+            amount: Amount(
+              rawValue: BigInt.from(amount),
+              fractionDigits: coin.fractionDigits,
+            ),
+          ),
+        );
+      }
+
+      // get utxos
+      final count = signInputs(signConfigPointer: signConfigPointer);
+      final List<Output> outputs = [];
+      for (int i = 0; i < count; i++) {
+        final output = signInput(
+          signConfig: signConfig,
+          index: i,
+          network: network,
+        );
+
+        outputs.add(output);
+      }
+
+      return (
+        recipients: recipients,
+        changeAddress: changeAddress,
+        feePerWeight: feePerWeight,
+        inputs: outputs,
+      );
+    } catch (e, s) {
+      Logging.instance.log(
+        "extractDataFromSignConfig failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+
+  //==================== wallet creation =======================================
+
+  static String createMultisigConfig({
+    required String name,
+    required int threshold,
+    required List<String> participants,
+  }) {
+    try {
+      final config = newMultisigConfig(
+        name: name,
+        threshold: threshold,
+        participants: participants,
+      );
+
+      return config;
+    } catch (e, s) {
+      Logging.instance.log(
+        "createMultisigConfig failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+
+  static ({
+    String seed,
+    String commitments,
+    Pointer<MultisigConfigWithName> multisigConfigWithNamePtr,
+    Pointer<SecretShareMachineWrapper> secretShareMachineWrapperPtr,
+  }) startKeyGeneration({
+    required String multisigConfig,
+    required String myName,
+  }) {
+    try {
+      final startKeyGenResPtr = startKeyGen(
+        multisigConfig: multisigConfig,
+        myName: myName,
+        language: Language.english,
+      );
+
+      final seed = startKeyGenResPtr.ref.seed.toDartString();
+      final commitments = startKeyGenResPtr.ref.commitments.toDartString();
+      final configWithNamePtr = startKeyGenResPtr.ref.config;
+      final machinePtr = startKeyGenResPtr.ref.machine;
+
+      return (
+        seed: seed,
+        commitments: commitments,
+        multisigConfigWithNamePtr: configWithNamePtr,
+        secretShareMachineWrapperPtr: machinePtr,
+      );
+    } catch (e, s) {
+      Logging.instance.log(
+        "startKeyGeneration failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+
+  static ({
+    String share,
+    Pointer<SecretSharesRes> secretSharesResPtr,
+  }) generateSecretShares({
+    required Pointer<MultisigConfigWithName> multisigConfigWithNamePtr,
+    required String mySeed,
+    required Pointer<SecretShareMachineWrapper> secretShareMachineWrapperPtr,
+    required List<String> commitments,
+  }) {
+    try {
+      final secretSharesResPtr = getSecretShares(
+        multisigConfigWithName: multisigConfigWithNamePtr,
+        seed: mySeed,
+        language: Language.english,
+        machine: secretShareMachineWrapperPtr,
+        commitments: commitments,
+      );
+
+      final share = secretSharesResPtr.ref.shares.toDartString();
+
+      return (share: share, secretSharesResPtr: secretSharesResPtr);
+    } catch (e, s) {
+      Logging.instance.log(
+        "generateSecretShares failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+
+  static ({
+    Uint8List multisigId,
+    String recoveryString,
+    String serializedKeys,
+  }) completeKeyGeneration({
+    required Pointer<MultisigConfigWithName> multisigConfigWithNamePtr,
+    required Pointer<SecretSharesRes> secretSharesResPtr,
+    required List<String> shares,
+  }) {
+    try {
+      final keyGenResPtr = completeKeyGen(
+        multisigConfigWithName: multisigConfigWithNamePtr,
+        machineAndCommitments: secretSharesResPtr,
+        shares: shares,
+      );
+
+      final id = Uint8List.fromList(
+        List<int>.generate(
+          MULTISIG_ID_LENGTH,
+          (index) => keyGenResPtr.ref.multisig_id[index],
+        ),
+      );
+
+      final recoveryString = keyGenResPtr.ref.recovery.toDartString();
+
+      final serializedKeys = serializeKeys(keys: keyGenResPtr.ref.keys);
+
+      return (
+        multisigId: id,
+        recoveryString: recoveryString,
+        serializedKeys: serializedKeys,
+      );
+    } catch (e, s) {
+      Logging.instance.log(
+        "completeKeyGeneration failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+
+  //=================== transaction creation ===================================
+
+  static String createSignConfig({
+    required int network,
+    required List<({UTXO utxo, Uint8List scriptPubKey})> inputs,
+    required List<({String address, Amount amount, bool isChange})> outputs,
+    required String changeAddress,
+    required int feePerWeight,
+  }) {
+    try {
+      final signConfig = newSignConfig(
+        network: network,
+        outputs: inputs
+            .map(
+              (e) => Output(
+                hash: e.utxo.txid.toUint8ListFromHex,
+                vout: e.utxo.vout,
+                value: e.utxo.value,
+                scriptPubKey: e.scriptPubKey,
+              ),
+            )
+            .toList(),
+        paymentAddresses: outputs.map((e) => e.address).toList(),
+        paymentAmounts: outputs.map((e) => e.amount.raw.toInt()).toList(),
+        change: changeAddress,
+        feePerWeight: feePerWeight,
+      );
+
+      return signConfig;
+    } catch (e, s) {
+      Logging.instance.log(
+        "createSignConfig failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+
+  static ({
+    Pointer<TransactionSignMachineWrapper> machinePtr,
+    String preprocess,
+  }) attemptSignConfig({
+    required int network,
+    required String config,
+    required String serializedKeys,
+  }) {
+    try {
+      final keys = deserializeKeys(keys: serializedKeys);
+
+      final attemptSignRes = attemptSign(
+        thresholdKeysWrapperPointer: keys,
+        network: network,
+        signConfig: config,
+      );
+
+      return (
+        preprocess: attemptSignRes.ref.preprocess.toDartString(),
+        machinePtr: attemptSignRes.ref.machine,
+      );
+    } catch (e, s) {
+      Logging.instance.log(
+        "attemptSignConfig failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+
+  static ({
+    Pointer<TransactionSignatureMachineWrapper> machinePtr,
+    String share,
+  }) continueSigning({
+    required Pointer<TransactionSignMachineWrapper> machinePtr,
+    required List<String> preprocesses,
+  }) {
+    try {
+      final continueSignRes = continueSign(
+        machine: machinePtr,
+        preprocesses: preprocesses,
+      );
+
+      return (
+        share: continueSignRes.ref.preprocess.toDartString(),
+        machinePtr: continueSignRes.ref.machine,
+      );
+    } catch (e, s) {
+      Logging.instance.log(
+        "continueSigning failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+
+  static String completeSigning({
+    required Pointer<TransactionSignatureMachineWrapper> machinePtr,
+    required List<String> shares,
+  }) {
+    try {
+      final rawTransaction = completeSign(
+        machine: machinePtr,
+        shares: shares,
+      );
+
+      return rawTransaction;
+    } catch (e, s) {
+      Logging.instance.log(
+        "completeSigning failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+
+  static Pointer<SignConfig> decodedSignConfig({
+    required String encodedConfig,
+    required int network,
+  }) {
+    try {
+      final configPtr =
+          decodeSignConfig(encodedSignConfig: encodedConfig, network: network);
+      return configPtr;
+    } catch (e, s) {
+      Logging.instance.log(
+        "decodedSignConfig failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+
+  //========================== resharing =======================================
+
+  static String createResharerConfig({
+    required int newThreshold,
+    required List<int> resharers,
+    required List<String> newParticipants,
+  }) {
+    try {
+      final config = newResharerConfig(
+        newThreshold: newThreshold,
+        newParticipants: newParticipants,
+        resharers: resharers,
+      );
+
+      return config;
+    } catch (e, s) {
+      Logging.instance.log(
+        "createResharerConfig failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+
+  static ({
+    String resharerStart,
+    Pointer<StartResharerRes> machine,
+  }) beginResharer({
+    required String serializedKeys,
+    required String config,
+  }) {
+    try {
+      final result = startResharer(
+        serializedKeys: serializedKeys,
+        config: config,
+      );
+
+      return (
+        resharerStart: result.encoded,
+        machine: result.machine,
+      );
+    } catch (e, s) {
+      Logging.instance.log(
+        "beginResharer failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+
+  /// expects [resharerStarts] of length equal to resharers.
+  static ({
+    String resharedStart,
+    Pointer<StartResharedRes> prior,
+  }) beginReshared({
+    required String myName,
+    required String resharerConfig,
+    required List<String> resharerStarts,
+  }) {
+    try {
+      final result = startReshared(
+        newMultisigName: 'unused_property',
+        myName: myName,
+        resharerConfig: resharerConfig,
+        resharerStarts: resharerStarts,
+      );
+      return (
+        resharedStart: result.encoded,
+        prior: result.machine,
+      );
+    } catch (e, s) {
+      Logging.instance.log(
+        "beginReshared failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+
+  /// expects [encryptionKeysOfResharedTo] of length equal to new participants
+  static String finishResharer({
+    required StartResharerRes machine,
+    required List<String> encryptionKeysOfResharedTo,
+  }) {
+    try {
+      final result = completeResharer(
+        machine: machine,
+        encryptionKeysOfResharedTo: encryptionKeysOfResharedTo,
+      );
+      return result;
+    } catch (e, s) {
+      Logging.instance.log(
+        "finishResharer failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+
+  /// expects [resharerCompletes] of length equal to resharers
+  static ({
+    String multisigConfig,
+    String serializedKeys,
+    String resharedId,
+  }) finishReshared({
+    required StartResharedRes prior,
+    required List<String> resharerCompletes,
+  }) {
+    try {
+      final result = completeReshared(
+        prior: prior,
+        resharerCompletes: resharerCompletes,
+      );
+      return result;
+    } catch (e, s) {
+      Logging.instance.log(
+        "finishReshared failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+
+  static Pointer<ResharerConfig> decodedResharerConfig({
+    required String resharerConfig,
+  }) {
+    try {
+      final config = decodeResharerConfig(resharerConfig: resharerConfig);
+
+      return config;
+    } catch (e, s) {
+      Logging.instance.log(
+        "decodedResharerConfig failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+
+  static ({
+    int newThreshold,
+    List<int> resharers,
+    List<String> newParticipants,
+  }) extractResharerConfigData({
+    required String resharerConfig,
+  }) {
+    try {
+      final newThreshold = resharerNewThreshold(
+        resharerConfigPointer: decodedResharerConfig(
+          resharerConfig: resharerConfig,
+        ),
+      );
+
+      final resharersCount = resharerResharers(
+        resharerConfigPointer: decodedResharerConfig(
+          resharerConfig: resharerConfig,
+        ),
+      );
+      final List<int> resharers = [];
+      for (int i = 0; i < resharersCount; i++) {
+        resharers.add(
+          resharerResharer(
+            resharerConfigPointer: decodedResharerConfig(
+              resharerConfig: resharerConfig,
+            ),
+            index: i,
+          ),
+        );
+      }
+
+      final newParticipantsCount = resharerNewParticipants(
+        resharerConfigPointer: decodedResharerConfig(
+          resharerConfig: resharerConfig,
+        ),
+      );
+      final List<String> newParticipants = [];
+      for (int i = 0; i < newParticipantsCount; i++) {
+        newParticipants.add(
+          resharerNewParticipant(
+            resharerConfigPointer: decodedResharerConfig(
+              resharerConfig: resharerConfig,
+            ),
+            index: i,
+          ),
+        );
+      }
+
+      return (
+        newThreshold: newThreshold,
+        resharers: resharers,
+        newParticipants: newParticipants,
+      );
+    } catch (e, s) {
+      Logging.instance.log(
+        "extractResharerConfigData failed: $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+}
diff --git a/lib/wallets/crypto_currency/coins/bitcoin_frost.dart b/lib/wallets/crypto_currency/coins/bitcoin_frost.dart
index f968818e1..b82d3987c 100644
--- a/lib/wallets/crypto_currency/coins/bitcoin_frost.dart
+++ b/lib/wallets/crypto_currency/coins/bitcoin_frost.dart
@@ -1,6 +1,7 @@
 import 'dart:typed_data';
 
 import 'package:stackwallet/models/node_model.dart';
+import 'package:stackwallet/utilities/amount/amount.dart';
 import 'package:stackwallet/utilities/default_nodes.dart';
 import 'package:stackwallet/utilities/enums/coin_enum.dart';
 import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
@@ -48,6 +49,12 @@ class BitcoinFrost extends FrostCurrency {
     }
   }
 
+  @override
+  Amount get dustLimit => Amount(
+        rawValue: BigInt.from(294),
+        fractionDigits: fractionDigits,
+      );
+
   @override
   String pubKeyToScriptHash({required Uint8List pubKey}) {
     try {
diff --git a/lib/wallets/crypto_currency/intermediate/private_key_currency.dart b/lib/wallets/crypto_currency/intermediate/private_key_currency.dart
index 8cbf11b27..0c10937fa 100644
--- a/lib/wallets/crypto_currency/intermediate/private_key_currency.dart
+++ b/lib/wallets/crypto_currency/intermediate/private_key_currency.dart
@@ -1,9 +1,12 @@
 import 'dart:typed_data';
 
+import 'package:stackwallet/utilities/amount/amount.dart';
 import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
 
 abstract class FrostCurrency extends CryptoCurrency {
   FrostCurrency(super.network);
 
   String pubKeyToScriptHash({required Uint8List pubKey});
+
+  Amount get dustLimit;
 }
diff --git a/lib/wallets/isar/models/frost_wallet_info.dart b/lib/wallets/isar/models/frost_wallet_info.dart
index 817f78f39..b5c7476d2 100644
--- a/lib/wallets/isar/models/frost_wallet_info.dart
+++ b/lib/wallets/isar/models/frost_wallet_info.dart
@@ -12,27 +12,30 @@ class FrostWalletInfo implements IsarId {
   final String walletId;
 
   final List<String> knownSalts;
+  final List<String> participants;
+  final String myName;
+  final int threshold;
 
   FrostWalletInfo({
     required this.walletId,
     required this.knownSalts,
+    required this.participants,
+    required this.myName,
+    required this.threshold,
   });
 
   FrostWalletInfo copyWith({
     List<String>? knownSalts,
+    List<String>? participants,
+    String? myName,
+    int? threshold,
   }) {
     return FrostWalletInfo(
       walletId: walletId,
       knownSalts: knownSalts ?? this.knownSalts,
-    );
-  }
-
-  Future<void> updateKnownSalts(
-    List<String> knownSalts, {
-    required Isar isar,
-  }) async {
-    // await isar.writeTxn(() async {
-    //   await isar.
-    // })
+      participants: participants ?? this.participants,
+      myName: myName ?? this.myName,
+      threshold: threshold ?? this.threshold,
+    )..id = id;
   }
 }
diff --git a/lib/wallets/isar/models/frost_wallet_info.g.dart b/lib/wallets/isar/models/frost_wallet_info.g.dart
index ce5ae2aae..6c80125e2 100644
--- a/lib/wallets/isar/models/frost_wallet_info.g.dart
+++ b/lib/wallets/isar/models/frost_wallet_info.g.dart
@@ -22,8 +22,23 @@ const FrostWalletInfoSchema = CollectionSchema(
       name: r'knownSalts',
       type: IsarType.stringList,
     ),
-    r'walletId': PropertySchema(
+    r'myName': PropertySchema(
       id: 1,
+      name: r'myName',
+      type: IsarType.string,
+    ),
+    r'participants': PropertySchema(
+      id: 2,
+      name: r'participants',
+      type: IsarType.stringList,
+    ),
+    r'threshold': PropertySchema(
+      id: 3,
+      name: r'threshold',
+      type: IsarType.long,
+    ),
+    r'walletId': PropertySchema(
+      id: 4,
       name: r'walletId',
       type: IsarType.string,
     )
@@ -69,6 +84,14 @@ int _frostWalletInfoEstimateSize(
       bytesCount += value.length * 3;
     }
   }
+  bytesCount += 3 + object.myName.length * 3;
+  bytesCount += 3 + object.participants.length * 3;
+  {
+    for (var i = 0; i < object.participants.length; i++) {
+      final value = object.participants[i];
+      bytesCount += value.length * 3;
+    }
+  }
   bytesCount += 3 + object.walletId.length * 3;
   return bytesCount;
 }
@@ -80,7 +103,10 @@ void _frostWalletInfoSerialize(
   Map<Type, List<int>> allOffsets,
 ) {
   writer.writeStringList(offsets[0], object.knownSalts);
-  writer.writeString(offsets[1], object.walletId);
+  writer.writeString(offsets[1], object.myName);
+  writer.writeStringList(offsets[2], object.participants);
+  writer.writeLong(offsets[3], object.threshold);
+  writer.writeString(offsets[4], object.walletId);
 }
 
 FrostWalletInfo _frostWalletInfoDeserialize(
@@ -91,7 +117,10 @@ FrostWalletInfo _frostWalletInfoDeserialize(
 ) {
   final object = FrostWalletInfo(
     knownSalts: reader.readStringList(offsets[0]) ?? [],
-    walletId: reader.readString(offsets[1]),
+    myName: reader.readString(offsets[1]),
+    participants: reader.readStringList(offsets[2]) ?? [],
+    threshold: reader.readLong(offsets[3]),
+    walletId: reader.readString(offsets[4]),
   );
   object.id = id;
   return object;
@@ -108,6 +137,12 @@ P _frostWalletInfoDeserializeProp<P>(
       return (reader.readStringList(offset) ?? []) as P;
     case 1:
       return (reader.readString(offset)) as P;
+    case 2:
+      return (reader.readStringList(offset) ?? []) as P;
+    case 3:
+      return (reader.readLong(offset)) as P;
+    case 4:
+      return (reader.readString(offset)) as P;
     default:
       throw IsarError('Unknown property with id $propertyId');
   }
@@ -589,6 +624,423 @@ extension FrostWalletInfoQueryFilter
     });
   }
 
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      myNameEqualTo(
+    String value, {
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.equalTo(
+        property: r'myName',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      myNameGreaterThan(
+    String value, {
+    bool include = false,
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.greaterThan(
+        include: include,
+        property: r'myName',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      myNameLessThan(
+    String value, {
+    bool include = false,
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.lessThan(
+        include: include,
+        property: r'myName',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      myNameBetween(
+    String lower,
+    String upper, {
+    bool includeLower = true,
+    bool includeUpper = true,
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.between(
+        property: r'myName',
+        lower: lower,
+        includeLower: includeLower,
+        upper: upper,
+        includeUpper: includeUpper,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      myNameStartsWith(
+    String value, {
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.startsWith(
+        property: r'myName',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      myNameEndsWith(
+    String value, {
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.endsWith(
+        property: r'myName',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      myNameContains(String value, {bool caseSensitive = true}) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.contains(
+        property: r'myName',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      myNameMatches(String pattern, {bool caseSensitive = true}) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.matches(
+        property: r'myName',
+        wildcard: pattern,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      myNameIsEmpty() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.equalTo(
+        property: r'myName',
+        value: '',
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      myNameIsNotEmpty() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.greaterThan(
+        property: r'myName',
+        value: '',
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      participantsElementEqualTo(
+    String value, {
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.equalTo(
+        property: r'participants',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      participantsElementGreaterThan(
+    String value, {
+    bool include = false,
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.greaterThan(
+        include: include,
+        property: r'participants',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      participantsElementLessThan(
+    String value, {
+    bool include = false,
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.lessThan(
+        include: include,
+        property: r'participants',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      participantsElementBetween(
+    String lower,
+    String upper, {
+    bool includeLower = true,
+    bool includeUpper = true,
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.between(
+        property: r'participants',
+        lower: lower,
+        includeLower: includeLower,
+        upper: upper,
+        includeUpper: includeUpper,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      participantsElementStartsWith(
+    String value, {
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.startsWith(
+        property: r'participants',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      participantsElementEndsWith(
+    String value, {
+    bool caseSensitive = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.endsWith(
+        property: r'participants',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      participantsElementContains(String value, {bool caseSensitive = true}) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.contains(
+        property: r'participants',
+        value: value,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      participantsElementMatches(String pattern, {bool caseSensitive = true}) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.matches(
+        property: r'participants',
+        wildcard: pattern,
+        caseSensitive: caseSensitive,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      participantsElementIsEmpty() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.equalTo(
+        property: r'participants',
+        value: '',
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      participantsElementIsNotEmpty() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.greaterThan(
+        property: r'participants',
+        value: '',
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      participantsLengthEqualTo(int length) {
+    return QueryBuilder.apply(this, (query) {
+      return query.listLength(
+        r'participants',
+        length,
+        true,
+        length,
+        true,
+      );
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      participantsIsEmpty() {
+    return QueryBuilder.apply(this, (query) {
+      return query.listLength(
+        r'participants',
+        0,
+        true,
+        0,
+        true,
+      );
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      participantsIsNotEmpty() {
+    return QueryBuilder.apply(this, (query) {
+      return query.listLength(
+        r'participants',
+        0,
+        false,
+        999999,
+        true,
+      );
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      participantsLengthLessThan(
+    int length, {
+    bool include = false,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.listLength(
+        r'participants',
+        0,
+        true,
+        length,
+        include,
+      );
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      participantsLengthGreaterThan(
+    int length, {
+    bool include = false,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.listLength(
+        r'participants',
+        length,
+        include,
+        999999,
+        true,
+      );
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      participantsLengthBetween(
+    int lower,
+    int upper, {
+    bool includeLower = true,
+    bool includeUpper = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.listLength(
+        r'participants',
+        lower,
+        includeLower,
+        upper,
+        includeUpper,
+      );
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      thresholdEqualTo(int value) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.equalTo(
+        property: r'threshold',
+        value: value,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      thresholdGreaterThan(
+    int value, {
+    bool include = false,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.greaterThan(
+        include: include,
+        property: r'threshold',
+        value: value,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      thresholdLessThan(
+    int value, {
+    bool include = false,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.lessThan(
+        include: include,
+        property: r'threshold',
+        value: value,
+      ));
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
+      thresholdBetween(
+    int lower,
+    int upper, {
+    bool includeLower = true,
+    bool includeUpper = true,
+  }) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(FilterCondition.between(
+        property: r'threshold',
+        lower: lower,
+        includeLower: includeLower,
+        upper: upper,
+        includeUpper: includeUpper,
+      ));
+    });
+  }
+
   QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterFilterCondition>
       walletIdEqualTo(
     String value, {
@@ -734,6 +1186,33 @@ extension FrostWalletInfoQueryLinks
 
 extension FrostWalletInfoQuerySortBy
     on QueryBuilder<FrostWalletInfo, FrostWalletInfo, QSortBy> {
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy> sortByMyName() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addSortBy(r'myName', Sort.asc);
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy>
+      sortByMyNameDesc() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addSortBy(r'myName', Sort.desc);
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy>
+      sortByThreshold() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addSortBy(r'threshold', Sort.asc);
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy>
+      sortByThresholdDesc() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addSortBy(r'threshold', Sort.desc);
+    });
+  }
+
   QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy>
       sortByWalletId() {
     return QueryBuilder.apply(this, (query) {
@@ -763,6 +1242,33 @@ extension FrostWalletInfoQuerySortThenBy
     });
   }
 
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy> thenByMyName() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addSortBy(r'myName', Sort.asc);
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy>
+      thenByMyNameDesc() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addSortBy(r'myName', Sort.desc);
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy>
+      thenByThreshold() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addSortBy(r'threshold', Sort.asc);
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy>
+      thenByThresholdDesc() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addSortBy(r'threshold', Sort.desc);
+    });
+  }
+
   QueryBuilder<FrostWalletInfo, FrostWalletInfo, QAfterSortBy>
       thenByWalletId() {
     return QueryBuilder.apply(this, (query) {
@@ -787,6 +1293,27 @@ extension FrostWalletInfoQueryWhereDistinct
     });
   }
 
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QDistinct> distinctByMyName(
+      {bool caseSensitive = true}) {
+    return QueryBuilder.apply(this, (query) {
+      return query.addDistinctBy(r'myName', caseSensitive: caseSensitive);
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QDistinct>
+      distinctByParticipants() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addDistinctBy(r'participants');
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, FrostWalletInfo, QDistinct>
+      distinctByThreshold() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addDistinctBy(r'threshold');
+    });
+  }
+
   QueryBuilder<FrostWalletInfo, FrostWalletInfo, QDistinct> distinctByWalletId(
       {bool caseSensitive = true}) {
     return QueryBuilder.apply(this, (query) {
@@ -810,6 +1337,25 @@ extension FrostWalletInfoQueryProperty
     });
   }
 
+  QueryBuilder<FrostWalletInfo, String, QQueryOperations> myNameProperty() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addPropertyName(r'myName');
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, List<String>, QQueryOperations>
+      participantsProperty() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addPropertyName(r'participants');
+    });
+  }
+
+  QueryBuilder<FrostWalletInfo, int, QQueryOperations> thresholdProperty() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addPropertyName(r'threshold');
+    });
+  }
+
   QueryBuilder<FrostWalletInfo, String, QQueryOperations> walletIdProperty() {
     return QueryBuilder.apply(this, (query) {
       return query.addPropertyName(r'walletId');
diff --git a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
index 203ea5877..102beb1e3 100644
--- a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
+++ b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
@@ -1,4 +1,5 @@
 import 'dart:async';
+import 'dart:ffi';
 
 import 'package:flutter/foundation.dart';
 import 'package:frostdart/frostdart.dart' as frost;
@@ -8,8 +9,15 @@ import 'package:stackwallet/electrumx_rpc/cached_electrumx_client.dart';
 import 'package:stackwallet/electrumx_rpc/electrumx_client.dart';
 import 'package:stackwallet/models/balance.dart';
 import 'package:stackwallet/models/isar/models/blockchain_data/address.dart';
+import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart';
 import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart';
+import 'package:stackwallet/models/isar/models/blockchain_data/v2/input_v2.dart';
+import 'package:stackwallet/models/isar/models/blockchain_data/v2/output_v2.dart';
+import 'package:stackwallet/models/isar/models/blockchain_data/v2/transaction_v2.dart';
 import 'package:stackwallet/models/paymint/fee_object_model.dart';
+import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
+import 'package:stackwallet/services/event_bus/global_event_bus.dart';
+import 'package:stackwallet/services/frost.dart';
 import 'package:stackwallet/utilities/amount/amount.dart';
 import 'package:stackwallet/utilities/extensions/extensions.dart';
 import 'package:stackwallet/utilities/logger.dart';
@@ -19,21 +27,275 @@ import 'package:stackwallet/wallets/crypto_currency/intermediate/private_key_cur
 import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart';
 import 'package:stackwallet/wallets/models/tx_data.dart';
 import 'package:stackwallet/wallets/wallet/wallet.dart';
-import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/private_key_interface.dart';
 
-class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T>
-    with PrivateKeyInterface {
-  FrostWalletInfo get frostInfo => throw UnimplementedError();
+class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
+  BitcoinFrostWallet(CryptoCurrencyNetwork network)
+      : super(BitcoinFrost(network) as T);
+
+  FrostWalletInfo get frostInfo => mainDB.isar.frostWalletInfo
+      .where()
+      .walletIdEqualTo(walletId)
+      .findFirstSync()!;
 
   late ElectrumXClient electrumXClient;
   late CachedElectrumXClient electrumXCachedClient;
 
+  Future<void> initializeNewFrost({
+    required String mnemonic,
+    required String multisigConfig,
+    required String recoveryString,
+    required String serializedKeys,
+    required Uint8List multisigId,
+    required String myName,
+    required List<String> participants,
+    required int threshold,
+  }) async {
+    Logging.instance.log(
+      "Generating new FROST wallet.",
+      level: LogLevel.Info,
+    );
+
+    try {
+      final salt = frost
+          .multisigSalt(
+            multisigConfig: multisigConfig,
+          )
+          .toHex;
+
+      final FrostWalletInfo frostWalletInfo = FrostWalletInfo(
+        walletId: info.walletId,
+        knownSalts: [salt],
+        participants: participants,
+        myName: myName,
+        threshold: threshold,
+      );
+
+      await secureStorageInterface.write(
+        key: Wallet.mnemonicKey(walletId: info.walletId),
+        value: mnemonic,
+      );
+      await secureStorageInterface.write(
+        key: Wallet.mnemonicPassphraseKey(walletId: info.walletId),
+        value: "",
+      );
+      await _saveSerializedKeys(serializedKeys);
+      await _saveRecoveryString(recoveryString);
+      await _saveMultisigId(multisigId);
+      await _saveMultisigConfig(multisigConfig);
+
+      await mainDB.isar.frostWalletInfo.put(frostWalletInfo);
+
+      final keys = frost.deserializeKeys(keys: serializedKeys);
+
+      final addressString = frost.addressForKeys(
+        network: cryptoCurrency.network == CryptoCurrencyNetwork.main
+            ? Network.Mainnet
+            : Network.Testnet,
+        keys: keys,
+      );
+
+      final publicKey = frost.scriptPubKeyForKeys(keys: keys);
+
+      final address = Address(
+        walletId: info.walletId,
+        value: addressString,
+        publicKey: publicKey.toUint8ListFromHex,
+        derivationIndex: 0,
+        derivationPath: null,
+        subType: AddressSubType.receiving,
+        type: AddressType.unknown,
+      );
+
+      await mainDB.putAddresses([address]);
+    } catch (e, s) {
+      Logging.instance.log(
+        "Exception rethrown from initializeNewFrost(): $e\n$s",
+        level: LogLevel.Fatal,
+      );
+      rethrow;
+    }
+  }
+
+  Future<TxData> frostCreateSignConfig({
+    required TxData txData,
+    required String changeAddress,
+    required int feePerWeight,
+  }) async {
+    try {
+      if (txData.recipients == null || txData.recipients!.isEmpty) {
+        throw Exception("No recipients found!");
+      }
+
+      final total = txData.recipients!
+          .map((e) => e.amount)
+          .reduce((value, e) => value += e);
+
+      final utxos = await mainDB
+          .getUTXOs(walletId)
+          .filter()
+          .isBlockedEqualTo(false)
+          .findAll();
+
+      if (utxos.isEmpty) {
+        throw Exception("No UTXOs found");
+      } else {
+        final currentHeight = await chainHeight;
+        utxos.removeWhere(
+          (e) => !e.isConfirmed(
+            currentHeight,
+            cryptoCurrency.minConfirms,
+          ),
+        );
+        if (utxos.isEmpty) {
+          throw Exception("No confirmed UTXOs found");
+        }
+      }
+
+      if (total.raw >
+          utxos.map((e) => BigInt.from(e.value)).reduce((v, e) => v += e)) {
+        throw Exception("Insufficient available funds");
+      }
+
+      Amount sum = Amount.zeroWith(
+        fractionDigits: cryptoCurrency.fractionDigits,
+      );
+      final Set<UTXO> utxosToUse = {};
+      for (final utxo in utxos) {
+        sum += Amount(
+          rawValue: BigInt.from(utxo.value),
+          fractionDigits: cryptoCurrency.fractionDigits,
+        );
+        utxosToUse.add(utxo);
+        if (sum > total) {
+          break;
+        }
+      }
+
+      final serializedKeys = await _getSerializedKeys();
+      final keys = frost.deserializeKeys(keys: serializedKeys!);
+
+      final int network = cryptoCurrency.network == CryptoCurrencyNetwork.main
+          ? Network.Mainnet
+          : Network.Testnet;
+
+      final publicKey = frost
+          .scriptPubKeyForKeys(
+            keys: keys,
+          )
+          .toUint8ListFromHex;
+
+      final config = Frost.createSignConfig(
+        network: network,
+        inputs: utxosToUse
+            .map((e) => (
+                  utxo: e,
+                  scriptPubKey: publicKey,
+                ))
+            .toList(),
+        outputs: txData.recipients!,
+        changeAddress: (await getCurrentReceivingAddress())!.value,
+        feePerWeight: feePerWeight,
+      );
+
+      return txData.copyWith(frostMSConfig: config, utxos: utxosToUse);
+    } catch (_) {
+      rethrow;
+    }
+  }
+
+  Future<
+      ({
+        Pointer<TransactionSignMachineWrapper> machinePtr,
+        String preprocess,
+      })> frostAttemptSignConfig({
+    required String config,
+  }) async {
+    final int network = cryptoCurrency.network == CryptoCurrencyNetwork.main
+        ? Network.Mainnet
+        : Network.Testnet;
+    final serializedKeys = await _getSerializedKeys();
+
+    return Frost.attemptSignConfig(
+      network: network,
+      config: config,
+      serializedKeys: serializedKeys!,
+    );
+  }
+
+  Future<void> updateWithResharedData({
+    required String serializedKeys,
+    required String multisigConfig,
+    required bool isNewWallet,
+  }) async {
+    await _saveSerializedKeys(serializedKeys);
+    await _saveMultisigConfig(multisigConfig);
+
+    await _updateThreshold(
+      frost.getThresholdFromKeys(
+        serializedKeys: serializedKeys,
+      ),
+    );
+
+    final myNameIndex = frost.getParticipantIndexFromKeys(
+      serializedKeys: serializedKeys,
+    );
+    final participants = Frost.getParticipants(
+      multisigConfig: multisigConfig,
+    );
+    final myName = participants[myNameIndex];
+
+    await _updateParticipants(participants);
+    await _updateMyName(myName);
+
+    if (isNewWallet) {
+      await recover(
+        serializedKeys: serializedKeys,
+        multisigConfig: multisigConfig,
+        isRescan: false,
+      );
+    }
+  }
+
+  Future<Amount> sweepAllEstimate(int feeRate) async {
+    int available = 0;
+    int inputCount = 0;
+    final height = await chainHeight;
+    for (final output in (await mainDB.getUTXOs(walletId).findAll())) {
+      if (!output.isBlocked &&
+          output.isConfirmed(height, cryptoCurrency.minConfirms)) {
+        available += output.value;
+        inputCount++;
+      }
+    }
+
+    // transaction will only have 1 output minus the fee
+    final estimatedFee = _roughFeeEstimate(inputCount, 1, feeRate);
+
+    return Amount(
+          rawValue: BigInt.from(available),
+          fractionDigits: cryptoCurrency.fractionDigits,
+        ) -
+        estimatedFee;
+  }
+
+  // int _estimateTxFee({required int vSize, required int feeRatePerKB}) {
+  //   return vSize * (feeRatePerKB / 1000).ceil();
+  // }
+
+  Amount _roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
+    return Amount(
+      rawValue: BigInt.from(
+          ((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() *
+              (feeRatePerKB / 1000).ceil()),
+      fractionDigits: cryptoCurrency.fractionDigits,
+    );
+  }
+
+  // ==================== Overrides ============================================
+
   @override
   int get isarTransactionVersion => 2;
 
-  BitcoinFrostWallet(CryptoCurrencyNetwork network)
-      : super(BitcoinFrost(network) as T);
-
   @override
   FilterOperation? get changeAddressFilterOperation => FilterGroup.and(
         [
@@ -62,62 +324,321 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T>
         ],
       );
 
-  // Future<List<Address>> fetchAddressesForElectrumXScan() async {
-  //   final allAddresses = await mainDB
-  //       .getAddresses(walletId)
-  //       .filter()
-  //       .typeEqualTo(AddressType.frostMS)
-  //       .and()
-  //       .group(
-  //         (q) => q
-  //             .subTypeEqualTo(AddressSubType.receiving)
-  //             .or()
-  //             .subTypeEqualTo(AddressSubType.change),
-  //       )
-  //       .findAll();
-  //   return allAddresses;
-  // }
+  @override
+  Future<void> updateTransactions() async {
+    final myAddress = (await getCurrentReceivingAddress())!;
+
+    final scriptHash = cryptoCurrency.pubKeyToScriptHash(
+      pubKey: Uint8List.fromList(myAddress.publicKey),
+    );
+    final allTxHashes =
+        (await electrumXClient.getHistory(scripthash: scriptHash)).toSet();
+
+    final currentHeight = await chainHeight;
+    final coin = info.coin;
+
+    List<Map<String, dynamic>> allTransactions = [];
+
+    for (final txHash in allTxHashes) {
+      final storedTx = await mainDB.isar.transactionV2s
+          .where()
+          .walletIdEqualTo(walletId)
+          .filter()
+          .txidEqualTo(txHash["tx_hash"] as String)
+          .findFirst();
+
+      if (storedTx == null ||
+          !storedTx.isConfirmed(currentHeight, cryptoCurrency.minConfirms)) {
+        final tx = await electrumXCachedClient.getTransaction(
+          txHash: txHash["tx_hash"] as String,
+          verbose: true,
+          coin: coin,
+        );
+
+        if (!_duplicateTxCheck(allTransactions, tx["txid"] as String)) {
+          tx["height"] = txHash["height"];
+          allTransactions.add(tx);
+        }
+      }
+    }
+
+    // Parse all new txs.
+    final List<TransactionV2> txns = [];
+    for (final txData in allTransactions) {
+      bool wasSentFromThisWallet = false;
+      // Set to true if any inputs were detected as owned by this wallet.
+
+      bool wasReceivedInThisWallet = false;
+      // Set to true if any outputs were detected as owned by this wallet.
+
+      // Parse inputs.
+      BigInt amountReceivedInThisWallet = BigInt.zero;
+      final List<InputV2> inputs = [];
+      for (final jsonInput in txData["vin"] as List) {
+        final map = Map<String, dynamic>.from(jsonInput as Map);
+
+        final List<String> addresses = [];
+        String valueStringSats = "0";
+        OutpointV2? outpoint;
+
+        final coinbase = map["coinbase"] as String?;
+
+        if (coinbase == null) {
+          // Not a coinbase (ie a typical input).
+          final txid = map["txid"] as String;
+          final vout = map["vout"] as int;
+
+          final inputTx = await electrumXCachedClient.getTransaction(
+            txHash: txid,
+            coin: cryptoCurrency.coin,
+          );
+
+          final prevOutJson = Map<String, dynamic>.from(
+              (inputTx["vout"] as List).firstWhere((e) => e["n"] == vout)
+                  as Map);
+
+          final prevOut = OutputV2.fromElectrumXJson(
+            prevOutJson,
+            decimalPlaces: cryptoCurrency.fractionDigits,
+            isFullAmountNotSats: true,
+            walletOwns: false, // Doesn't matter here as this is not saved.
+          );
+
+          outpoint = OutpointV2.isarCantDoRequiredInDefaultConstructor(
+            txid: txid,
+            vout: vout,
+          );
+          valueStringSats = prevOut.valueStringSats;
+          addresses.addAll(prevOut.addresses);
+        }
+
+        InputV2 input = InputV2.fromElectrumxJson(
+          json: map,
+          outpoint: outpoint,
+          valueStringSats: valueStringSats,
+          addresses: addresses,
+          coinbase: coinbase,
+          // Need addresses before we can know if the wallet owns this input.
+          walletOwns: false,
+        );
+
+        // Check if input was from this wallet.
+        if (input.addresses.contains(myAddress.value)) {
+          wasSentFromThisWallet = true;
+          input = input.copyWith(walletOwns: true);
+        }
+
+        inputs.add(input);
+      }
+
+      // Parse outputs.
+      final List<OutputV2> outputs = [];
+      for (final outputJson in txData["vout"] as List) {
+        OutputV2 output = OutputV2.fromElectrumXJson(
+          Map<String, dynamic>.from(outputJson as Map),
+          decimalPlaces: cryptoCurrency.fractionDigits,
+          isFullAmountNotSats: true,
+          // Need addresses before we can know if the wallet owns this input.
+          walletOwns: false,
+        );
+
+        // If output was to my wallet, add value to amount received.
+        if (output.addresses.contains(myAddress.value)) {
+          wasReceivedInThisWallet = true;
+          amountReceivedInThisWallet += output.value;
+          output = output.copyWith(walletOwns: true);
+        }
+
+        outputs.add(output);
+      }
+
+      final totalOut = outputs
+          .map((e) => e.value)
+          .fold(BigInt.zero, (value, element) => value + element);
+
+      TransactionType type;
+      TransactionSubType subType = TransactionSubType.none;
+      if (outputs.length > 1 && inputs.isNotEmpty) {
+        for (int i = 0; i < outputs.length; i++) {
+          List<String>? scriptChunks = outputs[i].scriptPubKeyAsm?.split(" ");
+          if (scriptChunks?.length == 2 && scriptChunks?[0] == "OP_RETURN") {
+            final blindedPaymentCode = scriptChunks![1];
+            final bytes = blindedPaymentCode.toUint8ListFromHex;
+
+            // https://en.bitcoin.it/wiki/BIP_0047#Sending
+            if (bytes.length == 80 && bytes.first == 1) {
+              subType = TransactionSubType.bip47Notification;
+              break;
+            }
+          }
+        }
+      }
+
+      // At least one input was owned by this wallet.
+      if (wasSentFromThisWallet) {
+        type = TransactionType.outgoing;
+
+        if (wasReceivedInThisWallet) {
+          if (amountReceivedInThisWallet == totalOut) {
+            // Definitely sent all to self.
+            type = TransactionType.sentToSelf;
+          } else if (amountReceivedInThisWallet == BigInt.zero) {
+            // Most likely just a typical send, do nothing here yet.
+          }
+        }
+      } else if (wasReceivedInThisWallet) {
+        // Only found outputs owned by this wallet.
+        type = TransactionType.incoming;
+      } else {
+        Logging.instance.log(
+          "Unexpected tx found (ignoring it): $txData",
+          level: LogLevel.Error,
+        );
+        continue;
+      }
+
+      final tx = TransactionV2(
+        walletId: walletId,
+        blockHash: txData["blockhash"] as String?,
+        hash: txData["hash"] as String,
+        txid: txData["txid"] as String,
+        height: txData["height"] as int?,
+        version: txData["version"] as int,
+        timestamp: txData["blocktime"] as int? ??
+            DateTime.timestamp().millisecondsSinceEpoch ~/ 1000,
+        inputs: List.unmodifiable(inputs),
+        outputs: List.unmodifiable(outputs),
+        type: type,
+        subType: subType,
+        otherData: null,
+      );
+
+      txns.add(tx);
+    }
+
+    await mainDB.updateOrPutTransactionV2s(txns);
+  }
 
   @override
-  Future<void> updateTransactions() {
-    // TODO: implement updateTransactions
-    throw UnimplementedError();
+  Future<void> checkSaveInitialReceivingAddress() async {
+    // should not be needed for frost as we explicitly save the address
+    // on new init and restore
   }
 
-  int estimateTxFee({required int vSize, required int feeRatePerKB}) {
-    return vSize * (feeRatePerKB / 1000).ceil();
+  @override
+  Future<TxData> confirmSend({required TxData txData}) async {
+    try {
+      Logging.instance.log("confirmSend txData: $txData", level: LogLevel.Info);
+
+      final hex = txData.raw!;
+
+      final txHash = await electrumXClient.broadcastTransaction(rawTx: hex);
+      Logging.instance.log("Sent txHash: $txHash", level: LogLevel.Info);
+
+      // mark utxos as used
+      final usedUTXOs = txData.utxos!.map((e) => e.copyWith(used: true));
+      await mainDB.putUTXOs(usedUTXOs.toList());
+
+      txData = txData.copyWith(
+        utxos: usedUTXOs.toSet(),
+        txHash: txHash,
+        txid: txHash,
+      );
+
+      return txData;
+    } catch (e, s) {
+      Logging.instance.log("Exception rethrown from confirmSend(): $e\n$s",
+          level: LogLevel.Error);
+      rethrow;
+    }
   }
 
-  Amount roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
-    return Amount(
-      rawValue: BigInt.from(
-          ((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() *
-              (feeRatePerKB / 1000).ceil()),
+  @override
+  Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
+    final available = info.cachedBalance.spendable;
+
+    if (available == amount) {
+      return amount - (await sweepAllEstimate(feeRate));
+    } else if (amount <= Amount.zero || amount > available) {
+      return _roughFeeEstimate(1, 2, feeRate);
+    }
+
+    Amount runningBalance = Amount(
+      rawValue: BigInt.zero,
       fractionDigits: cryptoCurrency.fractionDigits,
     );
+    int inputCount = 0;
+    for (final output in (await mainDB.getUTXOs(walletId).findAll())) {
+      if (!output.isBlocked) {
+        runningBalance += Amount(
+          rawValue: BigInt.from(output.value),
+          fractionDigits: cryptoCurrency.fractionDigits,
+        );
+        inputCount++;
+        if (runningBalance > amount) {
+          break;
+        }
+      }
+    }
+
+    final oneOutPutFee = _roughFeeEstimate(inputCount, 1, feeRate);
+    final twoOutPutFee = _roughFeeEstimate(inputCount, 2, feeRate);
+
+    if (runningBalance - amount > oneOutPutFee) {
+      if (runningBalance - amount > oneOutPutFee + cryptoCurrency.dustLimit) {
+        final change = runningBalance - amount - twoOutPutFee;
+        if (change > cryptoCurrency.dustLimit &&
+            runningBalance - amount - change == twoOutPutFee) {
+          return runningBalance - amount - change;
+        } else {
+          return runningBalance - amount;
+        }
+      } else {
+        return runningBalance - amount;
+      }
+    } else if (runningBalance - amount == oneOutPutFee) {
+      return oneOutPutFee;
+    } else {
+      return twoOutPutFee;
+    }
   }
 
   @override
-  Future<void> checkSaveInitialReceivingAddress() {
-    // TODO: implement checkSaveInitialReceivingAddress
-    throw UnimplementedError();
-  }
+  Future<FeeObject> get fees async {
+    try {
+      // adjust numbers for different speeds?
+      const int f = 1, m = 5, s = 20;
 
-  @override
-  Future<TxData> confirmSend({required TxData txData}) {
-    // TODO: implement confirmSend
-    throw UnimplementedError();
-  }
+      final fast = await electrumXClient.estimateFee(blocks: f);
+      final medium = await electrumXClient.estimateFee(blocks: m);
+      final slow = await electrumXClient.estimateFee(blocks: s);
 
-  @override
-  Future<Amount> estimateFeeFor(Amount amount, int feeRate) {
-    // TODO: implement estimateFeeFor
-    throw UnimplementedError();
-  }
+      final feeObject = FeeObject(
+        numberOfBlocksFast: f,
+        numberOfBlocksAverage: m,
+        numberOfBlocksSlow: s,
+        fast: Amount.fromDecimal(
+          fast,
+          fractionDigits: cryptoCurrency.fractionDigits,
+        ).raw.toInt(),
+        medium: Amount.fromDecimal(
+          medium,
+          fractionDigits: cryptoCurrency.fractionDigits,
+        ).raw.toInt(),
+        slow: Amount.fromDecimal(
+          slow,
+          fractionDigits: cryptoCurrency.fractionDigits,
+        ).raw.toInt(),
+      );
 
-  @override
-  // TODO: implement fees
-  Future<FeeObject> get fees => throw UnimplementedError();
+      Logging.instance.log("fetched fees: $feeObject", level: LogLevel.Info);
+      return feeObject;
+    } catch (e) {
+      Logging.instance
+          .log("Exception rethrown from _getFees(): $e", level: LogLevel.Error);
+      rethrow;
+    }
+  }
 
   @override
   Future<TxData> prepareSend({required TxData txData}) {
@@ -138,6 +659,16 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T>
       );
     }
 
+    final coin = info.coin;
+
+    GlobalEventBus.instance.fire(
+      WalletSyncStatusChangedEvent(
+        WalletSyncStatus.syncing,
+        walletId,
+        coin,
+      ),
+    );
+
     try {
       await refreshMutex.protect(() async {
         if (!isRescan) {
@@ -146,12 +677,16 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T>
                 multisigConfig: multisigConfig,
               )
               .toHex;
-          final knownSalts = frostInfo.knownSalts;
+          final knownSalts = _getKnownSalts();
           if (knownSalts.contains(salt)) {
             throw Exception("Known frost multisig salt found!");
           }
           knownSalts.add(salt);
-          await frostInfo.updateKnownSalts(knownSalts, isar: mainDB.isar);
+          await _updateKnownSalts(knownSalts);
+        } else {
+          // clear cache
+          await electrumXCachedClient.clearSharedTransactionCache(coin: coin);
+          await mainDB.deleteWalletBlockchainData(walletId);
         }
 
         final keys = frost.deserializeKeys(keys: serializedKeys);
@@ -180,12 +715,27 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T>
         await mainDB.updateOrPutAddresses([address]);
       });
 
+      GlobalEventBus.instance.fire(
+        WalletSyncStatusChangedEvent(
+          WalletSyncStatus.synced,
+          walletId,
+          coin,
+        ),
+      );
+
       unawaited(refresh());
     } catch (e, s) {
       Logging.instance.log(
         "recoverFromSerializedKeys failed: $e\n$s",
         level: LogLevel.Fatal,
       );
+      GlobalEventBus.instance.fire(
+        WalletSyncStatusChangedEvent(
+          WalletSyncStatus.unableToSync,
+          walletId,
+          coin,
+        ),
+      );
       rethrow;
     }
   }
@@ -309,12 +859,15 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T>
 
   // =================== Secure storage ========================================
 
-  Future<String?> get getSerializedKeys async =>
+  Future<String?> _getSerializedKeys() async =>
       await secureStorageInterface.read(
         key: "{$walletId}_serializedFROSTKeys",
       );
-  Future<void> _saveSerializedKeys(String keys) async {
-    final current = await getSerializedKeys;
+
+  Future<void> _saveSerializedKeys(
+    String keys,
+  ) async {
+    final current = await _getSerializedKeys();
 
     if (current == null) {
       // do nothing
@@ -334,20 +887,24 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T>
     );
   }
 
-  Future<String?> get getSerializedKeysPrevGen async =>
+  Future<String?> _getSerializedKeysPrevGen() async =>
       await secureStorageInterface.read(
         key: "{$walletId}_serializedFROSTKeysPrevGen",
       );
 
-  Future<String?> get multisigConfig async => await secureStorageInterface.read(
+  Future<String?> _multisigConfig() async => await secureStorageInterface.read(
         key: "{$walletId}_multisigConfig",
       );
-  Future<String?> get multisigConfigPrevGen async =>
+
+  Future<String?> _multisigConfigPrevGen() async =>
       await secureStorageInterface.read(
         key: "{$walletId}_multisigConfigPrevGen",
       );
-  Future<void> _saveMultisigConfig(String multisigConfig) async {
-    final current = await this.multisigConfig;
+
+  Future<void> _saveMultisigConfig(
+    String multisigConfig,
+  ) async {
+    final current = await _multisigConfig();
 
     if (current == null) {
       // do nothing
@@ -367,7 +924,7 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T>
     );
   }
 
-  Future<Uint8List?> get multisigId async {
+  Future<Uint8List?> _multisigId() async {
     final id = await secureStorageInterface.read(
       key: "{$walletId}_multisigIdFROST",
     );
@@ -378,21 +935,92 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T>
     }
   }
 
-  Future<void> saveMultisigId(Uint8List id) async =>
+  Future<void> _saveMultisigId(
+    Uint8List id,
+  ) async =>
       await secureStorageInterface.write(
         key: "{$walletId}_multisigIdFROST",
         value: id.toHex,
       );
 
-  Future<String?> get recoveryString async => await secureStorageInterface.read(
+  Future<String?> _recoveryString() async => await secureStorageInterface.read(
         key: "{$walletId}_recoveryStringFROST",
       );
-  Future<void> saveRecoveryString(String recoveryString) async =>
+
+  Future<void> _saveRecoveryString(
+    String recoveryString,
+  ) async =>
       await secureStorageInterface.write(
         key: "{$walletId}_recoveryStringFROST",
         value: recoveryString,
       );
 
+  // =================== DB ====================================================
+
+  List<String> _getKnownSalts() => mainDB.isar.frostWalletInfo
+      .where()
+      .walletIdEqualTo(walletId)
+      .knownSaltsProperty()
+      .findFirstSync()!;
+
+  Future<void> _updateKnownSalts(List<String> knownSalts) async {
+    await mainDB.isar.writeTxn(() async {
+      final info = frostInfo;
+      await mainDB.isar.frostWalletInfo.delete(info.id);
+      await mainDB.isar.frostWalletInfo.put(
+        info.copyWith(knownSalts: knownSalts),
+      );
+    });
+  }
+
+  List<String> _getParticipants() => mainDB.isar.frostWalletInfo
+      .where()
+      .walletIdEqualTo(walletId)
+      .participantsProperty()
+      .findFirstSync()!;
+
+  Future<void> _updateParticipants(List<String> participants) async {
+    await mainDB.isar.writeTxn(() async {
+      final info = frostInfo;
+      await mainDB.isar.frostWalletInfo.delete(info.id);
+      await mainDB.isar.frostWalletInfo.put(
+        info.copyWith(participants: participants),
+      );
+    });
+  }
+
+  int _getThreshold() => mainDB.isar.frostWalletInfo
+      .where()
+      .walletIdEqualTo(walletId)
+      .thresholdProperty()
+      .findFirstSync()!;
+
+  Future<void> _updateThreshold(int threshold) async {
+    await mainDB.isar.writeTxn(() async {
+      final info = frostInfo;
+      await mainDB.isar.frostWalletInfo.delete(info.id);
+      await mainDB.isar.frostWalletInfo.put(
+        info.copyWith(threshold: threshold),
+      );
+    });
+  }
+
+  String _getMyName() => mainDB.isar.frostWalletInfo
+      .where()
+      .walletIdEqualTo(walletId)
+      .myNameProperty()
+      .findFirstSync()!;
+
+  Future<void> _updateMyName(String myName) async {
+    await mainDB.isar.writeTxn(() async {
+      final info = frostInfo;
+      await mainDB.isar.frostWalletInfo.delete(info.id);
+      await mainDB.isar.frostWalletInfo.put(
+        info.copyWith(myName: myName),
+      );
+    });
+  }
+
   // =================== Private ===============================================
 
   Future<ElectrumXNode> _getCurrentElectrumXNode() async {
@@ -430,6 +1058,16 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T>
     );
   }
 
+  bool _duplicateTxCheck(
+      List<Map<String, dynamic>> allTransactions, String txid) {
+    for (int i = 0; i < allTransactions.length; i++) {
+      if (allTransactions[i]["txid"] == txid) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   Future<UTXO> _parseUTXO({
     required Map<String, dynamic> jsonUTXO,
   }) async {
@@ -443,12 +1081,12 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T>
 
     final outputs = txn["vout"] as List;
 
-    String? scriptPubKey;
+    // String? scriptPubKey;
     String? utxoOwnerAddress;
     // get UTXO owner address
     for (final output in outputs) {
       if (output["n"] == vout) {
-        scriptPubKey = output["scriptPubKey"]?["hex"] as String?;
+        // scriptPubKey = output["scriptPubKey"]?["hex"] as String?;
         utxoOwnerAddress =
             output["scriptPubKey"]?["addresses"]?[0] as String? ??
                 output["scriptPubKey"]?["address"] as String?;
diff --git a/lib/wallets/wallet/wallet.dart b/lib/wallets/wallet/wallet.dart
index 711a895a1..959b7b635 100644
--- a/lib/wallets/wallet/wallet.dart
+++ b/lib/wallets/wallet/wallet.dart
@@ -289,7 +289,7 @@ abstract class Wallet<T extends CryptoCurrency> {
     wallet.prefs = prefs;
     wallet.nodeService = nodeService;
 
-    if (wallet is ElectrumXInterface) {
+    if (wallet is ElectrumXInterface || wallet is BitcoinFrostWallet) {
       // initialize electrumx instance
       await wallet.updateNode();
     }

From 6a7ec2d5d26e26ad199dcc56400794a9c04d17da Mon Sep 17 00:00:00 2001
From: julian <julian@cypherstack.com>
Date: Fri, 19 Jan 2024 17:44:01 -0600
Subject: [PATCH 06/57] untested: Bitcoin frost

---
 crypto_plugins/frostdart                      |   2 +-
 ...irm_new_frost_ms_wallet_creation_view.dart | 343 +++++++++++++
 .../new/create_new_frost_ms_wallet_view.dart  | 285 +++++++++++
 .../new/frost_share_commitments_view.dart     | 443 ++++++++++++++++
 .../frost_ms/new/frost_share_shares_view.dart | 409 +++++++++++++++
 .../new/import_new_frost_ms_wallet_view.dart  | 386 ++++++++++++++
 .../new/share_new_multisig_config_view.dart   | 162 ++++++
 .../restore/restore_frost_ms_wallet_view.dart | 478 ++++++++++++++++++
 .../name_your_wallet_view.dart                | 216 +++++---
 .../frost_ms/frost_ms_options_view.dart       | 162 ++++++
 .../frost_ms/frost_participants_view.dart     | 119 +++++
 .../resharing/finish_resharing_view.dart      | 433 ++++++++++++++++
 .../step_1a/begin_reshare_config_view.dart    | 196 +++++++
 .../step_1a/complete_reshare_config_view.dart | 335 ++++++++++++
 .../step_1a/display_reshare_config_view.dart  | 214 ++++++++
 .../step_1b/import_reshare_config_view.dart   | 338 +++++++++++++
 .../involved/step_2/begin_resharing_view.dart | 439 ++++++++++++++++
 .../step_2/continue_resharing_view.dart       | 429 ++++++++++++++++
 .../new/new_continue_sharing_view.dart        | 204 ++++++++
 .../new/new_import_resharer_config_view.dart  | 426 ++++++++++++++++
 .../new/new_start_resharing_view.dart         | 379 ++++++++++++++
 .../resharing/verify_updated_wallet_view.dart | 315 ++++++++++++
 .../frost_wallet/frost_wallet_providers.dart  | 103 ++++
 lib/route_generator.dart                      | 333 ++++++++++++
 lib/themes/coin_card_provider.dart            |  14 +
 lib/themes/coin_icon_provider.dart            |   7 +
 lib/themes/coin_image_provider.dart           |  14 +
 lib/utilities/enums/coin_enum.dart            |  20 +
 .../models/incomplete_frost_wallet.dart       |  42 ++
 .../wallet/impl/bitcoin_frost_wallet.dart     |   8 +-
 lib/widgets/detail_item.dart                  |  90 ++++
 .../dialogs/frost_interruption_dialog.dart    |  70 +++
 lib/widgets/stack_dialog.dart                 |  12 +-
 33 files changed, 7349 insertions(+), 77 deletions(-)
 create mode 100644 lib/pages/add_wallet_views/frost_ms/new/confirm_new_frost_ms_wallet_creation_view.dart
 create mode 100644 lib/pages/add_wallet_views/frost_ms/new/create_new_frost_ms_wallet_view.dart
 create mode 100644 lib/pages/add_wallet_views/frost_ms/new/frost_share_commitments_view.dart
 create mode 100644 lib/pages/add_wallet_views/frost_ms/new/frost_share_shares_view.dart
 create mode 100644 lib/pages/add_wallet_views/frost_ms/new/import_new_frost_ms_wallet_view.dart
 create mode 100644 lib/pages/add_wallet_views/frost_ms/new/share_new_multisig_config_view.dart
 create mode 100644 lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart
 create mode 100644 lib/pages/settings_views/wallet_settings_view/frost_ms/frost_ms_options_view.dart
 create mode 100644 lib/pages/settings_views/wallet_settings_view/frost_ms/frost_participants_view.dart
 create mode 100644 lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/finish_resharing_view.dart
 create mode 100644 lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/begin_reshare_config_view.dart
 create mode 100644 lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/complete_reshare_config_view.dart
 create mode 100644 lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/display_reshare_config_view.dart
 create mode 100644 lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1b/import_reshare_config_view.dart
 create mode 100644 lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_2/begin_resharing_view.dart
 create mode 100644 lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_2/continue_resharing_view.dart
 create mode 100644 lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_continue_sharing_view.dart
 create mode 100644 lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_import_resharer_config_view.dart
 create mode 100644 lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_start_resharing_view.dart
 create mode 100644 lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/verify_updated_wallet_view.dart
 create mode 100644 lib/providers/frost_wallet/frost_wallet_providers.dart
 create mode 100644 lib/wallets/models/incomplete_frost_wallet.dart
 create mode 100644 lib/widgets/detail_item.dart
 create mode 100644 lib/widgets/dialogs/frost_interruption_dialog.dart

diff --git a/crypto_plugins/frostdart b/crypto_plugins/frostdart
index 2fa7e4666..0fbc038a2 160000
--- a/crypto_plugins/frostdart
+++ b/crypto_plugins/frostdart
@@ -1 +1 @@
-Subproject commit 2fa7e46669a023d270cad4552b5151b138738790
+Subproject commit 0fbc038a262e3c2d82c7c6e34e194e9a47011d91
diff --git a/lib/pages/add_wallet_views/frost_ms/new/confirm_new_frost_ms_wallet_creation_view.dart b/lib/pages/add_wallet_views/frost_ms/new/confirm_new_frost_ms_wallet_creation_view.dart
new file mode 100644
index 000000000..08018b43c
--- /dev/null
+++ b/lib/pages/add_wallet_views/frost_ms/new/confirm_new_frost_ms_wallet_creation_view.dart
@@ -0,0 +1,343 @@
+import 'dart:async';
+import 'dart:typed_data';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:stackwallet/notifications/show_flush_bar.dart';
+import 'package:stackwallet/pages/home_view/home_view.dart';
+import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
+import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
+import 'package:stackwallet/providers/db/main_db_provider.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/providers/global/node_service_provider.dart';
+import 'package:stackwallet/providers/global/prefs_provider.dart';
+import 'package:stackwallet/providers/global/secure_store_provider.dart';
+import 'package:stackwallet/providers/global/wallets_provider.dart';
+import 'package:stackwallet/services/frost.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/assets.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
+import 'package:stackwallet/wallets/wallet/wallet.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/detail_item.dart';
+import 'package:stackwallet/widgets/dialogs/frost_interruption_dialog.dart';
+import 'package:stackwallet/widgets/loading_indicator.dart';
+
+import '../../../../wallets/isar/models/wallet_info.dart';
+
+class ConfirmNewFrostMSWalletCreationView extends ConsumerStatefulWidget {
+  const ConfirmNewFrostMSWalletCreationView({
+    super.key,
+    required this.walletName,
+    required this.coin,
+  });
+
+  static const String routeName = "/confirmNewFrostMSWalletCreationView";
+
+  final String walletName;
+  final Coin coin;
+
+  @override
+  ConsumerState<ConfirmNewFrostMSWalletCreationView> createState() =>
+      _ConfirmNewFrostMSWalletCreationViewState();
+}
+
+class _ConfirmNewFrostMSWalletCreationViewState
+    extends ConsumerState<ConfirmNewFrostMSWalletCreationView> {
+  late final String seed, recoveryString, serializedKeys, multisigConfig;
+  late final Uint8List multisigId;
+
+  @override
+  void initState() {
+    seed = ref.read(pFrostStartKeyGenData.state).state!.seed;
+    serializedKeys =
+        ref.read(pFrostCompletedKeyGenData.state).state!.serializedKeys;
+    recoveryString =
+        ref.read(pFrostCompletedKeyGenData.state).state!.recoveryString;
+    multisigId = ref.read(pFrostCompletedKeyGenData.state).state!.multisigId;
+    multisigConfig = ref.read(pFrostMultisigConfig.state).state!;
+
+    super.initState();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return WillPopScope(
+      onWillPop: () async {
+        await showDialog<void>(
+          context: context,
+          builder: (_) => FrostInterruptionDialog(
+            type: FrostInterruptionDialogType.walletCreation,
+            popUntilOnYesRouteName:
+                Util.isDesktop ? DesktopHomeView.routeName : HomeView.routeName,
+          ),
+        );
+
+        return false;
+      },
+      child: ConditionalParent(
+        condition: Util.isDesktop,
+        builder: (child) => DesktopScaffold(
+          background: Theme.of(context).extension<StackColors>()!.background,
+          appBar: DesktopAppBar(
+            isCompactHeight: false,
+            leading: AppBarBackButton(
+              onPressed: () async {
+                await showDialog<void>(
+                  context: context,
+                  builder: (_) => const FrostInterruptionDialog(
+                    type: FrostInterruptionDialogType.walletCreation,
+                    popUntilOnYesRouteName: DesktopHomeView.routeName,
+                  ),
+                );
+              },
+            ),
+            trailing: ExitToMyStackButton(
+              onPressed: () async {
+                await showDialog<void>(
+                  context: context,
+                  builder: (_) => const FrostInterruptionDialog(
+                    type: FrostInterruptionDialogType.walletCreation,
+                    popUntilOnYesRouteName: DesktopHomeView.routeName,
+                  ),
+                );
+              },
+            ),
+          ),
+          body: SizedBox(
+            width: 480,
+            child: child,
+          ),
+        ),
+        child: ConditionalParent(
+          condition: !Util.isDesktop,
+          builder: (child) => Background(
+            child: Scaffold(
+              backgroundColor:
+                  Theme.of(context).extension<StackColors>()!.background,
+              appBar: AppBar(
+                leading: AppBarBackButton(
+                  onPressed: () async {
+                    await showDialog<void>(
+                      context: context,
+                      builder: (_) => const FrostInterruptionDialog(
+                        type: FrostInterruptionDialogType.walletCreation,
+                        popUntilOnYesRouteName: HomeView.routeName,
+                      ),
+                    );
+                  },
+                ),
+                title: Text(
+                  "Finalize FROST multisig wallet",
+                  style: STextStyles.navBarTitle(context),
+                ),
+              ),
+              body: SafeArea(
+                child: LayoutBuilder(
+                  builder: (context, constraints) {
+                    return SingleChildScrollView(
+                      child: ConstrainedBox(
+                        constraints: BoxConstraints(
+                          minHeight: constraints.maxHeight,
+                        ),
+                        child: IntrinsicHeight(
+                          child: Padding(
+                            padding: const EdgeInsets.all(16),
+                            child: child,
+                          ),
+                        ),
+                      ),
+                    );
+                  },
+                ),
+              ),
+            ),
+          ),
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              Text(
+                "Ensure your multisig ID matches that of each other participant",
+                style: STextStyles.pageTitleH2(context),
+              ),
+              const _Div(),
+              DetailItem(
+                title: "ID",
+                detail: multisigId.toString(),
+                button: Util.isDesktop
+                    ? IconCopyButton(
+                        data: multisigId.toString(),
+                      )
+                    : SimpleCopyButton(
+                        data: multisigId.toString(),
+                      ),
+              ),
+              const _Div(),
+              const _Div(),
+              Text(
+                "Back up your keys and config",
+                style: STextStyles.pageTitleH2(context),
+              ),
+              const _Div(),
+              DetailItem(
+                title: "Multisig Config",
+                detail: multisigConfig,
+                button: Util.isDesktop
+                    ? IconCopyButton(
+                        data: multisigConfig,
+                      )
+                    : SimpleCopyButton(
+                        data: multisigConfig,
+                      ),
+              ),
+              const _Div(),
+              DetailItem(
+                title: "Keys",
+                detail: serializedKeys,
+                button: Util.isDesktop
+                    ? IconCopyButton(
+                        data: serializedKeys,
+                      )
+                    : SimpleCopyButton(
+                        data: serializedKeys,
+                      ),
+              ),
+              if (!Util.isDesktop) const Spacer(),
+              const _Div(),
+              PrimaryButton(
+                label: "Confirm",
+                onPressed: () async {
+                  bool progressPopped = false;
+                  try {
+                    unawaited(
+                      showDialog<dynamic>(
+                        context: context,
+                        barrierDismissible: false,
+                        useSafeArea: true,
+                        builder: (ctx) {
+                          return const Center(
+                            child: LoadingIndicator(
+                              width: 50,
+                              height: 50,
+                            ),
+                          );
+                        },
+                      ),
+                    );
+
+                    final info = WalletInfo.createNew(
+                      coin: widget.coin,
+                      name: widget.walletName,
+                    );
+
+                    final wallet = await Wallet.create(
+                      walletInfo: info,
+                      mainDB: ref.read(mainDBProvider),
+                      secureStorageInterface: ref.read(secureStoreProvider),
+                      nodeService: ref.read(nodeServiceChangeNotifierProvider),
+                      prefs: ref.read(prefsChangeNotifierProvider),
+                    );
+
+                    await (wallet as BitcoinFrostWallet).initializeNewFrost(
+                      mnemonic: seed,
+                      multisigConfig: multisigConfig,
+                      recoveryString: recoveryString,
+                      serializedKeys: serializedKeys,
+                      multisigId: multisigId,
+                      myName: ref.read(pFrostMyName.state).state!,
+                      participants: Frost.getParticipants(
+                        multisigConfig:
+                            ref.read(pFrostMultisigConfig.state).state!,
+                      ),
+                      threshold: Frost.getThreshold(
+                        multisigConfig:
+                            ref.read(pFrostMultisigConfig.state).state!,
+                      ),
+                    );
+
+                    await info.setMnemonicVerified(
+                      isar: ref.read(mainDBProvider).isar,
+                    );
+
+                    ref.read(pWallets).addWallet(wallet);
+
+                    // pop progress dialog
+                    if (mounted) {
+                      Navigator.pop(context);
+                      progressPopped = true;
+                    }
+
+                    if (mounted) {
+                      if (Util.isDesktop) {
+                        Navigator.of(context).popUntil(
+                          ModalRoute.withName(
+                            DesktopHomeView.routeName,
+                          ),
+                        );
+                      } else {
+                        unawaited(
+                          Navigator.of(context).pushNamedAndRemoveUntil(
+                            HomeView.routeName,
+                            (route) => false,
+                          ),
+                        );
+                      }
+
+                      ref.read(pFrostMultisigConfig.state).state = null;
+                      ref.read(pFrostStartKeyGenData.state).state = null;
+                      ref.read(pFrostSecretSharesData.state).state = null;
+
+                      unawaited(
+                        showFloatingFlushBar(
+                          type: FlushBarType.success,
+                          message: "Your wallet is set up.",
+                          iconAsset: Assets.svg.check,
+                          context: context,
+                        ),
+                      );
+                    }
+                  } catch (e, s) {
+                    Logging.instance.log(
+                      "$e\n$s",
+                      level: LogLevel.Fatal,
+                    );
+
+                    // pop progress dialog
+                    if (mounted && !progressPopped) {
+                      Navigator.pop(context);
+                      progressPopped = true;
+                    }
+                    // TODO: handle gracefully
+                    rethrow;
+                  }
+                },
+              ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+}
+
+class _Div extends StatelessWidget {
+  const _Div({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return const SizedBox(
+      height: 12,
+    );
+  }
+}
diff --git a/lib/pages/add_wallet_views/frost_ms/new/create_new_frost_ms_wallet_view.dart b/lib/pages/add_wallet_views/frost_ms/new/create_new_frost_ms_wallet_view.dart
new file mode 100644
index 000000000..b408b61ef
--- /dev/null
+++ b/lib/pages/add_wallet_views/frost_ms/new/create_new_frost_ms_wallet_view.dart
@@ -0,0 +1,285 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/share_new_multisig_config_view.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/services/frost.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+
+class CreateNewFrostMsWalletView extends ConsumerStatefulWidget {
+  const CreateNewFrostMsWalletView({
+    super.key,
+    required this.walletName,
+    required this.coin,
+  });
+
+  static const String routeName = "/createNewFrostMsWalletView";
+
+  final String walletName;
+  final Coin coin;
+
+  @override
+  ConsumerState<CreateNewFrostMsWalletView> createState() =>
+      _NewFrostMsWalletViewState();
+}
+
+class _NewFrostMsWalletViewState
+    extends ConsumerState<CreateNewFrostMsWalletView> {
+  final _thresholdController = TextEditingController();
+  final _participantsController = TextEditingController();
+
+  final List<TextEditingController> controllers = [];
+
+  int _participantsCount = 0;
+
+  String _validateInputData() {
+    final threshold = int.tryParse(_thresholdController.text);
+    if (threshold == null) {
+      return "Choose a threshold";
+    }
+
+    final partsCount = int.tryParse(_participantsController.text);
+    if (partsCount == null) {
+      return "Choose total number of participants";
+    }
+
+    if (threshold > partsCount) {
+      return "Threshold cannot be greater than the number of participants";
+    }
+
+    if (partsCount < 2) {
+      return "At least two participants required";
+    }
+
+    if (controllers.length != partsCount) {
+      return "Participants count error";
+    }
+
+    final hasEmptyParticipants = controllers
+        .map((e) => e.text.isEmpty)
+        .reduce((value, element) => value |= element);
+    if (hasEmptyParticipants) {
+      return "Participants must not be empty";
+    }
+
+    if (controllers.length != controllers.map((e) => e.text).toSet().length) {
+      return "Duplicate participant name found";
+    }
+
+    return "valid";
+  }
+
+  void _participantsCountChanged(String newValue) {
+    final count = int.tryParse(newValue);
+    if (count != null) {
+      if (count > _participantsCount) {
+        for (int i = _participantsCount; i < count; i++) {
+          controllers.add(TextEditingController());
+        }
+
+        _participantsCount = count;
+        setState(() {});
+      } else if (count < _participantsCount) {
+        for (int i = _participantsCount; i > count; i--) {
+          final last = controllers.removeLast();
+          last.dispose();
+        }
+
+        _participantsCount = count;
+        setState(() {});
+      }
+    }
+  }
+
+  @override
+  void dispose() {
+    _thresholdController.dispose();
+    _participantsController.dispose();
+    for (final e in controllers) {
+      e.dispose();
+    }
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return ConditionalParent(
+      condition: Util.isDesktop,
+      builder: (child) => DesktopScaffold(
+        background: Theme.of(context).extension<StackColors>()!.background,
+        appBar: const DesktopAppBar(
+          isCompactHeight: false,
+          leading: AppBarBackButton(),
+          trailing: ExitToMyStackButton(),
+        ),
+        body: SizedBox(
+          width: 480,
+          child: child,
+        ),
+      ),
+      child: ConditionalParent(
+        condition: !Util.isDesktop,
+        builder: (child) => Background(
+          child: Scaffold(
+            backgroundColor:
+                Theme.of(context).extension<StackColors>()!.background,
+            appBar: AppBar(
+              leading: AppBarBackButton(
+                onPressed: () {
+                  Navigator.of(context).pop();
+                },
+              ),
+              title: Text(
+                "New FROST multisig config",
+                style: STextStyles.navBarTitle(context),
+              ),
+            ),
+            body: SafeArea(
+              child: LayoutBuilder(
+                builder: (context, constraints) {
+                  return SingleChildScrollView(
+                    child: ConstrainedBox(
+                      constraints: BoxConstraints(
+                        minHeight: constraints.maxHeight,
+                      ),
+                      child: IntrinsicHeight(
+                        child: Padding(
+                          padding: const EdgeInsets.all(16),
+                          child: child,
+                        ),
+                      ),
+                    ),
+                  );
+                },
+              ),
+            ),
+          ),
+        ),
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            Text(
+              "Threshold",
+              style: STextStyles.label(context),
+            ),
+            const SizedBox(
+              height: 10,
+            ),
+            TextField(
+              keyboardType: TextInputType.number,
+              inputFormatters: [FilteringTextInputFormatter.digitsOnly],
+              controller: _thresholdController,
+            ),
+            const SizedBox(
+              height: 16,
+            ),
+            Text(
+              "Number of participants",
+              style: STextStyles.label(context),
+            ),
+            const SizedBox(
+              height: 10,
+            ),
+            TextField(
+              keyboardType: TextInputType.number,
+              inputFormatters: [FilteringTextInputFormatter.digitsOnly],
+              controller: _participantsController,
+              onChanged: _participantsCountChanged,
+            ),
+            const SizedBox(
+              height: 16,
+            ),
+            if (controllers.isNotEmpty)
+              Text(
+                "My name",
+                style: STextStyles.label(context),
+              ),
+            if (controllers.isNotEmpty)
+              const SizedBox(
+                height: 10,
+              ),
+            if (controllers.isNotEmpty)
+              TextField(
+                controller: controllers.first,
+              ),
+            if (controllers.length > 1)
+              const SizedBox(
+                height: 16,
+              ),
+            if (controllers.length > 1)
+              Text(
+                "Remaining participants",
+                style: STextStyles.label(context),
+              ),
+            if (controllers.length > 1)
+              Column(
+                children: [
+                  for (int i = 1; i < controllers.length; i++)
+                    Padding(
+                      padding: const EdgeInsets.only(
+                        top: 10,
+                      ),
+                      child: TextField(
+                        controller: controllers[i],
+                      ),
+                    ),
+                ],
+              ),
+            if (!Util.isDesktop) const Spacer(),
+            const SizedBox(
+              height: 16,
+            ),
+            PrimaryButton(
+              label: "Generate",
+              onPressed: () async {
+                if (FocusScope.of(context).hasFocus) {
+                  FocusScope.of(context).unfocus();
+                }
+
+                final validationMessage = _validateInputData();
+
+                if (validationMessage != "valid") {
+                  return await showDialog<void>(
+                    context: context,
+                    builder: (_) => StackOkDialog(
+                      title: validationMessage,
+                      desktopPopRootNavigator: Util.isDesktop,
+                    ),
+                  );
+                }
+
+                final config = Frost.createMultisigConfig(
+                  name: controllers.first.text,
+                  threshold: int.parse(_thresholdController.text),
+                  participants: controllers.map((e) => e.text).toList(),
+                );
+
+                ref.read(pFrostMyName.notifier).state = controllers.first.text;
+                ref.read(pFrostMultisigConfig.notifier).state = config;
+
+                await Navigator.of(context).pushNamed(
+                  ShareNewMultisigConfigView.routeName,
+                  arguments: (
+                    walletName: widget.walletName,
+                    coin: widget.coin,
+                  ),
+                );
+              },
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/pages/add_wallet_views/frost_ms/new/frost_share_commitments_view.dart b/lib/pages/add_wallet_views/frost_ms/new/frost_share_commitments_view.dart
new file mode 100644
index 000000000..bf3649a37
--- /dev/null
+++ b/lib/pages/add_wallet_views/frost_ms/new/frost_share_commitments_view.dart
@@ -0,0 +1,443 @@
+import 'package:barcode_scan2/barcode_scan2.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:qr_flutter/qr_flutter.dart';
+import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/frost_share_shares_view.dart';
+import 'package:stackwallet/pages/home_view/home_view.dart';
+import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
+import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/services/frost.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/detail_item.dart';
+import 'package:stackwallet/widgets/dialogs/frost_interruption_dialog.dart';
+import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+import 'package:stackwallet/widgets/stack_text_field.dart';
+import 'package:stackwallet/widgets/textfield_icon_button.dart';
+
+class FrostShareCommitmentsView extends ConsumerStatefulWidget {
+  const FrostShareCommitmentsView({
+    super.key,
+    required this.walletName,
+    required this.coin,
+  });
+
+  static const String routeName = "/frostShareCommitmentsView";
+
+  final String walletName;
+  final Coin coin;
+
+  @override
+  ConsumerState<FrostShareCommitmentsView> createState() =>
+      _FrostShareCommitmentsViewState();
+}
+
+class _FrostShareCommitmentsViewState
+    extends ConsumerState<FrostShareCommitmentsView> {
+  final List<TextEditingController> controllers = [];
+  final List<FocusNode> focusNodes = [];
+
+  late final List<String> participants;
+  late final String myCommitment;
+  late final int myIndex;
+
+  final List<bool> fieldIsEmptyFlags = [];
+
+  @override
+  void initState() {
+    participants = Frost.getParticipants(
+      multisigConfig: ref.read(pFrostMultisigConfig.state).state!,
+    );
+    myIndex = participants.indexOf(ref.read(pFrostMyName.state).state!);
+    myCommitment = ref.read(pFrostStartKeyGenData.state).state!.commitments;
+
+    // temporarily remove my name
+    participants.removeAt(myIndex);
+
+    for (int i = 0; i < participants.length; i++) {
+      controllers.add(TextEditingController());
+      focusNodes.add(FocusNode());
+      fieldIsEmptyFlags.add(true);
+    }
+    super.initState();
+  }
+
+  @override
+  void dispose() {
+    for (int i = 0; i < controllers.length; i++) {
+      controllers[i].dispose();
+    }
+    for (int i = 0; i < focusNodes.length; i++) {
+      focusNodes[i].dispose();
+    }
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return WillPopScope(
+      onWillPop: () async {
+        await showDialog<void>(
+          context: context,
+          builder: (_) => FrostInterruptionDialog(
+            type: FrostInterruptionDialogType.walletCreation,
+            popUntilOnYesRouteName:
+                Util.isDesktop ? DesktopHomeView.routeName : HomeView.routeName,
+          ),
+        );
+        return false;
+      },
+      child: ConditionalParent(
+        condition: Util.isDesktop,
+        builder: (child) => DesktopScaffold(
+          background: Theme.of(context).extension<StackColors>()!.background,
+          appBar: DesktopAppBar(
+            isCompactHeight: false,
+            leading: AppBarBackButton(
+              onPressed: () async {
+                await showDialog<void>(
+                  context: context,
+                  builder: (_) => const FrostInterruptionDialog(
+                    type: FrostInterruptionDialogType.walletCreation,
+                    popUntilOnYesRouteName: DesktopHomeView.routeName,
+                  ),
+                );
+              },
+            ),
+            trailing: ExitToMyStackButton(
+              onPressed: () async {
+                await showDialog<void>(
+                  context: context,
+                  builder: (_) => const FrostInterruptionDialog(
+                    type: FrostInterruptionDialogType.walletCreation,
+                    popUntilOnYesRouteName: DesktopHomeView.routeName,
+                  ),
+                );
+              },
+            ),
+          ),
+          body: SizedBox(
+            width: 480,
+            child: child,
+          ),
+        ),
+        child: ConditionalParent(
+          condition: !Util.isDesktop,
+          builder: (child) => Background(
+            child: Scaffold(
+              backgroundColor:
+                  Theme.of(context).extension<StackColors>()!.background,
+              appBar: AppBar(
+                leading: AppBarBackButton(
+                  onPressed: () async {
+                    await showDialog<void>(
+                      context: context,
+                      builder: (_) => const FrostInterruptionDialog(
+                        type: FrostInterruptionDialogType.walletCreation,
+                        popUntilOnYesRouteName: HomeView.routeName,
+                      ),
+                    );
+                  },
+                ),
+                title: Text(
+                  "Commitments",
+                  style: STextStyles.navBarTitle(context),
+                ),
+              ),
+              body: SafeArea(
+                child: LayoutBuilder(
+                  builder: (context, constraints) {
+                    return SingleChildScrollView(
+                      child: ConstrainedBox(
+                        constraints: BoxConstraints(
+                          minHeight: constraints.maxHeight,
+                        ),
+                        child: IntrinsicHeight(
+                          child: Padding(
+                            padding: const EdgeInsets.all(16),
+                            child: child,
+                          ),
+                        ),
+                      ),
+                    );
+                  },
+                ),
+              ),
+            ),
+          ),
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              SizedBox(
+                height: 220,
+                child: Row(
+                  mainAxisAlignment: MainAxisAlignment.center,
+                  children: [
+                    QrImageView(
+                      data: myCommitment,
+                      size: 220,
+                      backgroundColor: Theme.of(context)
+                          .extension<StackColors>()!
+                          .background,
+                      foregroundColor: Theme.of(context)
+                          .extension<StackColors>()!
+                          .accentColorDark,
+                    ),
+                  ],
+                ),
+              ),
+              const _Div(),
+              DetailItem(
+                title: "My name",
+                detail: ref.watch(pFrostMyName.state).state!,
+              ),
+              const _Div(),
+              DetailItem(
+                title: "My commitment",
+                detail: myCommitment,
+                button: Util.isDesktop
+                    ? IconCopyButton(
+                        data: myCommitment,
+                      )
+                    : SimpleCopyButton(
+                        data: myCommitment,
+                      ),
+              ),
+              const _Div(),
+              Column(
+                mainAxisSize: MainAxisSize.min,
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  for (int i = 0; i < participants.length; i++)
+                    Column(
+                      mainAxisSize: MainAxisSize.min,
+                      crossAxisAlignment: CrossAxisAlignment.start,
+                      children: [
+                        Padding(
+                          padding: const EdgeInsets.symmetric(vertical: 8),
+                          child: ClipRRect(
+                            borderRadius: BorderRadius.circular(
+                              Constants.size.circularBorderRadius,
+                            ),
+                            child: TextField(
+                              key: Key("frostCommitmentsTextFieldKey_$i"),
+                              controller: controllers[i],
+                              focusNode: focusNodes[i],
+                              readOnly: false,
+                              autocorrect: false,
+                              enableSuggestions: false,
+                              style: STextStyles.field(context),
+                              onChanged: (_) {
+                                setState(() {
+                                  fieldIsEmptyFlags[i] =
+                                      controllers[i].text.isEmpty;
+                                });
+                              },
+                              decoration: standardInputDecoration(
+                                "Enter ${participants[i]}'s commitment",
+                                focusNodes[i],
+                                context,
+                              ).copyWith(
+                                contentPadding: const EdgeInsets.only(
+                                  left: 16,
+                                  top: 6,
+                                  bottom: 8,
+                                  right: 5,
+                                ),
+                                suffixIcon: Padding(
+                                  padding: fieldIsEmptyFlags[i]
+                                      ? const EdgeInsets.only(right: 8)
+                                      : const EdgeInsets.only(right: 0),
+                                  child: UnconstrainedBox(
+                                    child: Row(
+                                      mainAxisAlignment:
+                                          MainAxisAlignment.spaceAround,
+                                      children: [
+                                        !fieldIsEmptyFlags[i]
+                                            ? TextFieldIconButton(
+                                                semanticsLabel:
+                                                    "Clear Button. Clears The Commitment Field Input.",
+                                                key: Key(
+                                                    "frostCommitmentsClearButtonKey_$i"),
+                                                onTap: () {
+                                                  controllers[i].text = "";
+
+                                                  setState(() {
+                                                    fieldIsEmptyFlags[i] = true;
+                                                  });
+                                                },
+                                                child: const XIcon(),
+                                              )
+                                            : TextFieldIconButton(
+                                                semanticsLabel:
+                                                    "Paste Button. Pastes From Clipboard To Commitment Field Input.",
+                                                key: Key(
+                                                    "frostCommitmentsPasteButtonKey_$i"),
+                                                onTap: () async {
+                                                  final ClipboardData? data =
+                                                      await Clipboard.getData(
+                                                          Clipboard.kTextPlain);
+                                                  if (data?.text != null &&
+                                                      data!.text!.isNotEmpty) {
+                                                    controllers[i].text =
+                                                        data.text!.trim();
+                                                  }
+
+                                                  setState(() {
+                                                    fieldIsEmptyFlags[i] =
+                                                        controllers[i]
+                                                            .text
+                                                            .isEmpty;
+                                                  });
+                                                },
+                                                child: fieldIsEmptyFlags[i]
+                                                    ? const ClipboardIcon()
+                                                    : const XIcon(),
+                                              ),
+                                        if (fieldIsEmptyFlags[i])
+                                          TextFieldIconButton(
+                                            semanticsLabel:
+                                                "Scan QR Button. Opens Camera For Scanning QR Code.",
+                                            key: Key(
+                                                "frostCommitmentsScanQrButtonKey_$i"),
+                                            onTap: () async {
+                                              try {
+                                                if (FocusScope.of(context)
+                                                    .hasFocus) {
+                                                  FocusScope.of(context)
+                                                      .unfocus();
+                                                  await Future<void>.delayed(
+                                                      const Duration(
+                                                          milliseconds: 75));
+                                                }
+
+                                                final qrResult =
+                                                    await BarcodeScanner.scan();
+
+                                                controllers[i].text =
+                                                    qrResult.rawContent;
+
+                                                setState(() {
+                                                  fieldIsEmptyFlags[i] =
+                                                      controllers[i]
+                                                          .text
+                                                          .isEmpty;
+                                                });
+                                              } on PlatformException catch (e, s) {
+                                                Logging.instance.log(
+                                                  "Failed to get camera permissions while trying to scan qr code: $e\n$s",
+                                                  level: LogLevel.Warning,
+                                                );
+                                              }
+                                            },
+                                            child: const QrCodeIcon(),
+                                          )
+                                      ],
+                                    ),
+                                  ),
+                                ),
+                              ),
+                            ),
+                          ),
+                        ),
+                      ],
+                    ),
+                ],
+              ),
+              if (!Util.isDesktop) const Spacer(),
+              const _Div(),
+              PrimaryButton(
+                label: "Generate shares",
+                enabled: !fieldIsEmptyFlags.reduce((v, e) => v |= e),
+                onPressed: () async {
+                  // check for empty commitments
+                  if (controllers
+                      .map((e) => e.text.isEmpty)
+                      .reduce((value, element) => value |= element)) {
+                    return await showDialog<void>(
+                      context: context,
+                      builder: (_) => StackOkDialog(
+                        title: "Missing commitments",
+                        desktopPopRootNavigator: Util.isDesktop,
+                      ),
+                    );
+                  }
+
+                  // collect commitment strings and insert my own at the correct index
+                  final commitments = controllers.map((e) => e.text).toList();
+                  commitments.insert(myIndex, myCommitment);
+
+                  try {
+                    ref.read(pFrostSecretSharesData.notifier).state =
+                        Frost.generateSecretShares(
+                      multisigConfigWithNamePtr: ref
+                          .read(pFrostStartKeyGenData.state)
+                          .state!
+                          .multisigConfigWithNamePtr,
+                      mySeed: ref.read(pFrostStartKeyGenData.state).state!.seed,
+                      secretShareMachineWrapperPtr: ref
+                          .read(pFrostStartKeyGenData.state)
+                          .state!
+                          .secretShareMachineWrapperPtr,
+                      commitments: commitments,
+                    );
+
+                    await Navigator.of(context).pushNamed(
+                      FrostShareSharesView.routeName,
+                      arguments: (
+                        walletName: widget.walletName,
+                        coin: widget.coin,
+                      ),
+                    );
+                  } catch (e, s) {
+                    Logging.instance.log(
+                      "$e\n$s",
+                      level: LogLevel.Fatal,
+                    );
+
+                    return await showDialog<void>(
+                      context: context,
+                      builder: (_) => StackOkDialog(
+                        title: "Failed to generate shares",
+                        message: e.toString(),
+                        desktopPopRootNavigator: Util.isDesktop,
+                      ),
+                    );
+                  }
+                },
+              ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+}
+
+class _Div extends StatelessWidget {
+  const _Div({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return const SizedBox(
+      height: 12,
+    );
+  }
+}
diff --git a/lib/pages/add_wallet_views/frost_ms/new/frost_share_shares_view.dart b/lib/pages/add_wallet_views/frost_ms/new/frost_share_shares_view.dart
new file mode 100644
index 000000000..0f5e70ee7
--- /dev/null
+++ b/lib/pages/add_wallet_views/frost_ms/new/frost_share_shares_view.dart
@@ -0,0 +1,409 @@
+import 'package:barcode_scan2/barcode_scan2.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:qr_flutter/qr_flutter.dart';
+import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/confirm_new_frost_ms_wallet_creation_view.dart';
+import 'package:stackwallet/pages/home_view/home_view.dart';
+import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
+import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/services/frost.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/detail_item.dart';
+import 'package:stackwallet/widgets/dialogs/frost_interruption_dialog.dart';
+import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+import 'package:stackwallet/widgets/stack_text_field.dart';
+import 'package:stackwallet/widgets/textfield_icon_button.dart';
+
+class FrostShareSharesView extends ConsumerStatefulWidget {
+  const FrostShareSharesView({
+    super.key,
+    required this.walletName,
+    required this.coin,
+  });
+
+  static const String routeName = "/frostShareSharesView";
+
+  final String walletName;
+  final Coin coin;
+
+  @override
+  ConsumerState<FrostShareSharesView> createState() =>
+      _FrostShareSharesViewState();
+}
+
+class _FrostShareSharesViewState extends ConsumerState<FrostShareSharesView> {
+  final List<TextEditingController> controllers = [];
+  final List<FocusNode> focusNodes = [];
+
+  late final List<String> participants;
+  late final String myShare;
+  late final int myIndex;
+
+  final List<bool> fieldIsEmptyFlags = [];
+
+  @override
+  void initState() {
+    participants = Frost.getParticipants(
+      multisigConfig: ref.read(pFrostMultisigConfig.state).state!,
+    );
+    myIndex = participants.indexOf(ref.read(pFrostMyName.state).state!);
+    myShare = ref.read(pFrostSecretSharesData.state).state!.share;
+
+    // temporarily remove my name. Added back later
+    participants.removeAt(myIndex);
+
+    for (int i = 0; i < participants.length; i++) {
+      controllers.add(TextEditingController());
+      focusNodes.add(FocusNode());
+      fieldIsEmptyFlags.add(true);
+    }
+    super.initState();
+  }
+
+  @override
+  void dispose() {
+    for (int i = 0; i < controllers.length; i++) {
+      controllers[i].dispose();
+    }
+    for (int i = 0; i < focusNodes.length; i++) {
+      focusNodes[i].dispose();
+    }
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return WillPopScope(
+      onWillPop: () async {
+        await showDialog<void>(
+          context: context,
+          builder: (_) => FrostInterruptionDialog(
+            type: FrostInterruptionDialogType.walletCreation,
+            popUntilOnYesRouteName:
+                Util.isDesktop ? DesktopHomeView.routeName : HomeView.routeName,
+          ),
+        );
+        return false;
+      },
+      child: ConditionalParent(
+        condition: Util.isDesktop,
+        builder: (child) => DesktopScaffold(
+          background: Theme.of(context).extension<StackColors>()!.background,
+          appBar: DesktopAppBar(
+            isCompactHeight: false,
+            leading: AppBarBackButton(
+              onPressed: () async {
+                await showDialog<void>(
+                  context: context,
+                  builder: (_) => const FrostInterruptionDialog(
+                    type: FrostInterruptionDialogType.walletCreation,
+                    popUntilOnYesRouteName: DesktopHomeView.routeName,
+                  ),
+                );
+              },
+            ),
+            trailing: ExitToMyStackButton(
+              onPressed: () async {
+                await showDialog<void>(
+                  context: context,
+                  builder: (_) => const FrostInterruptionDialog(
+                    type: FrostInterruptionDialogType.walletCreation,
+                    popUntilOnYesRouteName: DesktopHomeView.routeName,
+                  ),
+                );
+              },
+            ),
+          ),
+          body: SizedBox(
+            width: 480,
+            child: child,
+          ),
+        ),
+        child: ConditionalParent(
+          condition: !Util.isDesktop,
+          builder: (child) => Background(
+            child: Scaffold(
+              backgroundColor:
+                  Theme.of(context).extension<StackColors>()!.background,
+              appBar: AppBar(
+                leading: AppBarBackButton(
+                  onPressed: () async {
+                    await showDialog<void>(
+                      context: context,
+                      builder: (_) => const FrostInterruptionDialog(
+                        type: FrostInterruptionDialogType.walletCreation,
+                        popUntilOnYesRouteName: HomeView.routeName,
+                      ),
+                    );
+                  },
+                ),
+                title: Text(
+                  "Generate shares",
+                  style: STextStyles.navBarTitle(context),
+                ),
+              ),
+              body: SafeArea(
+                child: LayoutBuilder(
+                  builder: (context, constraints) {
+                    return SingleChildScrollView(
+                      child: ConstrainedBox(
+                        constraints: BoxConstraints(
+                          minHeight: constraints.maxHeight,
+                        ),
+                        child: IntrinsicHeight(
+                          child: Padding(
+                            padding: const EdgeInsets.all(16),
+                            child: child,
+                          ),
+                        ),
+                      ),
+                    );
+                  },
+                ),
+              ),
+            ),
+          ),
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              SizedBox(
+                height: 220,
+                child: Row(
+                  mainAxisAlignment: MainAxisAlignment.center,
+                  children: [
+                    QrImageView(
+                      data: myShare,
+                      size: 220,
+                      backgroundColor: Theme.of(context)
+                          .extension<StackColors>()!
+                          .background,
+                      foregroundColor: Theme.of(context)
+                          .extension<StackColors>()!
+                          .accentColorDark,
+                    ),
+                  ],
+                ),
+              ),
+              const _Div(),
+              DetailItem(
+                title: "My name",
+                detail: ref.watch(pFrostMyName.state).state!,
+              ),
+              const _Div(),
+              DetailItem(
+                title: "My share",
+                detail: myShare,
+                button: Util.isDesktop
+                    ? IconCopyButton(
+                        data: myShare,
+                      )
+                    : SimpleCopyButton(
+                        data: myShare,
+                      ),
+              ),
+              const _Div(),
+              for (int i = 0; i < participants.length; i++)
+                Padding(
+                  padding: const EdgeInsets.symmetric(vertical: 8),
+                  child: ClipRRect(
+                    borderRadius: BorderRadius.circular(
+                      Constants.size.circularBorderRadius,
+                    ),
+                    child: TextField(
+                      key: Key("frSharesTextFieldKey_$i"),
+                      controller: controllers[i],
+                      focusNode: focusNodes[i],
+                      readOnly: false,
+                      autocorrect: false,
+                      enableSuggestions: false,
+                      style: STextStyles.field(context),
+                      decoration: standardInputDecoration(
+                        "Enter ${participants[i]}'s share",
+                        focusNodes[i],
+                        context,
+                      ).copyWith(
+                        contentPadding: const EdgeInsets.only(
+                          left: 16,
+                          top: 6,
+                          bottom: 8,
+                          right: 5,
+                        ),
+                        suffixIcon: Padding(
+                          padding: fieldIsEmptyFlags[i]
+                              ? const EdgeInsets.only(right: 8)
+                              : const EdgeInsets.only(right: 0),
+                          child: UnconstrainedBox(
+                            child: Row(
+                              mainAxisAlignment: MainAxisAlignment.spaceAround,
+                              children: [
+                                !fieldIsEmptyFlags[i]
+                                    ? TextFieldIconButton(
+                                        semanticsLabel:
+                                            "Clear Button. Clears The Share Field Input.",
+                                        key: Key("frSharesClearButtonKey_$i"),
+                                        onTap: () {
+                                          controllers[i].text = "";
+
+                                          setState(() {
+                                            fieldIsEmptyFlags[i] = true;
+                                          });
+                                        },
+                                        child: const XIcon(),
+                                      )
+                                    : TextFieldIconButton(
+                                        semanticsLabel:
+                                            "Paste Button. Pastes From Clipboard To Share Field Input.",
+                                        key: Key("frSharesPasteButtonKey_$i"),
+                                        onTap: () async {
+                                          final ClipboardData? data =
+                                              await Clipboard.getData(
+                                                  Clipboard.kTextPlain);
+                                          if (data?.text != null &&
+                                              data!.text!.isNotEmpty) {
+                                            controllers[i].text =
+                                                data.text!.trim();
+                                          }
+
+                                          setState(() {
+                                            fieldIsEmptyFlags[i] =
+                                                controllers[i].text.isEmpty;
+                                          });
+                                        },
+                                        child: fieldIsEmptyFlags[i]
+                                            ? const ClipboardIcon()
+                                            : const XIcon(),
+                                      ),
+                                if (fieldIsEmptyFlags[i])
+                                  TextFieldIconButton(
+                                    semanticsLabel:
+                                        "Scan QR Button. Opens Camera For Scanning QR Code.",
+                                    key: Key("frSharesScanQrButtonKey_$i"),
+                                    onTap: () async {
+                                      try {
+                                        if (FocusScope.of(context).hasFocus) {
+                                          FocusScope.of(context).unfocus();
+                                          await Future<void>.delayed(
+                                              const Duration(milliseconds: 75));
+                                        }
+
+                                        final qrResult =
+                                            await BarcodeScanner.scan();
+
+                                        controllers[i].text =
+                                            qrResult.rawContent;
+
+                                        setState(() {
+                                          fieldIsEmptyFlags[i] =
+                                              controllers[i].text.isEmpty;
+                                        });
+                                      } on PlatformException catch (e, s) {
+                                        Logging.instance.log(
+                                          "Failed to get camera permissions while trying to scan qr code: $e\n$s",
+                                          level: LogLevel.Warning,
+                                        );
+                                      }
+                                    },
+                                    child: const QrCodeIcon(),
+                                  )
+                              ],
+                            ),
+                          ),
+                        ),
+                      ),
+                    ),
+                  ),
+                ),
+              if (!Util.isDesktop) const Spacer(),
+              const _Div(),
+              PrimaryButton(
+                label: "Generate",
+                onPressed: () async {
+                  // check for empty commitments
+                  if (controllers
+                      .map((e) => e.text.isEmpty)
+                      .reduce((value, element) => value |= element)) {
+                    return await showDialog<void>(
+                      context: context,
+                      builder: (_) => StackOkDialog(
+                        title: "Missing shares",
+                        desktopPopRootNavigator: Util.isDesktop,
+                      ),
+                    );
+                  }
+
+                  // collect commitment strings and insert my own at the correct index
+                  final shares = controllers.map((e) => e.text).toList();
+                  shares.insert(myIndex, myShare);
+
+                  try {
+                    ref.read(pFrostCompletedKeyGenData.notifier).state =
+                        Frost.completeKeyGeneration(
+                      multisigConfigWithNamePtr: ref
+                          .read(pFrostStartKeyGenData.state)
+                          .state!
+                          .multisigConfigWithNamePtr,
+                      secretSharesResPtr: ref
+                          .read(pFrostSecretSharesData.state)
+                          .state!
+                          .secretSharesResPtr,
+                      shares: shares,
+                    );
+                    await Navigator.of(context).pushNamed(
+                      ConfirmNewFrostMSWalletCreationView.routeName,
+                      arguments: (
+                        walletName: widget.walletName,
+                        coin: widget.coin,
+                      ),
+                    );
+                  } catch (e, s) {
+                    Logging.instance.log(
+                      "$e\n$s",
+                      level: LogLevel.Fatal,
+                    );
+
+                    return await showDialog<void>(
+                      context: context,
+                      builder: (_) => StackOkDialog(
+                        title: "Failed to complete key generation",
+                        desktopPopRootNavigator: Util.isDesktop,
+                      ),
+                    );
+                  }
+                },
+              ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+}
+
+class _Div extends StatelessWidget {
+  const _Div({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return const SizedBox(
+      height: 12,
+    );
+  }
+}
diff --git a/lib/pages/add_wallet_views/frost_ms/new/import_new_frost_ms_wallet_view.dart b/lib/pages/add_wallet_views/frost_ms/new/import_new_frost_ms_wallet_view.dart
new file mode 100644
index 000000000..1b08b045d
--- /dev/null
+++ b/lib/pages/add_wallet_views/frost_ms/new/import_new_frost_ms_wallet_view.dart
@@ -0,0 +1,386 @@
+import 'package:barcode_scan2/barcode_scan2.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/frost_share_commitments_view.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/services/frost.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+import 'package:stackwallet/widgets/stack_text_field.dart';
+import 'package:stackwallet/widgets/textfield_icon_button.dart';
+
+class ImportNewFrostMsWalletView extends ConsumerStatefulWidget {
+  const ImportNewFrostMsWalletView({
+    super.key,
+    required this.walletName,
+    required this.coin,
+  });
+
+  static const String routeName = "/importNewFrostMsWalletView";
+
+  final String walletName;
+  final Coin coin;
+
+  @override
+  ConsumerState<ImportNewFrostMsWalletView> createState() =>
+      _ImportNewFrostMsWalletViewState();
+}
+
+class _ImportNewFrostMsWalletViewState
+    extends ConsumerState<ImportNewFrostMsWalletView> {
+  late final TextEditingController myNameFieldController, configFieldController;
+  late final FocusNode myNameFocusNode, configFocusNode;
+
+  bool _nameEmpty = true, _configEmpty = true;
+
+  @override
+  void initState() {
+    myNameFieldController = TextEditingController();
+    configFieldController = TextEditingController();
+    myNameFocusNode = FocusNode();
+    configFocusNode = FocusNode();
+    super.initState();
+  }
+
+  @override
+  void dispose() {
+    myNameFieldController.dispose();
+    configFieldController.dispose();
+    myNameFocusNode.dispose();
+    configFocusNode.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return ConditionalParent(
+      condition: Util.isDesktop,
+      builder: (child) => DesktopScaffold(
+        background: Theme.of(context).extension<StackColors>()!.background,
+        appBar: const DesktopAppBar(
+          isCompactHeight: false,
+          leading: AppBarBackButton(),
+          trailing: ExitToMyStackButton(),
+        ),
+        body: SizedBox(
+          width: 480,
+          child: child,
+        ),
+      ),
+      child: ConditionalParent(
+        condition: !Util.isDesktop,
+        builder: (child) => Background(
+          child: Scaffold(
+            backgroundColor:
+                Theme.of(context).extension<StackColors>()!.background,
+            appBar: AppBar(
+              leading: AppBarBackButton(
+                onPressed: () {
+                  Navigator.of(context).pop();
+                },
+              ),
+              title: Text(
+                "Import FROST multisig config",
+                style: STextStyles.navBarTitle(context),
+              ),
+            ),
+            body: SafeArea(
+              child: LayoutBuilder(
+                builder: (context, constraints) {
+                  return SingleChildScrollView(
+                    child: ConstrainedBox(
+                      constraints: BoxConstraints(
+                        minHeight: constraints.maxHeight,
+                      ),
+                      child: IntrinsicHeight(
+                        child: Padding(
+                          padding: const EdgeInsets.all(16),
+                          child: child,
+                        ),
+                      ),
+                    ),
+                  );
+                },
+              ),
+            ),
+          ),
+        ),
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            const SizedBox(
+              height: 16,
+            ),
+            ClipRRect(
+              borderRadius: BorderRadius.circular(
+                Constants.size.circularBorderRadius,
+              ),
+              child: TextField(
+                key: const Key("frMyNameTextFieldKey"),
+                controller: myNameFieldController,
+                onChanged: (_) {
+                  setState(() {
+                    _nameEmpty = myNameFieldController.text.isEmpty;
+                  });
+                },
+                focusNode: myNameFocusNode,
+                readOnly: false,
+                autocorrect: false,
+                enableSuggestions: false,
+                style: STextStyles.field(context),
+                decoration: standardInputDecoration(
+                  "My name",
+                  myNameFocusNode,
+                  context,
+                ).copyWith(
+                  contentPadding: const EdgeInsets.only(
+                    left: 16,
+                    top: 6,
+                    bottom: 8,
+                    right: 5,
+                  ),
+                  suffixIcon: Padding(
+                    padding: _nameEmpty
+                        ? const EdgeInsets.only(right: 8)
+                        : const EdgeInsets.only(right: 0),
+                    child: UnconstrainedBox(
+                      child: Row(
+                        mainAxisAlignment: MainAxisAlignment.spaceAround,
+                        children: [
+                          !_nameEmpty
+                              ? TextFieldIconButton(
+                                  semanticsLabel:
+                                      "Clear Button. Clears The Config Field.",
+                                  key: const Key("frMyNameClearButtonKey"),
+                                  onTap: () {
+                                    myNameFieldController.text = "";
+
+                                    setState(() {
+                                      _nameEmpty = true;
+                                    });
+                                  },
+                                  child: const XIcon(),
+                                )
+                              : TextFieldIconButton(
+                                  semanticsLabel:
+                                      "Paste Button. Pastes From Clipboard To Name Field.",
+                                  key: const Key("frMyNamePasteButtonKey"),
+                                  onTap: () async {
+                                    final ClipboardData? data =
+                                        await Clipboard.getData(
+                                            Clipboard.kTextPlain);
+                                    if (data?.text != null &&
+                                        data!.text!.isNotEmpty) {
+                                      myNameFieldController.text =
+                                          data.text!.trim();
+                                    }
+
+                                    setState(() {
+                                      _nameEmpty =
+                                          myNameFieldController.text.isEmpty;
+                                    });
+                                  },
+                                  child: _nameEmpty
+                                      ? const ClipboardIcon()
+                                      : const XIcon(),
+                                ),
+                        ],
+                      ),
+                    ),
+                  ),
+                ),
+              ),
+            ),
+            const SizedBox(
+              height: 16,
+            ),
+            ClipRRect(
+              borderRadius: BorderRadius.circular(
+                Constants.size.circularBorderRadius,
+              ),
+              child: TextField(
+                key: const Key("frConfigTextFieldKey"),
+                controller: configFieldController,
+                onChanged: (_) {
+                  setState(() {
+                    _configEmpty = configFieldController.text.isEmpty;
+                  });
+                },
+                focusNode: configFocusNode,
+                readOnly: false,
+                autocorrect: false,
+                enableSuggestions: false,
+                style: STextStyles.field(context),
+                decoration: standardInputDecoration(
+                  "Enter config",
+                  configFocusNode,
+                  context,
+                ).copyWith(
+                  contentPadding: const EdgeInsets.only(
+                    left: 16,
+                    top: 6,
+                    bottom: 8,
+                    right: 5,
+                  ),
+                  suffixIcon: Padding(
+                    padding: _configEmpty
+                        ? const EdgeInsets.only(right: 8)
+                        : const EdgeInsets.only(right: 0),
+                    child: UnconstrainedBox(
+                      child: Row(
+                        mainAxisAlignment: MainAxisAlignment.spaceAround,
+                        children: [
+                          !_configEmpty
+                              ? TextFieldIconButton(
+                                  semanticsLabel:
+                                      "Clear Button. Clears The Config Field.",
+                                  key: const Key("frConfigClearButtonKey"),
+                                  onTap: () {
+                                    configFieldController.text = "";
+
+                                    setState(() {
+                                      _configEmpty = true;
+                                    });
+                                  },
+                                  child: const XIcon(),
+                                )
+                              : TextFieldIconButton(
+                                  semanticsLabel:
+                                      "Paste Button. Pastes From Clipboard To Config Field Input.",
+                                  key: const Key("frConfigPasteButtonKey"),
+                                  onTap: () async {
+                                    final ClipboardData? data =
+                                        await Clipboard.getData(
+                                            Clipboard.kTextPlain);
+                                    if (data?.text != null &&
+                                        data!.text!.isNotEmpty) {
+                                      configFieldController.text =
+                                          data.text!.trim();
+                                    }
+
+                                    setState(() {
+                                      _configEmpty =
+                                          configFieldController.text.isEmpty;
+                                    });
+                                  },
+                                  child: _configEmpty
+                                      ? const ClipboardIcon()
+                                      : const XIcon(),
+                                ),
+                          if (_configEmpty)
+                            TextFieldIconButton(
+                              semanticsLabel:
+                                  "Scan QR Button. Opens Camera For Scanning QR Code.",
+                              key: const Key("frConfigScanQrButtonKey"),
+                              onTap: () async {
+                                try {
+                                  if (FocusScope.of(context).hasFocus) {
+                                    FocusScope.of(context).unfocus();
+                                    await Future<void>.delayed(
+                                        const Duration(milliseconds: 75));
+                                  }
+
+                                  final qrResult = await BarcodeScanner.scan();
+
+                                  configFieldController.text =
+                                      qrResult.rawContent;
+
+                                  setState(() {
+                                    _configEmpty =
+                                        configFieldController.text.isEmpty;
+                                  });
+                                } on PlatformException catch (e, s) {
+                                  Logging.instance.log(
+                                    "Failed to get camera permissions while trying to scan qr code: $e\n$s",
+                                    level: LogLevel.Warning,
+                                  );
+                                }
+                              },
+                              child: const QrCodeIcon(),
+                            )
+                        ],
+                      ),
+                    ),
+                  ),
+                ),
+              ),
+            ),
+            const SizedBox(
+              height: 16,
+            ),
+            if (!Util.isDesktop) const Spacer(),
+            const SizedBox(
+              height: 16,
+            ),
+            PrimaryButton(
+              label: "Start key generation",
+              enabled: !_nameEmpty && !_configEmpty,
+              onPressed: () async {
+                if (FocusScope.of(context).hasFocus) {
+                  FocusScope.of(context).unfocus();
+                }
+
+                final config = configFieldController.text;
+
+                if (!Frost.validateEncodedMultisigConfig(
+                    encodedConfig: config)) {
+                  return await showDialog<void>(
+                    context: context,
+                    builder: (_) => StackOkDialog(
+                      title: "Invalid config",
+                      desktopPopRootNavigator: Util.isDesktop,
+                    ),
+                  );
+                }
+
+                if (!Frost.getParticipants(multisigConfig: config)
+                    .contains(myNameFieldController.text)) {
+                  return await showDialog<void>(
+                    context: context,
+                    builder: (_) => StackOkDialog(
+                      title: "My name not found in config participants",
+                      desktopPopRootNavigator: Util.isDesktop,
+                    ),
+                  );
+                }
+
+                ref.read(pFrostMyName.state).state = myNameFieldController.text;
+                ref.read(pFrostMultisigConfig.notifier).state = config;
+
+                ref.read(pFrostStartKeyGenData.state).state =
+                    Frost.startKeyGeneration(
+                  multisigConfig: ref.read(pFrostMultisigConfig.state).state!,
+                  myName: ref.read(pFrostMyName.state).state!,
+                );
+
+                await Navigator.of(context).pushNamed(
+                  FrostShareCommitmentsView.routeName,
+                  arguments: (
+                    walletName: widget.walletName,
+                    coin: widget.coin,
+                  ),
+                );
+              },
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/pages/add_wallet_views/frost_ms/new/share_new_multisig_config_view.dart b/lib/pages/add_wallet_views/frost_ms/new/share_new_multisig_config_view.dart
new file mode 100644
index 000000000..4afb4c0c5
--- /dev/null
+++ b/lib/pages/add_wallet_views/frost_ms/new/share_new_multisig_config_view.dart
@@ -0,0 +1,162 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:qr_flutter/qr_flutter.dart';
+import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/frost_share_commitments_view.dart';
+import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/services/frost.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/detail_item.dart';
+
+class ShareNewMultisigConfigView extends ConsumerStatefulWidget {
+  const ShareNewMultisigConfigView({
+    super.key,
+    required this.walletName,
+    required this.coin,
+  });
+
+  static const String routeName = "/shareNewMultisigConfigView";
+
+  final String walletName;
+  final Coin coin;
+
+  @override
+  ConsumerState<ShareNewMultisigConfigView> createState() =>
+      _ShareNewMultisigConfigViewState();
+}
+
+class _ShareNewMultisigConfigViewState
+    extends ConsumerState<ShareNewMultisigConfigView> {
+  @override
+  Widget build(BuildContext context) {
+    return ConditionalParent(
+      condition: Util.isDesktop,
+      builder: (child) => DesktopScaffold(
+        background: Theme.of(context).extension<StackColors>()!.background,
+        appBar: const DesktopAppBar(
+          isCompactHeight: false,
+          leading: AppBarBackButton(),
+          trailing: ExitToMyStackButton(),
+        ),
+        body: SizedBox(
+          width: 480,
+          child: child,
+        ),
+      ),
+      child: ConditionalParent(
+        condition: !Util.isDesktop,
+        builder: (child) => Background(
+          child: Scaffold(
+            backgroundColor:
+                Theme.of(context).extension<StackColors>()!.background,
+            appBar: AppBar(
+              leading: AppBarBackButton(
+                onPressed: () {
+                  Navigator.of(context).pop();
+                },
+              ),
+              title: Text(
+                "Multisig config",
+                style: STextStyles.navBarTitle(context),
+              ),
+            ),
+            body: SafeArea(
+              child: LayoutBuilder(
+                builder: (context, constraints) {
+                  return SingleChildScrollView(
+                    child: ConstrainedBox(
+                      constraints: BoxConstraints(
+                        minHeight: constraints.maxHeight,
+                      ),
+                      child: IntrinsicHeight(
+                        child: Padding(
+                          padding: const EdgeInsets.all(16),
+                          child: child,
+                        ),
+                      ),
+                    ),
+                  );
+                },
+              ),
+            ),
+          ),
+        ),
+        child: Column(
+          children: [
+            if (!Util.isDesktop) const Spacer(),
+            SizedBox(
+              height: 220,
+              child: Row(
+                mainAxisAlignment: MainAxisAlignment.center,
+                children: [
+                  QrImageView(
+                    data:
+                        ref.watch(pFrostMultisigConfig.state).state ?? "Error",
+                    size: 220,
+                    backgroundColor:
+                        Theme.of(context).extension<StackColors>()!.background,
+                    foregroundColor: Theme.of(context)
+                        .extension<StackColors>()!
+                        .accentColorDark,
+                  ),
+                ],
+              ),
+            ),
+            const SizedBox(
+              height: 32,
+            ),
+            DetailItem(
+              title: "Encoded config",
+              detail: ref.watch(pFrostMultisigConfig.state).state ?? "Error",
+              button: Util.isDesktop
+                  ? IconCopyButton(
+                      data: ref.watch(pFrostMultisigConfig.state).state ??
+                          "Error",
+                    )
+                  : SimpleCopyButton(
+                      data: ref.watch(pFrostMultisigConfig.state).state ??
+                          "Error",
+                    ),
+            ),
+            SizedBox(
+              height: Util.isDesktop ? 64 : 16,
+            ),
+            if (!Util.isDesktop)
+              const Spacer(
+                flex: 2,
+              ),
+            PrimaryButton(
+              label: "Start key generation",
+              onPressed: () async {
+                ref.read(pFrostStartKeyGenData.notifier).state =
+                    Frost.startKeyGeneration(
+                  multisigConfig: ref.watch(pFrostMultisigConfig.state).state!,
+                  myName: ref.read(pFrostMyName.state).state!,
+                );
+
+                await Navigator.of(context).pushNamed(
+                  FrostShareCommitmentsView.routeName,
+                  arguments: (
+                    walletName: widget.walletName,
+                    coin: widget.coin,
+                  ),
+                );
+              },
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart b/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart
new file mode 100644
index 000000000..e99655f06
--- /dev/null
+++ b/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart
@@ -0,0 +1,478 @@
+import 'dart:async';
+
+import 'package:barcode_scan2/barcode_scan2.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:frostdart/frostdart.dart';
+import 'package:stackwallet/notifications/show_flush_bar.dart';
+import 'package:stackwallet/pages/home_view/home_view.dart';
+import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
+import 'package:stackwallet/providers/db/main_db_provider.dart';
+import 'package:stackwallet/providers/global/node_service_provider.dart';
+import 'package:stackwallet/providers/global/prefs_provider.dart';
+import 'package:stackwallet/providers/global/secure_store_provider.dart';
+import 'package:stackwallet/providers/global/wallets_provider.dart';
+import 'package:stackwallet/services/frost.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/assets.dart';
+import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/show_loading.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart';
+import 'package:stackwallet/wallets/isar/models/wallet_info.dart';
+import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
+import 'package:stackwallet/wallets/wallet/wallet.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+import 'package:stackwallet/widgets/stack_text_field.dart';
+import 'package:stackwallet/widgets/textfield_icon_button.dart';
+
+class RestoreFrostMsWalletView extends ConsumerStatefulWidget {
+  const RestoreFrostMsWalletView({
+    super.key,
+    required this.walletName,
+    required this.coin,
+  });
+
+  static const String routeName = "/restoreFrostMsWalletView";
+
+  final String walletName;
+  final Coin coin;
+
+  @override
+  ConsumerState<RestoreFrostMsWalletView> createState() =>
+      _RestoreFrostMsWalletViewState();
+}
+
+class _RestoreFrostMsWalletViewState
+    extends ConsumerState<RestoreFrostMsWalletView> {
+  late final TextEditingController keysFieldController, configFieldController;
+  late final FocusNode keysFocusNode, configFocusNode;
+
+  bool _keysEmpty = true, _configEmpty = true;
+
+  bool _restoreButtonLock = false;
+
+  Future<Wallet> _createWalletAndRecover() async {
+    final keys = keysFieldController.text;
+    final config = configFieldController.text;
+
+    final myNameIndex = getParticipantIndexFromKeys(serializedKeys: keys);
+    final participants = Frost.getParticipants(multisigConfig: config);
+    final myName = participants[myNameIndex];
+
+    final info = WalletInfo.createNew(
+      coin: widget.coin,
+      name: widget.walletName,
+    );
+
+    final wallet = await Wallet.create(
+      walletInfo: info,
+      mainDB: ref.read(mainDBProvider),
+      secureStorageInterface: ref.read(secureStoreProvider),
+      nodeService: ref.read(nodeServiceChangeNotifierProvider),
+      prefs: ref.read(prefsChangeNotifierProvider),
+    );
+
+    final frostInfo = FrostWalletInfo(
+      walletId: info.walletId,
+      knownSalts: [],
+      participants: participants,
+      myName: myName,
+      threshold: multisigThreshold(
+        multisigConfig: config,
+      ),
+    );
+
+    await ref.read(mainDBProvider).isar.frostWalletInfo.put(frostInfo);
+
+    await (wallet as BitcoinFrostWallet).recover(
+      serializedKeys: keys,
+      multisigConfig: config,
+      isRescan: false,
+    );
+
+    await info.setMnemonicVerified(
+      isar: ref.read(mainDBProvider).isar,
+    );
+
+    return wallet;
+  }
+
+  Future<void> _restore() async {
+    if (_restoreButtonLock) {
+      return;
+    }
+    _restoreButtonLock = true;
+
+    try {
+      if (FocusScope.of(context).hasFocus) {
+        FocusScope.of(context).unfocus();
+      }
+
+      Exception? ex;
+      final wallet = await showLoading(
+        whileFuture: _createWalletAndRecover(),
+        context: context,
+        message: "Restoring wallet...",
+        isDesktop: Util.isDesktop,
+        onException: (e) {
+          ex = e;
+        },
+      );
+
+      if (ex != null) {
+        throw ex!;
+      }
+
+      ref.read(pWallets).addWallet(wallet!);
+
+      if (mounted) {
+        if (Util.isDesktop) {
+          Navigator.of(context).popUntil(
+            ModalRoute.withName(
+              DesktopHomeView.routeName,
+            ),
+          );
+        } else {
+          unawaited(
+            Navigator.of(context).pushNamedAndRemoveUntil(
+              HomeView.routeName,
+              (route) => false,
+            ),
+          );
+        }
+
+        unawaited(
+          showFloatingFlushBar(
+            type: FlushBarType.success,
+            message: "Your wallet is set up.",
+            iconAsset: Assets.svg.check,
+            context: context,
+          ),
+        );
+      }
+    } catch (e, s) {
+      Logging.instance.log(
+        "$e\n$s",
+        level: LogLevel.Fatal,
+      );
+
+      if (mounted) {
+        await showDialog<void>(
+          context: context,
+          builder: (_) => StackOkDialog(
+            title: "Failed to restore",
+            message: e.toString(),
+            desktopPopRootNavigator: Util.isDesktop,
+          ),
+        );
+      }
+    } finally {
+      _restoreButtonLock = false;
+    }
+  }
+
+  @override
+  void initState() {
+    keysFieldController = TextEditingController();
+    configFieldController = TextEditingController();
+    keysFocusNode = FocusNode();
+    configFocusNode = FocusNode();
+    super.initState();
+  }
+
+  @override
+  void dispose() {
+    keysFieldController.dispose();
+    configFieldController.dispose();
+    keysFocusNode.dispose();
+    configFocusNode.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return ConditionalParent(
+      condition: Util.isDesktop,
+      builder: (child) => DesktopScaffold(
+        background: Theme.of(context).extension<StackColors>()!.background,
+        appBar: const DesktopAppBar(
+          isCompactHeight: false,
+          leading: AppBarBackButton(),
+          trailing: ExitToMyStackButton(),
+        ),
+        body: SizedBox(
+          width: 480,
+          child: child,
+        ),
+      ),
+      child: ConditionalParent(
+        condition: !Util.isDesktop,
+        builder: (child) => Background(
+          child: Scaffold(
+            backgroundColor:
+                Theme.of(context).extension<StackColors>()!.background,
+            appBar: AppBar(
+              leading: AppBarBackButton(
+                onPressed: () {
+                  Navigator.of(context).pop();
+                },
+              ),
+              title: Text(
+                "Restore FROST multisig wallet",
+                style: STextStyles.navBarTitle(context),
+              ),
+            ),
+            body: SafeArea(
+              child: LayoutBuilder(
+                builder: (context, constraints) {
+                  return SingleChildScrollView(
+                    child: ConstrainedBox(
+                      constraints: BoxConstraints(
+                        minHeight: constraints.maxHeight,
+                      ),
+                      child: IntrinsicHeight(
+                        child: Padding(
+                          padding: const EdgeInsets.all(16),
+                          child: child,
+                        ),
+                      ),
+                    ),
+                  );
+                },
+              ),
+            ),
+          ),
+        ),
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            const SizedBox(
+              height: 16,
+            ),
+            ClipRRect(
+              borderRadius: BorderRadius.circular(
+                Constants.size.circularBorderRadius,
+              ),
+              child: TextField(
+                key: const Key("frMyNameTextFieldKey"),
+                controller: keysFieldController,
+                onChanged: (_) {
+                  setState(() {
+                    _keysEmpty = keysFieldController.text.isEmpty;
+                  });
+                },
+                focusNode: keysFocusNode,
+                readOnly: false,
+                autocorrect: false,
+                enableSuggestions: false,
+                style: STextStyles.field(context),
+                decoration: standardInputDecoration(
+                  "Keys",
+                  keysFocusNode,
+                  context,
+                ).copyWith(
+                  contentPadding: const EdgeInsets.only(
+                    left: 16,
+                    top: 6,
+                    bottom: 8,
+                    right: 5,
+                  ),
+                  suffixIcon: Padding(
+                    padding: _keysEmpty
+                        ? const EdgeInsets.only(right: 8)
+                        : const EdgeInsets.only(right: 0),
+                    child: UnconstrainedBox(
+                      child: Row(
+                        mainAxisAlignment: MainAxisAlignment.spaceAround,
+                        children: [
+                          !_keysEmpty
+                              ? TextFieldIconButton(
+                                  semanticsLabel:
+                                      "Clear Button. Clears The Keys Field.",
+                                  key: const Key("frMyNameClearButtonKey"),
+                                  onTap: () {
+                                    keysFieldController.text = "";
+
+                                    setState(() {
+                                      _keysEmpty = true;
+                                    });
+                                  },
+                                  child: const XIcon(),
+                                )
+                              : TextFieldIconButton(
+                                  semanticsLabel:
+                                      "Paste Button. Pastes From Clipboard To Keys Field.",
+                                  key: const Key("frKeysPasteButtonKey"),
+                                  onTap: () async {
+                                    final ClipboardData? data =
+                                        await Clipboard.getData(
+                                            Clipboard.kTextPlain);
+                                    if (data?.text != null &&
+                                        data!.text!.isNotEmpty) {
+                                      keysFieldController.text =
+                                          data.text!.trim();
+                                    }
+
+                                    setState(() {
+                                      _keysEmpty =
+                                          keysFieldController.text.isEmpty;
+                                    });
+                                  },
+                                  child: _keysEmpty
+                                      ? const ClipboardIcon()
+                                      : const XIcon(),
+                                ),
+                        ],
+                      ),
+                    ),
+                  ),
+                ),
+              ),
+            ),
+            const SizedBox(
+              height: 16,
+            ),
+            ClipRRect(
+              borderRadius: BorderRadius.circular(
+                Constants.size.circularBorderRadius,
+              ),
+              child: TextField(
+                key: const Key("frConfigTextFieldKey"),
+                controller: configFieldController,
+                onChanged: (_) {
+                  setState(() {
+                    _configEmpty = configFieldController.text.isEmpty;
+                  });
+                },
+                focusNode: configFocusNode,
+                readOnly: false,
+                autocorrect: false,
+                enableSuggestions: false,
+                style: STextStyles.field(context),
+                decoration: standardInputDecoration(
+                  "Enter config",
+                  configFocusNode,
+                  context,
+                ).copyWith(
+                  contentPadding: const EdgeInsets.only(
+                    left: 16,
+                    top: 6,
+                    bottom: 8,
+                    right: 5,
+                  ),
+                  suffixIcon: Padding(
+                    padding: _configEmpty
+                        ? const EdgeInsets.only(right: 8)
+                        : const EdgeInsets.only(right: 0),
+                    child: UnconstrainedBox(
+                      child: Row(
+                        mainAxisAlignment: MainAxisAlignment.spaceAround,
+                        children: [
+                          !_configEmpty
+                              ? TextFieldIconButton(
+                                  semanticsLabel:
+                                      "Clear Button. Clears The Config Field.",
+                                  key: const Key("frConfigClearButtonKey"),
+                                  onTap: () {
+                                    configFieldController.text = "";
+
+                                    setState(() {
+                                      _configEmpty = true;
+                                    });
+                                  },
+                                  child: const XIcon(),
+                                )
+                              : TextFieldIconButton(
+                                  semanticsLabel:
+                                      "Paste Button. Pastes From Clipboard To Config Field Input.",
+                                  key: const Key("frConfigPasteButtonKey"),
+                                  onTap: () async {
+                                    final ClipboardData? data =
+                                        await Clipboard.getData(
+                                            Clipboard.kTextPlain);
+                                    if (data?.text != null &&
+                                        data!.text!.isNotEmpty) {
+                                      configFieldController.text =
+                                          data.text!.trim();
+                                    }
+
+                                    setState(() {
+                                      _configEmpty =
+                                          configFieldController.text.isEmpty;
+                                    });
+                                  },
+                                  child: _configEmpty
+                                      ? const ClipboardIcon()
+                                      : const XIcon(),
+                                ),
+                          if (_configEmpty)
+                            TextFieldIconButton(
+                              semanticsLabel:
+                                  "Scan QR Button. Opens Camera For Scanning QR Code.",
+                              key: const Key("frConfigScanQrButtonKey"),
+                              onTap: () async {
+                                try {
+                                  if (FocusScope.of(context).hasFocus) {
+                                    FocusScope.of(context).unfocus();
+                                    await Future<void>.delayed(
+                                        const Duration(milliseconds: 75));
+                                  }
+
+                                  final qrResult = await BarcodeScanner.scan();
+
+                                  configFieldController.text =
+                                      qrResult.rawContent;
+
+                                  setState(() {
+                                    _configEmpty =
+                                        configFieldController.text.isEmpty;
+                                  });
+                                } on PlatformException catch (e, s) {
+                                  Logging.instance.log(
+                                    "Failed to get camera permissions while trying to scan qr code: $e\n$s",
+                                    level: LogLevel.Warning,
+                                  );
+                                }
+                              },
+                              child: const QrCodeIcon(),
+                            )
+                        ],
+                      ),
+                    ),
+                  ),
+                ),
+              ),
+            ),
+            const SizedBox(
+              height: 16,
+            ),
+            if (!Util.isDesktop) const Spacer(),
+            const SizedBox(
+              height: 16,
+            ),
+            PrimaryButton(
+              label: "Restore",
+              enabled: !_keysEmpty && !_configEmpty,
+              onPressed: _restore,
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart b/lib/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart
index 350c839f8..ed91d265e 100644
--- a/lib/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart
+++ b/lib/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart
@@ -14,9 +14,13 @@ import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:isar/isar.dart';
 import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/coin_image.dart';
+import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/create_new_frost_ms_wallet_view.dart';
+import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/import_new_frost_ms_wallet_view.dart';
+import 'package:stackwallet/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart';
 import 'package:stackwallet/pages/add_wallet_views/new_wallet_options/new_wallet_options_view.dart';
 import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart';
 import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_import_resharer_config_view.dart';
 import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
 import 'package:stackwallet/providers/db/main_db_provider.dart';
 import 'package:stackwallet/providers/ui/verify_recovery_phrase/mnemonic_word_count_state_provider.dart';
@@ -32,6 +36,8 @@ import 'package:stackwallet/widgets/background.dart';
 import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
 import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
 import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/desktop/secondary_button.dart';
 import 'package:stackwallet/widgets/icon_widgets/dice_icon.dart';
 import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
 import 'package:stackwallet/widgets/rounded_white_container.dart';
@@ -77,6 +83,52 @@ class _NameYourWalletViewState extends ConsumerState<NameYourWalletView> {
     return name;
   }
 
+  Future<void> _nextPressed() async {
+    final name = textEditingController.text;
+
+    if (mounted) {
+      // hide keyboard if has focus
+      if (FocusScope.of(context).hasFocus) {
+        FocusScope.of(context).unfocus();
+        await Future<void>.delayed(const Duration(milliseconds: 50));
+      }
+
+      if (mounted) {
+        ref.read(mnemonicWordCountStateProvider.state).state =
+            Constants.possibleLengthsForCoin(coin).last;
+        ref.read(pNewWalletOptions.notifier).state = null;
+
+        switch (widget.addWalletType) {
+          case AddWalletType.New:
+            unawaited(
+              Navigator.of(context).pushNamed(
+                coin.hasMnemonicPassphraseSupport
+                    ? NewWalletOptionsView.routeName
+                    : NewWalletRecoveryPhraseWarningView.routeName,
+                arguments: Tuple2(
+                  name,
+                  coin,
+                ),
+              ),
+            );
+            break;
+
+          case AddWalletType.Restore:
+            unawaited(
+              Navigator.of(context).pushNamed(
+                RestoreOptionsView.routeName,
+                arguments: Tuple2(
+                  name,
+                  coin,
+                ),
+              ),
+            );
+            break;
+        }
+      }
+    }
+  }
+
   @override
   void initState() {
     isDesktop = Util.isDesktop;
@@ -330,78 +382,104 @@ class _NameYourWalletViewState extends ConsumerState<NameYourWalletView> {
             const SizedBox(
               height: 32,
             ),
-          ConstrainedBox(
-            constraints: BoxConstraints(
-              minWidth: isDesktop ? 480 : 0,
-              minHeight: isDesktop ? 70 : 0,
+          if (widget.coin.isFrost)
+            if (widget.addWalletType == AddWalletType.Restore)
+              PrimaryButton(
+                label: "Next",
+                enabled: _nextEnabled,
+                onPressed: () async {
+                  final name = textEditingController.text;
+
+                  await Navigator.of(context).pushNamed(
+                    RestoreFrostMsWalletView.routeName,
+                    arguments: (
+                      walletName: name,
+                      coin: coin,
+                    ),
+                  );
+                },
+              ),
+          if (widget.addWalletType == AddWalletType.New)
+            Column(
+              children: [
+                PrimaryButton(
+                  label: "Create config",
+                  enabled: _nextEnabled,
+                  onPressed: () async {
+                    final name = textEditingController.text;
+
+                    await Navigator.of(context).pushNamed(
+                      CreateNewFrostMsWalletView.routeName,
+                      arguments: (
+                        walletName: name,
+                        coin: coin,
+                      ),
+                    );
+                  },
+                ),
+                const SizedBox(
+                  height: 12,
+                ),
+                SecondaryButton(
+                  label: "Import multisig config",
+                  enabled: _nextEnabled,
+                  onPressed: () async {
+                    final name = textEditingController.text;
+
+                    await Navigator.of(context).pushNamed(
+                      ImportNewFrostMsWalletView.routeName,
+                      arguments: (
+                        walletName: name,
+                        coin: coin,
+                      ),
+                    );
+                  },
+                ),
+                const SizedBox(
+                  height: 12,
+                ),
+                SecondaryButton(
+                  label: "Import resharer config",
+                  enabled: _nextEnabled,
+                  onPressed: () async {
+                    final name = textEditingController.text;
+
+                    await Navigator.of(context).pushNamed(
+                      NewImportResharerConfigView.routeName,
+                      arguments: (
+                        walletName: name,
+                        coin: coin,
+                      ),
+                    );
+                  },
+                ),
+              ],
             ),
-            child: TextButton(
-              onPressed: _nextEnabled
-                  ? () async {
-                      final name = textEditingController.text;
-
-                      if (mounted) {
-                        // hide keyboard if has focus
-                        if (FocusScope.of(context).hasFocus) {
-                          FocusScope.of(context).unfocus();
-                          await Future<void>.delayed(
-                              const Duration(milliseconds: 50));
-                        }
-
-                        if (mounted) {
-                          ref.read(mnemonicWordCountStateProvider.state).state =
-                              Constants.possibleLengthsForCoin(coin).last;
-                          ref.read(pNewWalletOptions.notifier).state = null;
-
-                          switch (widget.addWalletType) {
-                            case AddWalletType.New:
-                              unawaited(
-                                Navigator.of(context).pushNamed(
-                                  coin.hasMnemonicPassphraseSupport
-                                      ? NewWalletOptionsView.routeName
-                                      : NewWalletRecoveryPhraseWarningView
-                                          .routeName,
-                                  arguments: Tuple2(
-                                    name,
-                                    coin,
-                                  ),
-                                ),
-                              );
-                              break;
-
-                            case AddWalletType.Restore:
-                              unawaited(
-                                Navigator.of(context).pushNamed(
-                                  RestoreOptionsView.routeName,
-                                  arguments: Tuple2(
-                                    name,
-                                    coin,
-                                  ),
-                                ),
-                              );
-                              break;
-                          }
-                        }
-                      }
-                    }
-                  : null,
-              style: _nextEnabled
-                  ? Theme.of(context)
-                      .extension<StackColors>()!
-                      .getPrimaryEnabledButtonStyle(context)
-                  : Theme.of(context)
-                      .extension<StackColors>()!
-                      .getPrimaryDisabledButtonStyle(context),
-              child: Text(
-                "Next",
-                style: isDesktop
-                    ? _nextEnabled
-                        ? STextStyles.desktopButtonEnabled(context)
-                        : STextStyles.desktopButtonDisabled(context)
-                    : STextStyles.button(context),
+          if (!widget.coin.isFrost)
+            ConstrainedBox(
+              constraints: BoxConstraints(
+                minWidth: isDesktop ? 480 : 0,
+                minHeight: isDesktop ? 70 : 0,
+              ),
+              child: TextButton(
+                onPressed: _nextEnabled ? _nextPressed : null,
+                style: _nextEnabled
+                    ? Theme.of(context)
+                        .extension<StackColors>()!
+                        .getPrimaryEnabledButtonStyle(context)
+                    : Theme.of(context)
+                        .extension<StackColors>()!
+                        .getPrimaryDisabledButtonStyle(context),
+                child: Text(
+                  "Next",
+                  style: isDesktop
+                      ? _nextEnabled
+                          ? STextStyles.desktopButtonEnabled(context)
+                          : STextStyles.desktopButtonDisabled(context)
+                      : STextStyles.button(context),
+                ),
               ),
             ),
-          ),
           if (isDesktop)
             const Spacer(
               flex: 15,
diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/frost_ms_options_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/frost_ms_options_view.dart
new file mode 100644
index 000000000..169a96b64
--- /dev/null
+++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/frost_ms_options_view.dart
@@ -0,0 +1,162 @@
+/*
+ * This file is part of Stack Wallet.
+ *
+ * Copyright (c) 2023 Cypher Stack
+ * All Rights Reserved.
+ * The code is distributed under GPLv3 license, see LICENSE file for details.
+ * Generated by Cypher Stack on 2023-05-26
+ *
+ */
+
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/frost_participants_view.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/begin_reshare_config_view.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1b/import_reshare_config_view.dart';
+import 'package:stackwallet/providers/db/main_db_provider.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/rounded_white_container.dart';
+
+class FrostMSWalletOptionsView extends ConsumerWidget {
+  const FrostMSWalletOptionsView({
+    Key? key,
+    required this.walletId,
+  }) : super(key: key);
+
+  static const String routeName = "/frostMSWalletOptionsView";
+
+  final String walletId;
+
+  @override
+  Widget build(BuildContext context, WidgetRef ref) {
+    return Background(
+      child: Scaffold(
+        backgroundColor: Theme.of(context).extension<StackColors>()!.background,
+        appBar: AppBar(
+          leading: AppBarBackButton(
+            onPressed: () {
+              Navigator.of(context).pop();
+            },
+          ),
+          title: Text(
+            "Multisig settings",
+            style: STextStyles.navBarTitle(context),
+          ),
+        ),
+        body: Padding(
+          padding: const EdgeInsets.only(
+            top: 12,
+            left: 16,
+            right: 16,
+          ),
+          child: SingleChildScrollView(
+            child: Column(
+              crossAxisAlignment: CrossAxisAlignment.stretch,
+              children: [
+                _OptionButton(
+                  label: "Show participants",
+                  onPressed: () {
+                    Navigator.of(context).pushNamed(
+                      FrostParticipantsView.routeName,
+                      arguments: walletId,
+                    );
+                  },
+                ),
+                const SizedBox(
+                  height: 8,
+                ),
+                _OptionButton(
+                  label: "Initiate resharing",
+                  onPressed: () {
+                    // TODO: optimize this by creating watcher providers (similar to normal WalletInfo)
+                    final frostInfo = ref
+                        .read(mainDBProvider)
+                        .isar
+                        .frostWalletInfo
+                        .getByWalletIdSync(walletId)!;
+
+                    ref.read(pFrostMyName.state).state = frostInfo.myName;
+
+                    Navigator.of(context).pushNamed(
+                      BeginReshareConfigView.routeName,
+                      arguments: walletId,
+                    );
+                  },
+                ),
+                const SizedBox(
+                  height: 8,
+                ),
+                _OptionButton(
+                  label: "Import reshare config",
+                  onPressed: () {
+                    // TODO: optimize this by creating watcher providers (similar to normal WalletInfo)
+                    final frostInfo = ref
+                        .read(mainDBProvider)
+                        .isar
+                        .frostWalletInfo
+                        .getByWalletIdSync(walletId)!;
+
+                    ref.read(pFrostMyName.state).state = frostInfo.myName;
+
+                    Navigator.of(context).pushNamed(
+                      ImportReshareConfigView.routeName,
+                      arguments: walletId,
+                    );
+                  },
+                ),
+              ],
+            ),
+          ),
+        ),
+      ),
+    );
+  }
+}
+
+class _OptionButton extends StatelessWidget {
+  const _OptionButton({
+    super.key,
+    required this.label,
+    required this.onPressed,
+  });
+
+  final String label;
+  final VoidCallback onPressed;
+
+  @override
+  Widget build(BuildContext context) {
+    return RoundedWhiteContainer(
+      padding: const EdgeInsets.all(0),
+      child: RawMaterialButton(
+        // splashColor: Theme.of(context).extension<StackColors>()!.highlight,
+        shape: RoundedRectangleBorder(
+          borderRadius: BorderRadius.circular(
+            Constants.size.circularBorderRadius,
+          ),
+        ),
+        materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
+        onPressed: onPressed,
+        child: Padding(
+          padding: const EdgeInsets.symmetric(
+            horizontal: 12.0,
+            vertical: 20,
+          ),
+          child: Row(
+            children: [
+              Text(
+                label,
+                style: STextStyles.titleBold12(context),
+              ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/frost_participants_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/frost_participants_view.dart
new file mode 100644
index 000000000..b4710bfe7
--- /dev/null
+++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/frost_participants_view.dart
@@ -0,0 +1,119 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
+import 'package:stackwallet/providers/db/main_db_provider.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+
+class FrostParticipantsView extends ConsumerWidget {
+  const FrostParticipantsView({
+    super.key,
+    required this.walletId,
+  });
+
+  static const String routeName = "/frostParticipantsView";
+
+  final String walletId;
+
+  @override
+  Widget build(BuildContext context, WidgetRef ref) {
+    // TODO: optimize this by creating watcher providers (similar to normal WalletInfo)
+    final frostInfo = ref
+        .read(mainDBProvider)
+        .isar
+        .frostWalletInfo
+        .getByWalletIdSync(walletId)!;
+
+    return ConditionalParent(
+      condition: Util.isDesktop,
+      builder: (child) => DesktopScaffold(
+        background: Theme.of(context).extension<StackColors>()!.background,
+        appBar: const DesktopAppBar(
+          isCompactHeight: false,
+          leading: AppBarBackButton(),
+          trailing: ExitToMyStackButton(),
+        ),
+        body: SizedBox(
+          width: 480,
+          child: child,
+        ),
+      ),
+      child: ConditionalParent(
+        condition: !Util.isDesktop,
+        builder: (child) => Background(
+          child: Scaffold(
+            backgroundColor:
+                Theme.of(context).extension<StackColors>()!.background,
+            appBar: AppBar(
+              leading: AppBarBackButton(
+                onPressed: () {
+                  Navigator.of(context).pop();
+                },
+              ),
+              title: Text(
+                "Participants",
+                style: STextStyles.navBarTitle(context),
+              ),
+            ),
+            body: SafeArea(
+              child: LayoutBuilder(
+                builder: (context, constraints) {
+                  return SingleChildScrollView(
+                    child: ConstrainedBox(
+                      constraints: BoxConstraints(
+                        minHeight: constraints.maxHeight,
+                      ),
+                      child: IntrinsicHeight(
+                        child: Padding(
+                          padding: const EdgeInsets.all(16),
+                          child: child,
+                        ),
+                      ),
+                    ),
+                  );
+                },
+              ),
+            ),
+          ),
+        ),
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            for (int i = 0; i < frostInfo.participants.length; i++)
+              Padding(
+                padding: const EdgeInsets.symmetric(
+                  vertical: 8,
+                ),
+                child: Column(
+                  mainAxisSize: MainAxisSize.min,
+                  crossAxisAlignment: CrossAxisAlignment.start,
+                  children: [
+                    Text(
+                      "Index $i",
+                      style: STextStyles.label(context),
+                    ),
+                    const SizedBox(
+                      height: 6,
+                    ),
+                    SelectableText(
+                      frostInfo.participants[i] == frostInfo.myName
+                          ? "${frostInfo.participants[i]} (me)"
+                          : frostInfo.participants[i],
+                      style: STextStyles.itemSubtitle12(context),
+                    ),
+                  ],
+                ),
+              ),
+          ],
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/finish_resharing_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/finish_resharing_view.dart
new file mode 100644
index 000000000..8d23e9ed4
--- /dev/null
+++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/finish_resharing_view.dart
@@ -0,0 +1,433 @@
+import 'dart:ffi';
+
+import 'package:barcode_scan2/barcode_scan2.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:qr_flutter/qr_flutter.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/verify_updated_wallet_view.dart';
+import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
+import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart';
+import 'package:stackwallet/providers/db/main_db_provider.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/services/frost.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/detail_item.dart';
+import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+import 'package:stackwallet/widgets/stack_text_field.dart';
+import 'package:stackwallet/widgets/textfield_icon_button.dart';
+
+class FinishResharingView extends ConsumerStatefulWidget {
+  const FinishResharingView({
+    super.key,
+    required this.walletId,
+  });
+
+  static const String routeName = "/finishResharingView";
+
+  final String walletId;
+
+  @override
+  ConsumerState<FinishResharingView> createState() =>
+      _FinishResharingViewState();
+}
+
+class _FinishResharingViewState extends ConsumerState<FinishResharingView> {
+  final List<TextEditingController> controllers = [];
+  final List<FocusNode> focusNodes = [];
+
+  late final List<int> resharerIndexes;
+  late final String myName;
+  late final int? myResharerIndexIndex;
+  late final String? myResharerComplete;
+  late final bool amOutgoingParticipant;
+
+  final List<bool> fieldIsEmptyFlags = [];
+
+  bool _buttonLock = false;
+  Future<void> _onPressed() async {
+    if (_buttonLock) {
+      return;
+    }
+    _buttonLock = true;
+
+    try {
+      if (amOutgoingParticipant) {
+        ref.read(pFrostResharingData).reset();
+        Navigator.of(context).popUntil(
+          ModalRoute.withName(
+            Util.isDesktop ? DesktopWalletView.routeName : WalletView.routeName,
+          ),
+        );
+      } else {
+        // collect resharer completes strings and insert my own at the correct index
+        final resharerCompletes = controllers.map((e) => e.text).toList();
+        if (myResharerIndexIndex != null && myResharerComplete != null) {
+          resharerCompletes.insert(myResharerIndexIndex!, myResharerComplete!);
+        }
+
+        final data = Frost.finishReshared(
+          prior: ref.read(pFrostResharingData).startResharedData!.prior.ref,
+          resharerCompletes: resharerCompletes,
+        );
+
+        ref.read(pFrostResharingData).newWalletData = data;
+
+        await Navigator.of(context).pushNamed(
+          VerifyUpdatedWalletView.routeName,
+          arguments: widget.walletId,
+        );
+      }
+    } catch (e, s) {
+      Logging.instance.log(
+        "$e\n$s",
+        level: LogLevel.Fatal,
+      );
+      if (mounted) {
+        await showDialog<void>(
+          context: context,
+          builder: (_) => StackOkDialog(
+            title: "Error",
+            message: e.toString(),
+            desktopPopRootNavigator: Util.isDesktop,
+          ),
+        );
+      }
+    } finally {
+      _buttonLock = false;
+    }
+  }
+
+  @override
+  void initState() {
+    final amNewParticipant =
+        ref.read(pFrostResharingData).startResharerData == null &&
+            ref.read(pFrostResharingData).incompleteWallet != null &&
+            ref.read(pFrostResharingData).incompleteWallet?.walletId ==
+                widget.walletId;
+
+    myName = ref.read(pFrostResharingData).myName!;
+
+    resharerIndexes = ref.read(pFrostResharingData).configData!.resharers;
+
+    if (amNewParticipant) {
+      myResharerComplete = null;
+      myResharerIndexIndex = null;
+      amOutgoingParticipant = false;
+    } else {
+      myResharerComplete = ref.read(pFrostResharingData).resharerComplete!;
+
+      final frostInfo = ref
+          .read(mainDBProvider)
+          .isar
+          .frostWalletInfo
+          .getByWalletIdSync(widget.walletId)!;
+      final myOldIndex =
+          frostInfo.participants.indexOf(ref.read(pFrostResharingData).myName!);
+
+      myResharerIndexIndex = resharerIndexes.indexOf(myOldIndex);
+      if (myResharerIndexIndex! >= 0) {
+        // remove my name for now as we don't need a text field for it
+        resharerIndexes.removeAt(myResharerIndexIndex!);
+      }
+
+      amOutgoingParticipant = !ref
+          .read(pFrostResharingData)
+          .configData!
+          .newParticipants
+          .contains(ref.read(pFrostResharingData).myName!);
+    }
+
+    for (int i = 0; i < resharerIndexes.length; i++) {
+      controllers.add(TextEditingController());
+      focusNodes.add(FocusNode());
+      fieldIsEmptyFlags.add(true);
+    }
+    super.initState();
+  }
+
+  @override
+  void dispose() {
+    for (int i = 0; i < controllers.length; i++) {
+      controllers[i].dispose();
+    }
+    for (int i = 0; i < focusNodes.length; i++) {
+      focusNodes[i].dispose();
+    }
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return ConditionalParent(
+      condition: Util.isDesktop,
+      builder: (child) => DesktopScaffold(
+        background: Theme.of(context).extension<StackColors>()!.background,
+        appBar: const DesktopAppBar(
+          isCompactHeight: false,
+          leading: AppBarBackButton(),
+          trailing: ExitToMyStackButton(),
+        ),
+        body: SizedBox(
+          width: 480,
+          child: child,
+        ),
+      ),
+      child: ConditionalParent(
+        condition: !Util.isDesktop,
+        builder: (child) => Background(
+          child: Scaffold(
+            backgroundColor:
+                Theme.of(context).extension<StackColors>()!.background,
+            appBar: AppBar(
+              leading: AppBarBackButton(
+                onPressed: () {
+                  Navigator.of(context).pop();
+                },
+              ),
+              title: Text(
+                "Resharer completes",
+                style: STextStyles.navBarTitle(context),
+              ),
+            ),
+            body: SafeArea(
+              child: LayoutBuilder(
+                builder: (context, constraints) {
+                  return SingleChildScrollView(
+                    child: ConstrainedBox(
+                      constraints: BoxConstraints(
+                        minHeight: constraints.maxHeight,
+                      ),
+                      child: IntrinsicHeight(
+                        child: Padding(
+                          padding: const EdgeInsets.all(16),
+                          child: child,
+                        ),
+                      ),
+                    ),
+                  );
+                },
+              ),
+            ),
+          ),
+        ),
+        child: Column(
+          children: [
+            if (myResharerComplete != null)
+              SizedBox(
+                height: 220,
+                child: Row(
+                  mainAxisAlignment: MainAxisAlignment.center,
+                  children: [
+                    QrImageView(
+                      data: myResharerComplete!,
+                      size: 220,
+                      backgroundColor: Theme.of(context)
+                          .extension<StackColors>()!
+                          .background,
+                      foregroundColor: Theme.of(context)
+                          .extension<StackColors>()!
+                          .accentColorDark,
+                    ),
+                  ],
+                ),
+              ),
+            if (myResharerComplete != null) const _Div(),
+            if (myResharerComplete != null)
+              DetailItem(
+                title: "My resharer complete",
+                detail: myResharerComplete!,
+                button: Util.isDesktop
+                    ? IconCopyButton(
+                        data: myResharerComplete!,
+                      )
+                    : SimpleCopyButton(
+                        data: myResharerComplete!,
+                      ),
+              ),
+            if (!amOutgoingParticipant) const _Div(),
+            if (!amOutgoingParticipant)
+              Column(
+                mainAxisSize: MainAxisSize.min,
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  for (int i = 0; i < resharerIndexes.length; i++)
+                    Column(
+                      mainAxisSize: MainAxisSize.min,
+                      crossAxisAlignment: CrossAxisAlignment.start,
+                      children: [
+                        Padding(
+                          padding: const EdgeInsets.symmetric(vertical: 8),
+                          child: ClipRRect(
+                            borderRadius: BorderRadius.circular(
+                              Constants.size.circularBorderRadius,
+                            ),
+                            child: TextField(
+                              key: Key("frostEncryptionKeyTextFieldKey_$i"),
+                              controller: controllers[i],
+                              focusNode: focusNodes[i],
+                              readOnly: false,
+                              autocorrect: false,
+                              enableSuggestions: false,
+                              style: STextStyles.field(context),
+                              onChanged: (_) {
+                                setState(() {
+                                  fieldIsEmptyFlags[i] =
+                                      controllers[i].text.isEmpty;
+                                });
+                              },
+                              decoration: standardInputDecoration(
+                                "Enter index "
+                                "${resharerIndexes[i]}"
+                                "'s resharer complete",
+                                focusNodes[i],
+                                context,
+                              ).copyWith(
+                                contentPadding: const EdgeInsets.only(
+                                  left: 16,
+                                  top: 6,
+                                  bottom: 8,
+                                  right: 5,
+                                ),
+                                suffixIcon: Padding(
+                                  padding: fieldIsEmptyFlags[i]
+                                      ? const EdgeInsets.only(right: 8)
+                                      : const EdgeInsets.only(right: 0),
+                                  child: UnconstrainedBox(
+                                    child: Row(
+                                      mainAxisAlignment:
+                                          MainAxisAlignment.spaceAround,
+                                      children: [
+                                        !fieldIsEmptyFlags[i]
+                                            ? TextFieldIconButton(
+                                                semanticsLabel:
+                                                    "Clear Button. Clears The Encryption Key Field Input.",
+                                                key: Key(
+                                                    "frostEncryptionKeyClearButtonKey_$i"),
+                                                onTap: () {
+                                                  controllers[i].text = "";
+
+                                                  setState(() {
+                                                    fieldIsEmptyFlags[i] = true;
+                                                  });
+                                                },
+                                                child: const XIcon(),
+                                              )
+                                            : TextFieldIconButton(
+                                                semanticsLabel:
+                                                    "Paste Button. Pastes From Clipboard To Encryption Key Field Input.",
+                                                key: Key(
+                                                    "frostEncryptionKeyPasteButtonKey_$i"),
+                                                onTap: () async {
+                                                  final ClipboardData? data =
+                                                      await Clipboard.getData(
+                                                          Clipboard.kTextPlain);
+                                                  if (data?.text != null &&
+                                                      data!.text!.isNotEmpty) {
+                                                    controllers[i].text =
+                                                        data.text!.trim();
+                                                  }
+
+                                                  setState(() {
+                                                    fieldIsEmptyFlags[i] =
+                                                        controllers[i]
+                                                            .text
+                                                            .isEmpty;
+                                                  });
+                                                },
+                                                child: fieldIsEmptyFlags[i]
+                                                    ? const ClipboardIcon()
+                                                    : const XIcon(),
+                                              ),
+                                        if (fieldIsEmptyFlags[i])
+                                          TextFieldIconButton(
+                                            semanticsLabel: "Scan QR Button. "
+                                                "Opens Camera For Scanning QR Code.",
+                                            key: Key("frostScanQrButtonKey_$i"),
+                                            onTap: () async {
+                                              try {
+                                                if (FocusScope.of(context)
+                                                    .hasFocus) {
+                                                  FocusScope.of(context)
+                                                      .unfocus();
+                                                  await Future<void>.delayed(
+                                                      const Duration(
+                                                          milliseconds: 75));
+                                                }
+
+                                                final qrResult =
+                                                    await BarcodeScanner.scan();
+
+                                                controllers[i].text =
+                                                    qrResult.rawContent;
+
+                                                setState(() {
+                                                  fieldIsEmptyFlags[i] =
+                                                      controllers[i]
+                                                          .text
+                                                          .isEmpty;
+                                                });
+                                              } on PlatformException catch (e, s) {
+                                                Logging.instance.log(
+                                                  "Failed to get camera permissions "
+                                                  "while trying to scan qr code: $e\n$s",
+                                                  level: LogLevel.Warning,
+                                                );
+                                              }
+                                            },
+                                            child: const QrCodeIcon(),
+                                          ),
+                                      ],
+                                    ),
+                                  ),
+                                ),
+                              ),
+                            ),
+                          ),
+                        ),
+                      ],
+                    ),
+                ],
+              ),
+            if (!Util.isDesktop) const Spacer(),
+            const _Div(),
+            PrimaryButton(
+              label: amOutgoingParticipant ? "Exit" : "Complete",
+              enabled: amOutgoingParticipant ||
+                  !fieldIsEmptyFlags.reduce((v, e) => v |= e),
+              onPressed: _onPressed,
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}
+
+class _Div extends StatelessWidget {
+  const _Div({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return const SizedBox(
+      height: 12,
+    );
+  }
+}
diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/begin_reshare_config_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/begin_reshare_config_view.dart
new file mode 100644
index 000000000..94d2de0b2
--- /dev/null
+++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/begin_reshare_config_view.dart
@@ -0,0 +1,196 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/complete_reshare_config_view.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
+import 'package:stackwallet/providers/db/main_db_provider.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+
+final class BeginReshareConfigView extends ConsumerStatefulWidget {
+  const BeginReshareConfigView({
+    super.key,
+    required this.walletId,
+  });
+
+  static const String routeName = "/beginReshareConfigView";
+
+  final String walletId;
+
+  @override
+  ConsumerState<BeginReshareConfigView> createState() =>
+      _BeginReshareConfigViewState();
+}
+
+class _BeginReshareConfigViewState
+    extends ConsumerState<BeginReshareConfigView> {
+  late final int currentThreshold;
+  late final List<String> currentParticipants;
+
+  final Map<String, int> pFrostResharersMap = {};
+
+  @override
+  void initState() {
+    ref.read(pFrostResharingData).reset();
+
+    // TODO: optimize this by creating watcher providers (similar to normal WalletInfo)
+    final frostInfo = ref
+        .read(mainDBProvider)
+        .isar
+        .frostWalletInfo
+        .getByWalletIdSync(widget.walletId)!;
+
+    currentThreshold = frostInfo.threshold;
+    currentParticipants = frostInfo.participants;
+
+    super.initState();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return ConditionalParent(
+      condition: Util.isDesktop,
+      builder: (child) => DesktopScaffold(
+        background: Theme.of(context).extension<StackColors>()!.background,
+        appBar: const DesktopAppBar(
+          isCompactHeight: false,
+          leading: AppBarBackButton(),
+          trailing: ExitToMyStackButton(),
+        ),
+        body: SizedBox(
+          width: 480,
+          child: child,
+        ),
+      ),
+      child: ConditionalParent(
+        condition: !Util.isDesktop,
+        builder: (child) => Background(
+          child: Scaffold(
+            backgroundColor:
+                Theme.of(context).extension<StackColors>()!.background,
+            appBar: AppBar(
+              leading: AppBarBackButton(
+                onPressed: () {
+                  Navigator.of(context).pop();
+                },
+              ),
+              // title: Text(
+              //   "Modify Participants",
+              //   style: STextStyles.navBarTitle(context),
+              // ),
+            ),
+            body: SafeArea(
+              child: LayoutBuilder(
+                builder: (context, constraints) {
+                  return SingleChildScrollView(
+                    child: ConstrainedBox(
+                      constraints: BoxConstraints(
+                        minHeight: constraints.maxHeight,
+                      ),
+                      child: IntrinsicHeight(
+                        child: Padding(
+                          padding: const EdgeInsets.all(16),
+                          child: child,
+                        ),
+                      ),
+                    ),
+                  );
+                },
+              ),
+            ),
+          ),
+        ),
+        child: Column(
+          mainAxisSize: MainAxisSize.min,
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            Text(
+              "Select participants for resharing",
+              style: STextStyles.label(context),
+            ),
+            const SizedBox(
+              height: 16,
+            ),
+            Column(
+              children: [
+                for (int i = 0; i < currentParticipants.length; i++)
+                  Padding(
+                    padding: const EdgeInsets.only(
+                      top: 10,
+                    ),
+                    child: RawMaterialButton(
+                      materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
+                      shape: RoundedRectangleBorder(
+                        borderRadius: BorderRadius.circular(
+                          Constants.size.circularBorderRadius,
+                        ),
+                      ),
+                      onPressed: () {
+                        if (pFrostResharersMap[currentParticipants[i]] ==
+                            null) {
+                          pFrostResharersMap[currentParticipants[i]] = i;
+                        } else {
+                          pFrostResharersMap.remove(currentParticipants[i]);
+                        }
+
+                        setState(() {});
+                      },
+                      child: Container(
+                        color: Colors.transparent,
+                        child: IgnorePointer(
+                          child: Row(
+                            children: [
+                              Checkbox(
+                                value: pFrostResharersMap[
+                                        currentParticipants[i]] ==
+                                    i,
+                                onChanged: (bool? value) {},
+                              ),
+                              const SizedBox(
+                                width: 10,
+                              ),
+                              Text(
+                                currentParticipants[i],
+                                style: STextStyles.itemSubtitle12(context),
+                              ),
+                            ],
+                          ),
+                        ),
+                      ),
+                    ),
+                  ),
+              ],
+            ),
+            if (!Util.isDesktop) const Spacer(),
+            const SizedBox(
+              height: 16,
+            ),
+            PrimaryButton(
+              label: "Continue",
+              enabled: pFrostResharersMap.length >= currentThreshold,
+              onPressed: () async {
+                await Navigator.of(context).pushNamed(
+                  CompleteReshareConfigView.routeName,
+                  arguments: (
+                    walletId: widget.walletId,
+                    resharers:
+                        pFrostResharersMap.values.toList(growable: false),
+                  ),
+                );
+              },
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/complete_reshare_config_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/complete_reshare_config_view.dart
new file mode 100644
index 000000000..0e2e1e111
--- /dev/null
+++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/complete_reshare_config_view.dart
@@ -0,0 +1,335 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:frostdart/frostdart.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/display_reshare_config_view.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
+import 'package:stackwallet/providers/db/main_db_provider.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/services/frost.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/format.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+
+final class CompleteReshareConfigView extends ConsumerStatefulWidget {
+  const CompleteReshareConfigView({
+    super.key,
+    required this.walletId,
+    required this.resharers,
+  });
+
+  static const String routeName = "/completeReshareConfigView";
+
+  final String walletId;
+  final List<int> resharers;
+
+  @override
+  ConsumerState<CompleteReshareConfigView> createState() =>
+      _CompleteReshareConfigViewState();
+}
+
+class _CompleteReshareConfigViewState
+    extends ConsumerState<CompleteReshareConfigView> {
+  final _newThresholdController = TextEditingController();
+  final _newParticipantsCountController = TextEditingController();
+
+  final List<TextEditingController> controllers = [];
+
+  int _participantsCount = 0;
+
+  bool _buttonLock = false;
+
+  Future<void> _onPressed() async {
+    if (_buttonLock) {
+      return;
+    }
+    _buttonLock = true;
+
+    try {
+      // TODO: optimize this by creating watcher providers (similar to normal WalletInfo)
+      final frostInfo = ref
+          .read(mainDBProvider)
+          .isar
+          .frostWalletInfo
+          .getByWalletIdSync(widget.walletId)!;
+      final validationMessage = _validateInputData();
+
+      if (validationMessage != "valid") {
+        return await showDialog<void>(
+          context: context,
+          builder: (_) => StackOkDialog(
+            title: validationMessage,
+            desktopPopRootNavigator: Util.isDesktop,
+          ),
+        );
+      }
+
+      final config = Frost.createResharerConfig(
+        newThreshold: int.parse(_newThresholdController.text),
+        resharers: widget.resharers,
+        newParticipants: controllers.map((e) => e.text).toList(),
+      );
+
+      final salt = Format.uint8listToString(
+        resharerSalt(resharerConfig: config),
+      );
+
+      if (frostInfo.knownSalts.contains(salt)) {
+        return await showDialog<void>(
+          context: context,
+          builder: (_) => StackOkDialog(
+            title: "Duplicate config salt",
+            desktopPopRootNavigator: Util.isDesktop,
+          ),
+        );
+      } else {
+        final salts = frostInfo.knownSalts;
+        salts.add(salt);
+        final mainDB = ref.read(mainDBProvider);
+        await mainDB.isar.writeTxn(() async {
+          final info = frostInfo;
+          await mainDB.isar.frostWalletInfo.delete(info.id);
+          await mainDB.isar.frostWalletInfo.put(
+            info.copyWith(knownSalts: salts),
+          );
+        });
+      }
+
+      ref.read(pFrostResharingData).myName = frostInfo.myName;
+      ref.read(pFrostResharingData).resharerConfig = config;
+
+      if (mounted) {
+        await Navigator.of(context).pushNamed(
+          DisplayReshareConfigView.routeName,
+          arguments: widget.walletId,
+        );
+      }
+    } catch (e, s) {
+      Logging.instance.log(
+        "$e\n$s",
+        level: LogLevel.Fatal,
+      );
+      if (mounted) {
+        await showDialog<void>(
+          context: context,
+          builder: (_) => StackOkDialog(
+            title: e.toString(),
+            desktopPopRootNavigator: Util.isDesktop,
+          ),
+        );
+      }
+    } finally {
+      _buttonLock = false;
+    }
+  }
+
+  String _validateInputData() {
+    final threshold = int.tryParse(_newThresholdController.text);
+    if (threshold == null) {
+      return "Choose a threshold";
+    }
+
+    final partsCount = int.tryParse(_newParticipantsCountController.text);
+    if (partsCount == null) {
+      return "Choose total number of participants";
+    }
+
+    if (threshold > partsCount) {
+      return "Threshold cannot be greater than the number of participants";
+    }
+
+    if (partsCount < 2) {
+      return "At least two participants required";
+    }
+
+    if (controllers.length != partsCount) {
+      return "Participants count error";
+    }
+
+    final hasEmptyParticipants = controllers
+        .map((e) => e.text.isEmpty)
+        .reduce((value, element) => value |= element);
+    if (hasEmptyParticipants) {
+      return "Participants must not be empty";
+    }
+
+    if (controllers.length != controllers.map((e) => e.text).toSet().length) {
+      return "Duplicate participant name found";
+    }
+
+    return "valid";
+  }
+
+  void _participantsCountChanged(String newValue) {
+    final count = int.tryParse(newValue);
+    if (count != null) {
+      if (count > _participantsCount) {
+        for (int i = _participantsCount; i < count; i++) {
+          controllers.add(TextEditingController());
+        }
+
+        _participantsCount = count;
+        setState(() {});
+      } else if (count < _participantsCount) {
+        for (int i = _participantsCount; i > count; i--) {
+          final last = controllers.removeLast();
+          last.dispose();
+        }
+
+        _participantsCount = count;
+        setState(() {});
+      }
+    }
+  }
+
+  @override
+  void dispose() {
+    _newThresholdController.dispose();
+    _newParticipantsCountController.dispose();
+    for (final e in controllers) {
+      e.dispose();
+    }
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return ConditionalParent(
+      condition: Util.isDesktop,
+      builder: (child) => DesktopScaffold(
+        background: Theme.of(context).extension<StackColors>()!.background,
+        appBar: const DesktopAppBar(
+          isCompactHeight: false,
+          leading: AppBarBackButton(),
+          trailing: ExitToMyStackButton(),
+        ),
+        body: SizedBox(
+          width: 480,
+          child: child,
+        ),
+      ),
+      child: ConditionalParent(
+        condition: !Util.isDesktop,
+        builder: (child) => Background(
+          child: Scaffold(
+            backgroundColor:
+                Theme.of(context).extension<StackColors>()!.background,
+            appBar: AppBar(
+              leading: AppBarBackButton(
+                onPressed: () {
+                  Navigator.of(context).pop();
+                },
+              ),
+              title: Text(
+                "Modify Participants",
+                style: STextStyles.navBarTitle(context),
+              ),
+            ),
+            body: SafeArea(
+              child: LayoutBuilder(
+                builder: (context, constraints) {
+                  return SingleChildScrollView(
+                    child: ConstrainedBox(
+                      constraints: BoxConstraints(
+                        minHeight: constraints.maxHeight,
+                      ),
+                      child: IntrinsicHeight(
+                        child: Padding(
+                          padding: const EdgeInsets.all(16),
+                          child: child,
+                        ),
+                      ),
+                    ),
+                  );
+                },
+              ),
+            ),
+          ),
+        ),
+        child: Column(
+          mainAxisSize: MainAxisSize.min,
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            Text(
+              "New threshold",
+              style: STextStyles.label(context),
+            ),
+            const SizedBox(
+              height: 10,
+            ),
+            TextField(
+              keyboardType: TextInputType.number,
+              inputFormatters: [FilteringTextInputFormatter.digitsOnly],
+              controller: _newThresholdController,
+            ),
+            const SizedBox(
+              height: 16,
+            ),
+            Text(
+              "Number of participants",
+              style: STextStyles.label(context),
+            ),
+            const SizedBox(
+              height: 10,
+            ),
+            TextField(
+              keyboardType: TextInputType.number,
+              inputFormatters: [FilteringTextInputFormatter.digitsOnly],
+              controller: _newParticipantsCountController,
+              onChanged: _participantsCountChanged,
+            ),
+            const SizedBox(
+              height: 16,
+            ),
+            if (controllers.isNotEmpty)
+              Text(
+                "Participants",
+                style: STextStyles.label(context),
+              ),
+            if (controllers.isNotEmpty)
+              const SizedBox(
+                height: 10,
+              ),
+            if (controllers.isNotEmpty)
+              Column(
+                children: [
+                  for (int i = 0; i < controllers.length; i++)
+                    Padding(
+                      padding: const EdgeInsets.only(
+                        top: 10,
+                      ),
+                      child: TextField(
+                        controller: controllers[i],
+                      ),
+                    ),
+                ],
+              ),
+            if (!Util.isDesktop) const Spacer(),
+            const SizedBox(
+              height: 16,
+            ),
+            PrimaryButton(
+              label: "Generate config",
+              onPressed: () async {
+                if (FocusScope.of(context).hasFocus) {
+                  FocusScope.of(context).unfocus();
+                }
+                await _onPressed();
+              },
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/display_reshare_config_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/display_reshare_config_view.dart
new file mode 100644
index 000000000..2b7f1f899
--- /dev/null
+++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/display_reshare_config_view.dart
@@ -0,0 +1,214 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:qr_flutter/qr_flutter.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_2/begin_resharing_view.dart';
+import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
+import 'package:stackwallet/providers/db/main_db_provider.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/providers/global/wallets_provider.dart';
+import 'package:stackwallet/services/frost.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart';
+import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/detail_item.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+
+class DisplayReshareConfigView extends ConsumerStatefulWidget {
+  const DisplayReshareConfigView({
+    super.key,
+    required this.walletId,
+  });
+
+  static const String routeName = "/displayReshareConfigView";
+
+  final String walletId;
+
+  @override
+  ConsumerState<DisplayReshareConfigView> createState() =>
+      _DisplayReshareConfigViewState();
+}
+
+class _DisplayReshareConfigViewState
+    extends ConsumerState<DisplayReshareConfigView> {
+  late final bool iAmInvolved;
+
+  bool _buttonLock = false;
+
+  Future<void> _onPressed() async {
+    if (_buttonLock) {
+      return;
+    }
+    _buttonLock = true;
+
+    try {
+      final wallet =
+          ref.read(pWallets).getWallet(widget.walletId) as BitcoinFrostWallet;
+
+      final serializedKeys = await wallet.getSerializedKeys();
+      if (mounted) {
+        final result = Frost.beginResharer(
+          serializedKeys: serializedKeys!,
+          config: ref.read(pFrostResharingData).resharerConfig!,
+        );
+
+        ref.read(pFrostResharingData).startResharerData = result;
+
+        await Navigator.of(context).pushNamed(
+          BeginResharingView.routeName,
+          arguments: widget.walletId,
+        );
+      }
+    } catch (e, s) {
+      Logging.instance.log(
+        "$e\n$s",
+        level: LogLevel.Fatal,
+      );
+
+      if (mounted) {
+        await showDialog<void>(
+          context: context,
+          builder: (_) => StackOkDialog(
+            title: e.toString(),
+            desktopPopRootNavigator: Util.isDesktop,
+          ),
+        );
+      }
+    } finally {
+      _buttonLock = false;
+    }
+  }
+
+  @override
+  void initState() {
+    // TODO: optimize this by creating watcher providers (similar to normal WalletInfo)
+    final frostInfo = ref
+        .read(mainDBProvider)
+        .isar
+        .frostWalletInfo
+        .getByWalletIdSync(widget.walletId)!;
+
+    final myOldIndex = frostInfo.participants.indexOf(frostInfo.myName);
+
+    iAmInvolved = ref
+        .read(pFrostResharingData)
+        .configData!
+        .resharers
+        .contains(myOldIndex);
+    super.initState();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return ConditionalParent(
+      condition: Util.isDesktop,
+      builder: (child) => DesktopScaffold(
+        background: Theme.of(context).extension<StackColors>()!.background,
+        appBar: const DesktopAppBar(
+          isCompactHeight: false,
+          leading: AppBarBackButton(),
+        ),
+        body: SizedBox(
+          width: 480,
+          child: child,
+        ),
+      ),
+      child: ConditionalParent(
+        condition: !Util.isDesktop,
+        builder: (child) => Background(
+          child: Scaffold(
+            backgroundColor:
+                Theme.of(context).extension<StackColors>()!.background,
+            appBar: AppBar(
+              leading: AppBarBackButton(
+                onPressed: () {
+                  Navigator.of(context).pop();
+                },
+              ),
+              title: Text(
+                "Resharer config",
+                style: STextStyles.navBarTitle(context),
+              ),
+            ),
+            body: SafeArea(
+              child: LayoutBuilder(
+                builder: (context, constraints) {
+                  return SingleChildScrollView(
+                    child: ConstrainedBox(
+                      constraints: BoxConstraints(
+                        minHeight: constraints.maxHeight,
+                      ),
+                      child: IntrinsicHeight(
+                        child: Padding(
+                          padding: const EdgeInsets.all(16),
+                          child: child,
+                        ),
+                      ),
+                    ),
+                  );
+                },
+              ),
+            ),
+          ),
+        ),
+        child: Column(
+          children: [
+            if (!Util.isDesktop) const Spacer(),
+            SizedBox(
+              height: 220,
+              child: Row(
+                mainAxisAlignment: MainAxisAlignment.center,
+                children: [
+                  QrImageView(
+                    data: ref.watch(pFrostResharingData).resharerConfig!,
+                    size: 220,
+                    backgroundColor:
+                        Theme.of(context).extension<StackColors>()!.background,
+                    foregroundColor: Theme.of(context)
+                        .extension<StackColors>()!
+                        .accentColorDark,
+                  ),
+                ],
+              ),
+            ),
+            const SizedBox(
+              height: 32,
+            ),
+            DetailItem(
+              title: "Config",
+              detail: ref.watch(pFrostResharingData).resharerConfig!,
+              button: Util.isDesktop
+                  ? IconCopyButton(
+                      data: ref.watch(pFrostResharingData).resharerConfig!,
+                    )
+                  : SimpleCopyButton(
+                      data: ref.watch(pFrostResharingData).resharerConfig!,
+                    ),
+            ),
+            SizedBox(
+              height: Util.isDesktop ? 64 : 16,
+            ),
+            if (!Util.isDesktop)
+              const Spacer(
+                flex: 2,
+              ),
+            if (iAmInvolved)
+              PrimaryButton(
+                label: "Start resharing",
+                onPressed: _onPressed,
+              ),
+          ],
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1b/import_reshare_config_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1b/import_reshare_config_view.dart
new file mode 100644
index 000000000..966a24710
--- /dev/null
+++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1b/import_reshare_config_view.dart
@@ -0,0 +1,338 @@
+import 'package:barcode_scan2/barcode_scan2.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:frostdart/frostdart.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_2/begin_resharing_view.dart';
+import 'package:stackwallet/providers/db/main_db_provider.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/providers/global/secure_store_provider.dart';
+import 'package:stackwallet/services/frost.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/format.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+import 'package:stackwallet/widgets/stack_text_field.dart';
+import 'package:stackwallet/widgets/textfield_icon_button.dart';
+
+class ImportReshareConfigView extends ConsumerStatefulWidget {
+  const ImportReshareConfigView({
+    super.key,
+    required this.walletId,
+  });
+
+  static const String routeName = "/importReshareConfigView";
+
+  final String walletId;
+
+  @override
+  ConsumerState<ImportReshareConfigView> createState() =>
+      _ImportReshareConfigViewState();
+}
+
+class _ImportReshareConfigViewState
+    extends ConsumerState<ImportReshareConfigView> {
+  late final TextEditingController configFieldController;
+  late final FocusNode configFocusNode;
+
+  bool _configEmpty = true;
+
+  bool _buttonLock = false;
+
+  Future<void> _onPressed() async {
+    if (_buttonLock) {
+      return;
+    }
+    _buttonLock = true;
+
+    try {
+      // TODO: optimize this by creating watcher providers (similar to normal WalletInfo)
+      final frostInfo = ref
+          .read(mainDBProvider)
+          .isar
+          .frostWalletInfo
+          .getByWalletIdSync(widget.walletId)!;
+
+      ref.read(pFrostResharingData).reset();
+      ref.read(pFrostResharingData).myName = frostInfo.myName;
+      ref.read(pFrostResharingData).resharerConfig = configFieldController.text;
+
+      String? salt;
+      try {
+        salt = Format.uint8listToString(
+          resharerSalt(
+            resharerConfig: ref.read(pFrostResharingData).resharerConfig!,
+          ),
+        );
+      } catch (_) {
+        throw Exception("Bad resharer config");
+      }
+
+      if (frostInfo.knownSalts.contains(salt)) {
+        throw Exception("Duplicate config salt");
+      } else {
+        final salts = frostInfo.knownSalts;
+        salts.add(salt);
+        final mainDB = ref.read(mainDBProvider);
+        await mainDB.isar.writeTxn(() async {
+          final info = frostInfo;
+          await mainDB.isar.frostWalletInfo.delete(info.id);
+          await mainDB.isar.frostWalletInfo.put(
+            info.copyWith(knownSalts: salts),
+          );
+        });
+      }
+
+      final serializedKeys = await ref.read(secureStoreProvider).read(
+            key: "{${widget.walletId}}_serializedFROSTKeys",
+          );
+      if (mounted) {
+        final result = Frost.beginResharer(
+          serializedKeys: serializedKeys!,
+          config: ref.read(pFrostResharingData).resharerConfig!,
+        );
+
+        ref.read(pFrostResharingData).startResharerData = result;
+
+        await Navigator.of(context).pushNamed(
+          BeginResharingView.routeName,
+          arguments: widget.walletId,
+        );
+      }
+    } catch (e, s) {
+      Logging.instance.log(
+        "$e\n$s",
+        level: LogLevel.Fatal,
+      );
+
+      if (mounted) {
+        await showDialog<void>(
+          context: context,
+          builder: (_) => StackOkDialog(
+            title: e.toString(),
+            desktopPopRootNavigator: Util.isDesktop,
+          ),
+        );
+      }
+    } finally {
+      _buttonLock = false;
+    }
+  }
+
+  @override
+  void initState() {
+    configFieldController = TextEditingController();
+    configFocusNode = FocusNode();
+    super.initState();
+  }
+
+  @override
+  void dispose() {
+    configFieldController.dispose();
+    configFocusNode.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return ConditionalParent(
+      condition: Util.isDesktop,
+      builder: (child) => DesktopScaffold(
+        background: Theme.of(context).extension<StackColors>()!.background,
+        appBar: const DesktopAppBar(
+          isCompactHeight: false,
+          leading: AppBarBackButton(),
+        ),
+        body: SizedBox(
+          width: 480,
+          child: child,
+        ),
+      ),
+      child: ConditionalParent(
+        condition: !Util.isDesktop,
+        builder: (child) => Background(
+          child: Scaffold(
+            backgroundColor:
+                Theme.of(context).extension<StackColors>()!.background,
+            appBar: AppBar(
+              leading: const AppBarBackButton(),
+              title: Text(
+                "Import FROST reshare config",
+                style: STextStyles.navBarTitle(context),
+              ),
+            ),
+            body: SafeArea(
+              child: LayoutBuilder(
+                builder: (context, constraints) {
+                  return SingleChildScrollView(
+                    child: ConstrainedBox(
+                      constraints: BoxConstraints(
+                        minHeight: constraints.maxHeight,
+                      ),
+                      child: IntrinsicHeight(
+                        child: Padding(
+                          padding: const EdgeInsets.all(16),
+                          child: child,
+                        ),
+                      ),
+                    ),
+                  );
+                },
+              ),
+            ),
+          ),
+        ),
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            const SizedBox(
+              height: 16,
+            ),
+            ClipRRect(
+              borderRadius: BorderRadius.circular(
+                Constants.size.circularBorderRadius,
+              ),
+              child: TextField(
+                key: const Key("frConfigTextFieldKey"),
+                controller: configFieldController,
+                onChanged: (_) {
+                  setState(() {
+                    _configEmpty = configFieldController.text.isEmpty;
+                  });
+                },
+                focusNode: configFocusNode,
+                readOnly: false,
+                autocorrect: false,
+                enableSuggestions: false,
+                style: STextStyles.field(context),
+                decoration: standardInputDecoration(
+                  "Enter config",
+                  configFocusNode,
+                  context,
+                ).copyWith(
+                  contentPadding: const EdgeInsets.only(
+                    left: 16,
+                    top: 6,
+                    bottom: 8,
+                    right: 5,
+                  ),
+                  suffixIcon: Padding(
+                    padding: _configEmpty
+                        ? const EdgeInsets.only(right: 8)
+                        : const EdgeInsets.only(right: 0),
+                    child: UnconstrainedBox(
+                      child: Row(
+                        mainAxisAlignment: MainAxisAlignment.spaceAround,
+                        children: [
+                          !_configEmpty
+                              ? TextFieldIconButton(
+                                  semanticsLabel:
+                                      "Clear Button. Clears The Config Field.",
+                                  key: const Key("frConfigClearButtonKey"),
+                                  onTap: () {
+                                    configFieldController.text = "";
+
+                                    setState(() {
+                                      _configEmpty = true;
+                                    });
+                                  },
+                                  child: const XIcon(),
+                                )
+                              : TextFieldIconButton(
+                                  semanticsLabel:
+                                      "Paste Button. Pastes From Clipboard To Config Field Input.",
+                                  key: const Key("frConfigPasteButtonKey"),
+                                  onTap: () async {
+                                    final ClipboardData? data =
+                                        await Clipboard.getData(
+                                            Clipboard.kTextPlain);
+                                    if (data?.text != null &&
+                                        data!.text!.isNotEmpty) {
+                                      configFieldController.text =
+                                          data.text!.trim();
+                                    }
+
+                                    setState(() {
+                                      _configEmpty =
+                                          configFieldController.text.isEmpty;
+                                    });
+                                  },
+                                  child: _configEmpty
+                                      ? const ClipboardIcon()
+                                      : const XIcon(),
+                                ),
+                          if (_configEmpty)
+                            TextFieldIconButton(
+                              semanticsLabel:
+                                  "Scan QR Button. Opens Camera For Scanning QR Code.",
+                              key: const Key("frConfigScanQrButtonKey"),
+                              onTap: () async {
+                                try {
+                                  if (FocusScope.of(context).hasFocus) {
+                                    FocusScope.of(context).unfocus();
+                                    await Future<void>.delayed(
+                                        const Duration(milliseconds: 75));
+                                  }
+
+                                  final qrResult = await BarcodeScanner.scan();
+
+                                  configFieldController.text =
+                                      qrResult.rawContent;
+
+                                  setState(() {
+                                    _configEmpty =
+                                        configFieldController.text.isEmpty;
+                                  });
+                                } on PlatformException catch (e, s) {
+                                  Logging.instance.log(
+                                    "Failed to get camera permissions while trying to scan qr code: $e\n$s",
+                                    level: LogLevel.Warning,
+                                  );
+                                }
+                              },
+                              child: const QrCodeIcon(),
+                            )
+                        ],
+                      ),
+                    ),
+                  ),
+                ),
+              ),
+            ),
+            const SizedBox(
+              height: 16,
+            ),
+            if (!Util.isDesktop) const Spacer(),
+            const SizedBox(
+              height: 16,
+            ),
+            PrimaryButton(
+              label: "Start resharing",
+              enabled: !_configEmpty,
+              onPressed: () async {
+                if (FocusScope.of(context).hasFocus) {
+                  FocusScope.of(context).unfocus();
+                }
+
+                await _onPressed();
+              },
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_2/begin_resharing_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_2/begin_resharing_view.dart
new file mode 100644
index 000000000..90218529f
--- /dev/null
+++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_2/begin_resharing_view.dart
@@ -0,0 +1,439 @@
+import 'package:barcode_scan2/barcode_scan2.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:qr_flutter/qr_flutter.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_2/continue_resharing_view.dart';
+import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
+import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart';
+import 'package:stackwallet/providers/db/main_db_provider.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/services/frost.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/detail_item.dart';
+import 'package:stackwallet/widgets/dialogs/frost_interruption_dialog.dart';
+import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+import 'package:stackwallet/widgets/stack_text_field.dart';
+import 'package:stackwallet/widgets/textfield_icon_button.dart';
+
+class BeginResharingView extends ConsumerStatefulWidget {
+  const BeginResharingView({
+    super.key,
+    required this.walletId,
+  });
+
+  static const String routeName = "/beginResharingView";
+
+  final String walletId;
+
+  @override
+  ConsumerState<BeginResharingView> createState() => _BeginResharingViewState();
+}
+
+class _BeginResharingViewState extends ConsumerState<BeginResharingView> {
+  final List<TextEditingController> controllers = [];
+  final List<FocusNode> focusNodes = [];
+
+  late final List<int> resharerIndexes;
+  late final int myResharerIndexIndex;
+  late final String myResharerStart;
+  late final bool amOutgoingParticipant;
+
+  final List<bool> fieldIsEmptyFlags = [];
+
+  bool _buttonLock = false;
+
+  Future<void> _onPressed() async {
+    if (_buttonLock) {
+      return;
+    }
+    _buttonLock = true;
+
+    try {
+      if (!amOutgoingParticipant) {
+        // collect resharer strings
+        final resharerStarts = controllers.map((e) => e.text).toList();
+        if (myResharerIndexIndex >= 0) {
+          // only insert my own at the correct index if I am a resharer
+          resharerStarts.insert(myResharerIndexIndex, myResharerStart);
+        }
+
+        final result = Frost.beginReshared(
+          myName: ref.read(pFrostResharingData).myName!,
+          resharerConfig: ref.read(pFrostResharingData).resharerConfig!,
+          resharerStarts: resharerStarts,
+        );
+
+        ref.read(pFrostResharingData).startResharedData = result;
+      }
+      await Navigator.of(context).pushNamed(
+        ContinueResharingView.routeName,
+        arguments: widget.walletId,
+      );
+    } catch (e, s) {
+      Logging.instance.log(
+        "$e\n$s",
+        level: LogLevel.Fatal,
+      );
+
+      if (mounted) {
+        await showDialog<void>(
+          context: context,
+          builder: (_) => StackOkDialog(
+            title: "Error",
+            message: e.toString(),
+            desktopPopRootNavigator: Util.isDesktop,
+          ),
+        );
+      }
+    } finally {
+      _buttonLock = false;
+    }
+  }
+
+  @override
+  void initState() {
+    // TODO: optimize this by creating watcher providers (similar to normal WalletInfo)
+    final frostInfo = ref
+        .read(mainDBProvider)
+        .isar
+        .frostWalletInfo
+        .getByWalletIdSync(widget.walletId)!;
+    final myOldIndex =
+        frostInfo.participants.indexOf(ref.read(pFrostResharingData).myName!);
+
+    myResharerStart =
+        ref.read(pFrostResharingData).startResharerData!.resharerStart;
+
+    resharerIndexes = ref.read(pFrostResharingData).configData!.resharers;
+    myResharerIndexIndex = resharerIndexes.indexOf(myOldIndex);
+    if (myResharerIndexIndex >= 0) {
+      // remove my name for now as we don't need a text field for it
+      resharerIndexes.removeAt(myResharerIndexIndex);
+    }
+
+    amOutgoingParticipant = !ref
+        .read(pFrostResharingData)
+        .configData!
+        .newParticipants
+        .contains(ref.read(pFrostResharingData).myName!);
+
+    for (int i = 0; i < resharerIndexes.length; i++) {
+      controllers.add(TextEditingController());
+      focusNodes.add(FocusNode());
+      fieldIsEmptyFlags.add(true);
+    }
+    super.initState();
+  }
+
+  @override
+  void dispose() {
+    for (int i = 0; i < controllers.length; i++) {
+      controllers[i].dispose();
+    }
+    for (int i = 0; i < focusNodes.length; i++) {
+      focusNodes[i].dispose();
+    }
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return WillPopScope(
+      onWillPop: () async {
+        await showDialog<void>(
+          context: context,
+          builder: (_) => FrostInterruptionDialog(
+            type: FrostInterruptionDialogType.resharing,
+            popUntilOnYesRouteName: Util.isDesktop
+                ? DesktopWalletView.routeName
+                : WalletView.routeName,
+          ),
+        );
+        return false;
+      },
+      child: ConditionalParent(
+        condition: Util.isDesktop,
+        builder: (child) => DesktopScaffold(
+          background: Theme.of(context).extension<StackColors>()!.background,
+          appBar: DesktopAppBar(
+            isCompactHeight: false,
+            leading: AppBarBackButton(
+              onPressed: () async {
+                await showDialog<void>(
+                  context: context,
+                  builder: (_) => const FrostInterruptionDialog(
+                    type: FrostInterruptionDialogType.resharing,
+                    popUntilOnYesRouteName: DesktopWalletView.routeName,
+                  ),
+                );
+              },
+            ),
+          ),
+          body: SizedBox(
+            width: 480,
+            child: child,
+          ),
+        ),
+        child: ConditionalParent(
+          condition: !Util.isDesktop,
+          builder: (child) => Background(
+            child: Scaffold(
+              backgroundColor:
+                  Theme.of(context).extension<StackColors>()!.background,
+              appBar: AppBar(
+                leading: AppBarBackButton(
+                  onPressed: () async {
+                    await showDialog<void>(
+                      context: context,
+                      builder: (_) => const FrostInterruptionDialog(
+                        type: FrostInterruptionDialogType.resharing,
+                        popUntilOnYesRouteName: WalletView.routeName,
+                      ),
+                    );
+                  },
+                ),
+                title: Text(
+                  "Resharers",
+                  style: STextStyles.navBarTitle(context),
+                ),
+              ),
+              body: SafeArea(
+                child: LayoutBuilder(
+                  builder: (context, constraints) {
+                    return SingleChildScrollView(
+                      child: ConstrainedBox(
+                        constraints: BoxConstraints(
+                          minHeight: constraints.maxHeight,
+                        ),
+                        child: IntrinsicHeight(
+                          child: Padding(
+                            padding: const EdgeInsets.all(16),
+                            child: child,
+                          ),
+                        ),
+                      ),
+                    );
+                  },
+                ),
+              ),
+            ),
+          ),
+          child: Column(
+            children: [
+              SizedBox(
+                height: 220,
+                child: Row(
+                  mainAxisAlignment: MainAxisAlignment.center,
+                  children: [
+                    QrImageView(
+                      data: myResharerStart,
+                      size: 220,
+                      backgroundColor: Theme.of(context)
+                          .extension<StackColors>()!
+                          .background,
+                      foregroundColor: Theme.of(context)
+                          .extension<StackColors>()!
+                          .accentColorDark,
+                    ),
+                  ],
+                ),
+              ),
+              const _Div(),
+              DetailItem(
+                title: "My resharer",
+                detail: myResharerStart,
+                button: Util.isDesktop
+                    ? IconCopyButton(
+                        data: myResharerStart,
+                      )
+                    : SimpleCopyButton(
+                        data: myResharerStart,
+                      ),
+              ),
+              const _Div(),
+              Column(
+                mainAxisSize: MainAxisSize.min,
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  for (int i = 0; i < resharerIndexes.length; i++)
+                    Column(
+                      mainAxisSize: MainAxisSize.min,
+                      crossAxisAlignment: CrossAxisAlignment.start,
+                      children: [
+                        Padding(
+                          padding: const EdgeInsets.symmetric(vertical: 8),
+                          child: ClipRRect(
+                            borderRadius: BorderRadius.circular(
+                              Constants.size.circularBorderRadius,
+                            ),
+                            child: TextField(
+                              key: Key("frostResharerTextFieldKey_$i"),
+                              controller: controllers[i],
+                              focusNode: focusNodes[i],
+                              readOnly: false,
+                              autocorrect: false,
+                              enableSuggestions: false,
+                              style: STextStyles.field(context),
+                              onChanged: (_) {
+                                setState(() {
+                                  fieldIsEmptyFlags[i] =
+                                      controllers[i].text.isEmpty;
+                                });
+                              },
+                              decoration: standardInputDecoration(
+                                "Enter index "
+                                "${resharerIndexes[i]}"
+                                "'s resharer",
+                                focusNodes[i],
+                                context,
+                              ).copyWith(
+                                contentPadding: const EdgeInsets.only(
+                                  left: 16,
+                                  top: 6,
+                                  bottom: 8,
+                                  right: 5,
+                                ),
+                                suffixIcon: Padding(
+                                  padding: fieldIsEmptyFlags[i]
+                                      ? const EdgeInsets.only(right: 8)
+                                      : const EdgeInsets.only(right: 0),
+                                  child: UnconstrainedBox(
+                                    child: Row(
+                                      mainAxisAlignment:
+                                          MainAxisAlignment.spaceAround,
+                                      children: [
+                                        !fieldIsEmptyFlags[i]
+                                            ? TextFieldIconButton(
+                                                semanticsLabel:
+                                                    "Clear Button. Clears The Resharer Field Input.",
+                                                key: Key(
+                                                    "frostResharerClearButtonKey_$i"),
+                                                onTap: () {
+                                                  controllers[i].text = "";
+
+                                                  setState(() {
+                                                    fieldIsEmptyFlags[i] = true;
+                                                  });
+                                                },
+                                                child: const XIcon(),
+                                              )
+                                            : TextFieldIconButton(
+                                                semanticsLabel:
+                                                    "Paste Button. Pastes From Clipboard To Resharer Field Input.",
+                                                key: Key(
+                                                    "frostResharerPasteButtonKey_$i"),
+                                                onTap: () async {
+                                                  final ClipboardData? data =
+                                                      await Clipboard.getData(
+                                                          Clipboard.kTextPlain);
+                                                  if (data?.text != null &&
+                                                      data!.text!.isNotEmpty) {
+                                                    controllers[i].text =
+                                                        data.text!.trim();
+                                                  }
+
+                                                  setState(() {
+                                                    fieldIsEmptyFlags[i] =
+                                                        controllers[i]
+                                                            .text
+                                                            .isEmpty;
+                                                  });
+                                                },
+                                                child: fieldIsEmptyFlags[i]
+                                                    ? const ClipboardIcon()
+                                                    : const XIcon(),
+                                              ),
+                                        if (fieldIsEmptyFlags[i])
+                                          TextFieldIconButton(
+                                            semanticsLabel: "Scan QR Button. "
+                                                "Opens Camera For Scanning QR Code.",
+                                            key: Key(
+                                                "frostCommitmentsScanQrButtonKey_$i"),
+                                            onTap: () async {
+                                              try {
+                                                if (FocusScope.of(context)
+                                                    .hasFocus) {
+                                                  FocusScope.of(context)
+                                                      .unfocus();
+                                                  await Future<void>.delayed(
+                                                      const Duration(
+                                                          milliseconds: 75));
+                                                }
+
+                                                final qrResult =
+                                                    await BarcodeScanner.scan();
+
+                                                controllers[i].text =
+                                                    qrResult.rawContent;
+
+                                                setState(() {
+                                                  fieldIsEmptyFlags[i] =
+                                                      controllers[i]
+                                                          .text
+                                                          .isEmpty;
+                                                });
+                                              } on PlatformException catch (e, s) {
+                                                Logging.instance.log(
+                                                  "Failed to get camera permissions "
+                                                  "while trying to scan qr code: $e\n$s",
+                                                  level: LogLevel.Warning,
+                                                );
+                                              }
+                                            },
+                                            child: const QrCodeIcon(),
+                                          ),
+                                      ],
+                                    ),
+                                  ),
+                                ),
+                              ),
+                            ),
+                          ),
+                        ),
+                      ],
+                    ),
+                ],
+              ),
+              if (!Util.isDesktop) const Spacer(),
+              const _Div(),
+              PrimaryButton(
+                label: "Continue",
+                enabled: amOutgoingParticipant ||
+                    !fieldIsEmptyFlags.reduce((v, e) => v |= e),
+                onPressed: _onPressed,
+              ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+}
+
+class _Div extends StatelessWidget {
+  const _Div({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return const SizedBox(
+      height: 12,
+    );
+  }
+}
diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_2/continue_resharing_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_2/continue_resharing_view.dart
new file mode 100644
index 000000000..75359d266
--- /dev/null
+++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_2/continue_resharing_view.dart
@@ -0,0 +1,429 @@
+import 'dart:ffi';
+
+import 'package:barcode_scan2/barcode_scan2.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:qr_flutter/qr_flutter.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/finish_resharing_view.dart';
+import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
+import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/services/frost.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/detail_item.dart';
+import 'package:stackwallet/widgets/dialogs/frost_interruption_dialog.dart';
+import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+import 'package:stackwallet/widgets/stack_text_field.dart';
+import 'package:stackwallet/widgets/textfield_icon_button.dart';
+
+class ContinueResharingView extends ConsumerStatefulWidget {
+  const ContinueResharingView({
+    super.key,
+    required this.walletId,
+  });
+
+  static const String routeName = "/continueResharingView";
+
+  final String walletId;
+
+  @override
+  ConsumerState<ContinueResharingView> createState() =>
+      _ContinueResharingViewState();
+}
+
+class _ContinueResharingViewState extends ConsumerState<ContinueResharingView> {
+  final List<TextEditingController> controllers = [];
+  final List<FocusNode> focusNodes = [];
+
+  late final List<String> newParticipants;
+  late final int myIndex;
+  late final String? myEncryptionKey;
+  late final bool amOutgoingParticipant;
+
+  final List<bool> fieldIsEmptyFlags = [];
+
+  bool _buttonLock = false;
+  Future<void> _onPressed() async {
+    if (_buttonLock) {
+      return;
+    }
+    _buttonLock = true;
+
+    try {
+      // collect encryptionKeys strings and insert my own at the correct index
+      final encryptionKeys = controllers.map((e) => e.text).toList();
+      if (!amOutgoingParticipant) {
+        encryptionKeys.insert(myIndex, myEncryptionKey!);
+      }
+
+      final result = Frost.finishResharer(
+        machine: ref.read(pFrostResharingData).startResharerData!.machine.ref,
+        encryptionKeysOfResharedTo: encryptionKeys,
+      );
+
+      ref.read(pFrostResharingData).resharerComplete = result;
+
+      await Navigator.of(context).pushNamed(
+        FinishResharingView.routeName,
+        arguments: widget.walletId,
+      );
+    } catch (e, s) {
+      Logging.instance.log(
+        "$e\n$s",
+        level: LogLevel.Fatal,
+      );
+
+      await showDialog<void>(
+        context: context,
+        builder: (_) => StackOkDialog(
+          title: "Error",
+          message: e.toString(),
+          desktopPopRootNavigator: Util.isDesktop,
+        ),
+      );
+    } finally {
+      _buttonLock = false;
+    }
+  }
+
+  @override
+  void initState() {
+    myEncryptionKey =
+        ref.read(pFrostResharingData).startResharedData?.resharedStart;
+
+    newParticipants = ref.read(pFrostResharingData).configData!.newParticipants;
+    myIndex = newParticipants.indexOf(ref.read(pFrostResharingData).myName!);
+
+    if (myIndex >= 0) {
+      // remove my name for now as we don't need a text field for it
+      newParticipants.removeAt(myIndex);
+    }
+
+    if (myEncryptionKey == null && myIndex == -1) {
+      amOutgoingParticipant = true;
+    } else if (myEncryptionKey != null && myIndex >= 0) {
+      amOutgoingParticipant = false;
+    } else {
+      throw Exception("Invalid resharing state");
+    }
+
+    for (int i = 0; i < newParticipants.length; i++) {
+      controllers.add(TextEditingController());
+      focusNodes.add(FocusNode());
+      fieldIsEmptyFlags.add(true);
+    }
+    super.initState();
+  }
+
+  @override
+  void dispose() {
+    for (int i = 0; i < controllers.length; i++) {
+      controllers[i].dispose();
+    }
+    for (int i = 0; i < focusNodes.length; i++) {
+      focusNodes[i].dispose();
+    }
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return WillPopScope(
+      onWillPop: () async {
+        await showDialog<void>(
+          context: context,
+          builder: (_) => FrostInterruptionDialog(
+            type: FrostInterruptionDialogType.resharing,
+            popUntilOnYesRouteName: Util.isDesktop
+                ? DesktopWalletView.routeName
+                : WalletView.routeName,
+          ),
+        );
+        return false;
+      },
+      child: ConditionalParent(
+        condition: Util.isDesktop,
+        builder: (child) => DesktopScaffold(
+          background: Theme.of(context).extension<StackColors>()!.background,
+          appBar: DesktopAppBar(
+            isCompactHeight: false,
+            leading: AppBarBackButton(
+              onPressed: () async {
+                await showDialog<void>(
+                  context: context,
+                  builder: (_) => const FrostInterruptionDialog(
+                    type: FrostInterruptionDialogType.resharing,
+                    popUntilOnYesRouteName: DesktopWalletView.routeName,
+                  ),
+                );
+              },
+            ),
+          ),
+          body: SizedBox(
+            width: 480,
+            child: child,
+          ),
+        ),
+        child: ConditionalParent(
+          condition: !Util.isDesktop,
+          builder: (child) => Background(
+            child: Scaffold(
+              backgroundColor:
+                  Theme.of(context).extension<StackColors>()!.background,
+              appBar: AppBar(
+                leading: AppBarBackButton(
+                  onPressed: () async {
+                    await showDialog<void>(
+                      context: context,
+                      builder: (_) => const FrostInterruptionDialog(
+                        type: FrostInterruptionDialogType.resharing,
+                        popUntilOnYesRouteName: WalletView.routeName,
+                      ),
+                    );
+                  },
+                ),
+                title: Text(
+                  "Encryption keys",
+                  style: STextStyles.navBarTitle(context),
+                ),
+              ),
+              body: SafeArea(
+                child: LayoutBuilder(
+                  builder: (context, constraints) {
+                    return SingleChildScrollView(
+                      child: ConstrainedBox(
+                        constraints: BoxConstraints(
+                          minHeight: constraints.maxHeight,
+                        ),
+                        child: IntrinsicHeight(
+                          child: Padding(
+                            padding: const EdgeInsets.all(16),
+                            child: child,
+                          ),
+                        ),
+                      ),
+                    );
+                  },
+                ),
+              ),
+            ),
+          ),
+          child: Column(
+            children: [
+              if (!amOutgoingParticipant)
+                SizedBox(
+                  height: 220,
+                  child: Row(
+                    mainAxisAlignment: MainAxisAlignment.center,
+                    children: [
+                      QrImageView(
+                        data: myEncryptionKey!,
+                        size: 220,
+                        backgroundColor: Theme.of(context)
+                            .extension<StackColors>()!
+                            .background,
+                        foregroundColor: Theme.of(context)
+                            .extension<StackColors>()!
+                            .accentColorDark,
+                      ),
+                    ],
+                  ),
+                ),
+              if (!amOutgoingParticipant) const _Div(),
+              if (!amOutgoingParticipant)
+                DetailItem(
+                  title: "My encryption key",
+                  detail: myEncryptionKey!,
+                  button: Util.isDesktop
+                      ? IconCopyButton(
+                          data: myEncryptionKey!,
+                        )
+                      : SimpleCopyButton(
+                          data: myEncryptionKey!,
+                        ),
+                ),
+              if (!amOutgoingParticipant) const _Div(),
+              Column(
+                mainAxisSize: MainAxisSize.min,
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  for (int i = 0; i < newParticipants.length; i++)
+                    Column(
+                      mainAxisSize: MainAxisSize.min,
+                      crossAxisAlignment: CrossAxisAlignment.start,
+                      children: [
+                        Padding(
+                          padding: const EdgeInsets.symmetric(vertical: 8),
+                          child: ClipRRect(
+                            borderRadius: BorderRadius.circular(
+                              Constants.size.circularBorderRadius,
+                            ),
+                            child: TextField(
+                              key: Key("frostEncryptionKeyTextFieldKey_$i"),
+                              controller: controllers[i],
+                              focusNode: focusNodes[i],
+                              readOnly: false,
+                              autocorrect: false,
+                              enableSuggestions: false,
+                              style: STextStyles.field(context),
+                              onChanged: (_) {
+                                setState(() {
+                                  fieldIsEmptyFlags[i] =
+                                      controllers[i].text.isEmpty;
+                                });
+                              },
+                              decoration: standardInputDecoration(
+                                "Enter "
+                                "${newParticipants[i]}"
+                                "'s encryption key",
+                                focusNodes[i],
+                                context,
+                              ).copyWith(
+                                contentPadding: const EdgeInsets.only(
+                                  left: 16,
+                                  top: 6,
+                                  bottom: 8,
+                                  right: 5,
+                                ),
+                                suffixIcon: Padding(
+                                  padding: fieldIsEmptyFlags[i]
+                                      ? const EdgeInsets.only(right: 8)
+                                      : const EdgeInsets.only(right: 0),
+                                  child: UnconstrainedBox(
+                                    child: Row(
+                                      mainAxisAlignment:
+                                          MainAxisAlignment.spaceAround,
+                                      children: [
+                                        !fieldIsEmptyFlags[i]
+                                            ? TextFieldIconButton(
+                                                semanticsLabel:
+                                                    "Clear Button. Clears The Encryption Key Field Input.",
+                                                key: Key(
+                                                    "frostEncryptionKeyClearButtonKey_$i"),
+                                                onTap: () {
+                                                  controllers[i].text = "";
+
+                                                  setState(() {
+                                                    fieldIsEmptyFlags[i] = true;
+                                                  });
+                                                },
+                                                child: const XIcon(),
+                                              )
+                                            : TextFieldIconButton(
+                                                semanticsLabel:
+                                                    "Paste Button. Pastes From Clipboard To Encryption Key Field Input.",
+                                                key: Key(
+                                                    "frostEncryptionKeyPasteButtonKey_$i"),
+                                                onTap: () async {
+                                                  final ClipboardData? data =
+                                                      await Clipboard.getData(
+                                                          Clipboard.kTextPlain);
+                                                  if (data?.text != null &&
+                                                      data!.text!.isNotEmpty) {
+                                                    controllers[i].text =
+                                                        data.text!.trim();
+                                                  }
+
+                                                  setState(() {
+                                                    fieldIsEmptyFlags[i] =
+                                                        controllers[i]
+                                                            .text
+                                                            .isEmpty;
+                                                  });
+                                                },
+                                                child: fieldIsEmptyFlags[i]
+                                                    ? const ClipboardIcon()
+                                                    : const XIcon(),
+                                              ),
+                                        if (fieldIsEmptyFlags[i])
+                                          TextFieldIconButton(
+                                            semanticsLabel: "Scan QR Button. "
+                                                "Opens Camera For Scanning QR Code.",
+                                            key: Key(
+                                                "frostCommitmentsScanQrButtonKey_$i"),
+                                            onTap: () async {
+                                              try {
+                                                if (FocusScope.of(context)
+                                                    .hasFocus) {
+                                                  FocusScope.of(context)
+                                                      .unfocus();
+                                                  await Future<void>.delayed(
+                                                      const Duration(
+                                                          milliseconds: 75));
+                                                }
+
+                                                final qrResult =
+                                                    await BarcodeScanner.scan();
+
+                                                controllers[i].text =
+                                                    qrResult.rawContent;
+
+                                                setState(() {
+                                                  fieldIsEmptyFlags[i] =
+                                                      controllers[i]
+                                                          .text
+                                                          .isEmpty;
+                                                });
+                                              } on PlatformException catch (e, s) {
+                                                Logging.instance.log(
+                                                  "Failed to get camera permissions "
+                                                  "while trying to scan qr code: $e\n$s",
+                                                  level: LogLevel.Warning,
+                                                );
+                                              }
+                                            },
+                                            child: const QrCodeIcon(),
+                                          ),
+                                      ],
+                                    ),
+                                  ),
+                                ),
+                              ),
+                            ),
+                          ),
+                        ),
+                      ],
+                    ),
+                ],
+              ),
+              if (!Util.isDesktop) const Spacer(),
+              const _Div(),
+              PrimaryButton(
+                label: "Continue",
+                enabled: !fieldIsEmptyFlags.reduce((v, e) => v |= e),
+                onPressed: _onPressed,
+              ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+}
+
+class _Div extends StatelessWidget {
+  const _Div({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return const SizedBox(
+      height: 12,
+    );
+  }
+}
diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_continue_sharing_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_continue_sharing_view.dart
new file mode 100644
index 000000000..86ff2ebe0
--- /dev/null
+++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_continue_sharing_view.dart
@@ -0,0 +1,204 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:qr_flutter/qr_flutter.dart';
+import 'package:stackwallet/pages/home_view/home_view.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/finish_resharing_view.dart';
+import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
+import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/detail_item.dart';
+import 'package:stackwallet/widgets/dialogs/frost_interruption_dialog.dart';
+
+class NewContinueSharingView extends ConsumerStatefulWidget {
+  const NewContinueSharingView({
+    super.key,
+    required this.walletId,
+  });
+
+  static const String routeName = "/NewContinueSharingView";
+
+  final String walletId;
+
+  @override
+  ConsumerState<NewContinueSharingView> createState() =>
+      _NewContinueSharingViewState();
+}
+
+class _NewContinueSharingViewState
+    extends ConsumerState<NewContinueSharingView> {
+  @override
+  Widget build(BuildContext context) {
+    return WillPopScope(
+      onWillPop: () async {
+        await showDialog<void>(
+          context: context,
+          builder: (_) => FrostInterruptionDialog(
+            type: FrostInterruptionDialogType.resharing,
+            popUntilOnYesRouteName:
+                Util.isDesktop ? DesktopHomeView.routeName : HomeView.routeName,
+          ),
+        );
+        return false;
+      },
+      child: ConditionalParent(
+        condition: Util.isDesktop,
+        builder: (child) => DesktopScaffold(
+          background: Theme.of(context).extension<StackColors>()!.background,
+          appBar: DesktopAppBar(
+            isCompactHeight: false,
+            leading: AppBarBackButton(
+              onPressed: () async {
+                await showDialog<void>(
+                  context: context,
+                  builder: (_) => const FrostInterruptionDialog(
+                    type: FrostInterruptionDialogType.resharing,
+                    popUntilOnYesRouteName: DesktopHomeView.routeName,
+                  ),
+                );
+              },
+            ),
+            trailing: ExitToMyStackButton(
+              onPressed: () async {
+                await showDialog<void>(
+                  context: context,
+                  builder: (_) => const FrostInterruptionDialog(
+                    type: FrostInterruptionDialogType.resharing,
+                    popUntilOnYesRouteName: DesktopHomeView.routeName,
+                  ),
+                );
+              },
+            ),
+          ),
+          body: SizedBox(
+            width: 480,
+            child: child,
+          ),
+        ),
+        child: ConditionalParent(
+          condition: !Util.isDesktop,
+          builder: (child) => Background(
+            child: Scaffold(
+              backgroundColor:
+                  Theme.of(context).extension<StackColors>()!.background,
+              appBar: AppBar(
+                leading: AppBarBackButton(
+                  onPressed: () async {
+                    await showDialog<void>(
+                      context: context,
+                      builder: (_) => const FrostInterruptionDialog(
+                        type: FrostInterruptionDialogType.resharing,
+                        popUntilOnYesRouteName: HomeView.routeName,
+                      ),
+                    );
+                  },
+                ),
+                title: Text(
+                  "Encryption keys",
+                  style: STextStyles.navBarTitle(context),
+                ),
+              ),
+              body: SafeArea(
+                child: LayoutBuilder(
+                  builder: (context, constraints) {
+                    return SingleChildScrollView(
+                      child: ConstrainedBox(
+                        constraints: BoxConstraints(
+                          minHeight: constraints.maxHeight,
+                        ),
+                        child: IntrinsicHeight(
+                          child: Padding(
+                            padding: const EdgeInsets.all(16),
+                            child: child,
+                          ),
+                        ),
+                      ),
+                    );
+                  },
+                ),
+              ),
+            ),
+          ),
+          child: Column(
+            children: [
+              SizedBox(
+                height: 220,
+                child: Row(
+                  mainAxisAlignment: MainAxisAlignment.center,
+                  children: [
+                    QrImageView(
+                      data: ref
+                          .watch(pFrostResharingData)
+                          .startResharedData!
+                          .resharedStart,
+                      size: 220,
+                      backgroundColor: Theme.of(context)
+                          .extension<StackColors>()!
+                          .background,
+                      foregroundColor: Theme.of(context)
+                          .extension<StackColors>()!
+                          .accentColorDark,
+                    ),
+                  ],
+                ),
+              ),
+              const _Div(),
+              DetailItem(
+                title: "My encryption key",
+                detail: ref
+                    .watch(pFrostResharingData)
+                    .startResharedData!
+                    .resharedStart,
+                button: Util.isDesktop
+                    ? IconCopyButton(
+                        data: ref
+                            .watch(pFrostResharingData)
+                            .startResharedData!
+                            .resharedStart,
+                      )
+                    : SimpleCopyButton(
+                        data: ref
+                            .watch(pFrostResharingData)
+                            .startResharedData!
+                            .resharedStart,
+                      ),
+              ),
+              if (!Util.isDesktop) const Spacer(),
+              const _Div(),
+              PrimaryButton(
+                label: "Continue",
+                onPressed: () {
+                  Navigator.of(context).pushNamed(
+                    FinishResharingView.routeName,
+                    arguments: widget.walletId,
+                  );
+                },
+              ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+}
+
+class _Div extends StatelessWidget {
+  const _Div({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return const SizedBox(
+      height: 12,
+    );
+  }
+}
diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_import_resharer_config_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_import_resharer_config_view.dart
new file mode 100644
index 000000000..f3ef1ec0b
--- /dev/null
+++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_import_resharer_config_view.dart
@@ -0,0 +1,426 @@
+import 'package:barcode_scan2/barcode_scan2.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_start_resharing_view.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/show_loading.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/wallets/isar/models/wallet_info.dart';
+import 'package:stackwallet/wallets/models/incomplete_frost_wallet.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+import 'package:stackwallet/widgets/stack_text_field.dart';
+import 'package:stackwallet/widgets/textfield_icon_button.dart';
+
+class NewImportResharerConfigView extends ConsumerStatefulWidget {
+  const NewImportResharerConfigView({
+    super.key,
+    required this.walletName,
+    required this.coin,
+  });
+
+  static const String routeName = "/newImportResharerConfigView";
+
+  final String walletName;
+  final Coin coin;
+
+  @override
+  ConsumerState<NewImportResharerConfigView> createState() =>
+      _NewImportResharerConfigViewState();
+}
+
+class _NewImportResharerConfigViewState
+    extends ConsumerState<NewImportResharerConfigView> {
+  late final TextEditingController myNameFieldController, configFieldController;
+  late final FocusNode myNameFocusNode, configFocusNode;
+
+  bool _nameEmpty = true, _configEmpty = true;
+
+  bool _buttonLock = false;
+
+  Future<IncompleteFrostWallet> _createWallet() async {
+    final info = WalletInfo.createNew(
+      name: widget.walletName,
+      coin: widget.coin,
+    );
+
+    final wallet = IncompleteFrostWallet();
+    wallet.info = info;
+
+    return wallet;
+  }
+
+  @override
+  void initState() {
+    myNameFieldController = TextEditingController();
+    configFieldController = TextEditingController();
+    myNameFocusNode = FocusNode();
+    configFocusNode = FocusNode();
+    super.initState();
+  }
+
+  @override
+  void dispose() {
+    myNameFieldController.dispose();
+    configFieldController.dispose();
+    myNameFocusNode.dispose();
+    configFocusNode.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return ConditionalParent(
+      condition: Util.isDesktop,
+      builder: (child) => DesktopScaffold(
+        background: Theme.of(context).extension<StackColors>()!.background,
+        appBar: const DesktopAppBar(
+          isCompactHeight: false,
+          leading: AppBarBackButton(),
+          trailing: ExitToMyStackButton(),
+        ),
+        body: SizedBox(
+          width: 480,
+          child: child,
+        ),
+      ),
+      child: ConditionalParent(
+        condition: !Util.isDesktop,
+        builder: (child) => Background(
+          child: Scaffold(
+            backgroundColor:
+                Theme.of(context).extension<StackColors>()!.background,
+            appBar: AppBar(
+              leading: AppBarBackButton(
+                onPressed: () {
+                  Navigator.of(context).pop();
+                },
+              ),
+              title: Text(
+                "Import FROST reshare config",
+                style: STextStyles.navBarTitle(context),
+              ),
+            ),
+            body: SafeArea(
+              child: LayoutBuilder(
+                builder: (context, constraints) {
+                  return SingleChildScrollView(
+                    child: ConstrainedBox(
+                      constraints: BoxConstraints(
+                        minHeight: constraints.maxHeight,
+                      ),
+                      child: IntrinsicHeight(
+                        child: Padding(
+                          padding: const EdgeInsets.all(16),
+                          child: child,
+                        ),
+                      ),
+                    ),
+                  );
+                },
+              ),
+            ),
+          ),
+        ),
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            const SizedBox(
+              height: 16,
+            ),
+            ClipRRect(
+              borderRadius: BorderRadius.circular(
+                Constants.size.circularBorderRadius,
+              ),
+              child: TextField(
+                key: const Key("frMyNameTextFieldKey"),
+                controller: myNameFieldController,
+                onChanged: (_) {
+                  setState(() {
+                    _nameEmpty = myNameFieldController.text.isEmpty;
+                  });
+                },
+                focusNode: myNameFocusNode,
+                readOnly: false,
+                autocorrect: false,
+                enableSuggestions: false,
+                style: STextStyles.field(context),
+                decoration: standardInputDecoration(
+                  "My name",
+                  myNameFocusNode,
+                  context,
+                ).copyWith(
+                  contentPadding: const EdgeInsets.only(
+                    left: 16,
+                    top: 6,
+                    bottom: 8,
+                    right: 5,
+                  ),
+                  suffixIcon: Padding(
+                    padding: _nameEmpty
+                        ? const EdgeInsets.only(right: 8)
+                        : const EdgeInsets.only(right: 0),
+                    child: UnconstrainedBox(
+                      child: Row(
+                        mainAxisAlignment: MainAxisAlignment.spaceAround,
+                        children: [
+                          !_nameEmpty
+                              ? TextFieldIconButton(
+                                  semanticsLabel:
+                                      "Clear Button. Clears The Config Field.",
+                                  key: const Key("frMyNameClearButtonKey"),
+                                  onTap: () {
+                                    myNameFieldController.text = "";
+
+                                    setState(() {
+                                      _nameEmpty = true;
+                                    });
+                                  },
+                                  child: const XIcon(),
+                                )
+                              : TextFieldIconButton(
+                                  semanticsLabel:
+                                      "Paste Button. Pastes From Clipboard To Name Field.",
+                                  key: const Key("frMyNamePasteButtonKey"),
+                                  onTap: () async {
+                                    final ClipboardData? data =
+                                        await Clipboard.getData(
+                                            Clipboard.kTextPlain);
+                                    if (data?.text != null &&
+                                        data!.text!.isNotEmpty) {
+                                      myNameFieldController.text =
+                                          data.text!.trim();
+                                    }
+
+                                    setState(() {
+                                      _nameEmpty =
+                                          myNameFieldController.text.isEmpty;
+                                    });
+                                  },
+                                  child: _nameEmpty
+                                      ? const ClipboardIcon()
+                                      : const XIcon(),
+                                ),
+                        ],
+                      ),
+                    ),
+                  ),
+                ),
+              ),
+            ),
+            const SizedBox(
+              height: 16,
+            ),
+            ClipRRect(
+              borderRadius: BorderRadius.circular(
+                Constants.size.circularBorderRadius,
+              ),
+              child: TextField(
+                key: const Key("frConfigTextFieldKey"),
+                controller: configFieldController,
+                onChanged: (_) {
+                  setState(() {
+                    _configEmpty = configFieldController.text.isEmpty;
+                  });
+                },
+                focusNode: configFocusNode,
+                readOnly: false,
+                autocorrect: false,
+                enableSuggestions: false,
+                style: STextStyles.field(context),
+                decoration: standardInputDecoration(
+                  "Enter config",
+                  configFocusNode,
+                  context,
+                ).copyWith(
+                  contentPadding: const EdgeInsets.only(
+                    left: 16,
+                    top: 6,
+                    bottom: 8,
+                    right: 5,
+                  ),
+                  suffixIcon: Padding(
+                    padding: _configEmpty
+                        ? const EdgeInsets.only(right: 8)
+                        : const EdgeInsets.only(right: 0),
+                    child: UnconstrainedBox(
+                      child: Row(
+                        mainAxisAlignment: MainAxisAlignment.spaceAround,
+                        children: [
+                          !_configEmpty
+                              ? TextFieldIconButton(
+                                  semanticsLabel:
+                                      "Clear Button. Clears The Config Field.",
+                                  key: const Key("frConfigClearButtonKey"),
+                                  onTap: () {
+                                    configFieldController.text = "";
+
+                                    setState(() {
+                                      _configEmpty = true;
+                                    });
+                                  },
+                                  child: const XIcon(),
+                                )
+                              : TextFieldIconButton(
+                                  semanticsLabel:
+                                      "Paste Button. Pastes From Clipboard To Config Field Input.",
+                                  key: const Key("frConfigPasteButtonKey"),
+                                  onTap: () async {
+                                    final ClipboardData? data =
+                                        await Clipboard.getData(
+                                            Clipboard.kTextPlain);
+                                    if (data?.text != null &&
+                                        data!.text!.isNotEmpty) {
+                                      configFieldController.text =
+                                          data.text!.trim();
+                                    }
+
+                                    setState(() {
+                                      _configEmpty =
+                                          configFieldController.text.isEmpty;
+                                    });
+                                  },
+                                  child: _configEmpty
+                                      ? const ClipboardIcon()
+                                      : const XIcon(),
+                                ),
+                          if (_configEmpty)
+                            TextFieldIconButton(
+                              semanticsLabel:
+                                  "Scan QR Button. Opens Camera For Scanning QR Code.",
+                              key: const Key("frConfigScanQrButtonKey"),
+                              onTap: () async {
+                                try {
+                                  if (FocusScope.of(context).hasFocus) {
+                                    FocusScope.of(context).unfocus();
+                                    await Future<void>.delayed(
+                                        const Duration(milliseconds: 75));
+                                  }
+
+                                  final qrResult = await BarcodeScanner.scan();
+
+                                  configFieldController.text =
+                                      qrResult.rawContent;
+
+                                  setState(() {
+                                    _configEmpty =
+                                        configFieldController.text.isEmpty;
+                                  });
+                                } on PlatformException catch (e, s) {
+                                  Logging.instance.log(
+                                    "Failed to get camera permissions while trying to scan qr code: $e\n$s",
+                                    level: LogLevel.Warning,
+                                  );
+                                }
+                              },
+                              child: const QrCodeIcon(),
+                            )
+                        ],
+                      ),
+                    ),
+                  ),
+                ),
+              ),
+            ),
+            const SizedBox(
+              height: 16,
+            ),
+            if (!Util.isDesktop) const Spacer(),
+            const SizedBox(
+              height: 16,
+            ),
+            PrimaryButton(
+              label: "Start",
+              enabled: !_nameEmpty && !_configEmpty,
+              onPressed: () async {
+                if (FocusScope.of(context).hasFocus) {
+                  FocusScope.of(context).unfocus();
+                }
+                if (_buttonLock) {
+                  return;
+                }
+                _buttonLock = true;
+
+                try {
+                  ref.read(pFrostResharingData).reset();
+                  ref.read(pFrostResharingData).myName =
+                      myNameFieldController.text;
+                  ref.read(pFrostResharingData).resharerConfig =
+                      configFieldController.text;
+
+                  if (!ref
+                      .read(pFrostResharingData)
+                      .configData!
+                      .newParticipants
+                      .contains(ref.read(pFrostResharingData).myName!)) {
+                    ref.read(pFrostResharingData).reset();
+                    return await showDialog<void>(
+                      context: context,
+                      builder: (_) => StackOkDialog(
+                        title: "My name not found in config participants",
+                        desktopPopRootNavigator: Util.isDesktop,
+                      ),
+                    );
+                  }
+
+                  Exception? ex;
+                  final wallet = await showLoading(
+                    whileFuture: _createWallet(),
+                    context: context,
+                    message: "Setting up wallet",
+                    isDesktop: Util.isDesktop,
+                    onException: (e) => ex = e,
+                  );
+
+                  if (ex != null) {
+                    throw ex!;
+                  }
+
+                  if (mounted) {
+                    ref.read(pFrostResharingData).incompleteWallet = wallet!;
+                    await Navigator.of(context).pushNamed(
+                      NewStartResharingView.routeName,
+                      arguments: wallet.walletId,
+                    );
+                  }
+                } catch (e, s) {
+                  Logging.instance.log(
+                    "$e\n$s",
+                    level: LogLevel.Fatal,
+                  );
+
+                  if (mounted) {
+                    await showDialog<void>(
+                      context: context,
+                      builder: (_) => StackOkDialog(
+                        title: e.toString(),
+                        desktopPopRootNavigator: Util.isDesktop,
+                      ),
+                    );
+                  }
+                } finally {
+                  _buttonLock = false;
+                }
+              },
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_start_resharing_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_start_resharing_view.dart
new file mode 100644
index 000000000..fb6107c2c
--- /dev/null
+++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_start_resharing_view.dart
@@ -0,0 +1,379 @@
+import 'package:barcode_scan2/barcode_scan2.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:stackwallet/pages/home_view/home_view.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_continue_sharing_view.dart';
+import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/services/frost.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/dialogs/frost_interruption_dialog.dart';
+import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+import 'package:stackwallet/widgets/stack_text_field.dart';
+import 'package:stackwallet/widgets/textfield_icon_button.dart';
+
+class NewStartResharingView extends ConsumerStatefulWidget {
+  const NewStartResharingView({
+    super.key,
+    required this.walletId,
+  });
+
+  static const String routeName = "/newStartResharingView";
+
+  final String walletId;
+
+  @override
+  ConsumerState<NewStartResharingView> createState() =>
+      _NewStartResharingViewState();
+}
+
+class _NewStartResharingViewState extends ConsumerState<NewStartResharingView> {
+  final List<TextEditingController> controllers = [];
+  final List<FocusNode> focusNodes = [];
+
+  late final List<int> resharerIndexes;
+
+  final List<bool> fieldIsEmptyFlags = [];
+
+  bool _buttonLock = false;
+  Future<void> _onPressed() async {
+    if (_buttonLock) {
+      return;
+    }
+    _buttonLock = true;
+
+    try {
+      // collect resharer strings
+      final resharerStarts = controllers.map((e) => e.text).toList();
+
+      final result = Frost.beginReshared(
+        myName: ref.read(pFrostResharingData).myName!,
+        resharerConfig: ref.read(pFrostResharingData).resharerConfig!,
+        resharerStarts: resharerStarts,
+      );
+
+      ref.read(pFrostResharingData).startResharedData = result;
+
+      await Navigator.of(context).pushNamed(
+        NewContinueSharingView.routeName,
+        arguments: widget.walletId,
+      );
+    } catch (e, s) {
+      Logging.instance.log(
+        "$e\n$s",
+        level: LogLevel.Fatal,
+      );
+
+      await showDialog<void>(
+        context: context,
+        builder: (_) => StackOkDialog(
+          title: "Error",
+          message: e.toString(),
+          desktopPopRootNavigator: Util.isDesktop,
+        ),
+      );
+    } finally {
+      _buttonLock = false;
+    }
+  }
+
+  @override
+  void initState() {
+    resharerIndexes = ref.read(pFrostResharingData).configData!.resharers;
+
+    for (int i = 0; i < resharerIndexes.length; i++) {
+      controllers.add(TextEditingController());
+      focusNodes.add(FocusNode());
+      fieldIsEmptyFlags.add(true);
+    }
+    super.initState();
+  }
+
+  @override
+  void dispose() {
+    for (int i = 0; i < controllers.length; i++) {
+      controllers[i].dispose();
+    }
+    for (int i = 0; i < focusNodes.length; i++) {
+      focusNodes[i].dispose();
+    }
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return WillPopScope(
+      onWillPop: () async {
+        await showDialog<void>(
+          context: context,
+          builder: (_) => FrostInterruptionDialog(
+            type: FrostInterruptionDialogType.resharing,
+            popUntilOnYesRouteName:
+                Util.isDesktop ? DesktopHomeView.routeName : HomeView.routeName,
+          ),
+        );
+        return false;
+      },
+      child: ConditionalParent(
+        condition: Util.isDesktop,
+        builder: (child) => DesktopScaffold(
+          background: Theme.of(context).extension<StackColors>()!.background,
+          appBar: DesktopAppBar(
+            isCompactHeight: false,
+            leading: AppBarBackButton(
+              onPressed: () async {
+                await showDialog<void>(
+                  context: context,
+                  builder: (_) => const FrostInterruptionDialog(
+                    type: FrostInterruptionDialogType.resharing,
+                    popUntilOnYesRouteName: DesktopHomeView.routeName,
+                  ),
+                );
+              },
+            ),
+            trailing: ExitToMyStackButton(
+              onPressed: () async {
+                await showDialog<void>(
+                  context: context,
+                  builder: (_) => const FrostInterruptionDialog(
+                    type: FrostInterruptionDialogType.resharing,
+                    popUntilOnYesRouteName: DesktopHomeView.routeName,
+                  ),
+                );
+              },
+            ),
+          ),
+          body: SizedBox(
+            width: 480,
+            child: child,
+          ),
+        ),
+        child: ConditionalParent(
+          condition: !Util.isDesktop,
+          builder: (child) => Background(
+            child: Scaffold(
+              backgroundColor:
+                  Theme.of(context).extension<StackColors>()!.background,
+              appBar: AppBar(
+                leading: AppBarBackButton(
+                  onPressed: () async {
+                    await showDialog<void>(
+                      context: context,
+                      builder: (_) => const FrostInterruptionDialog(
+                        type: FrostInterruptionDialogType.resharing,
+                        popUntilOnYesRouteName: HomeView.routeName,
+                      ),
+                    );
+                  },
+                ),
+                title: Text(
+                  "Resharers",
+                  style: STextStyles.navBarTitle(context),
+                ),
+              ),
+              body: SafeArea(
+                child: LayoutBuilder(
+                  builder: (context, constraints) {
+                    return SingleChildScrollView(
+                      child: ConstrainedBox(
+                        constraints: BoxConstraints(
+                          minHeight: constraints.maxHeight,
+                        ),
+                        child: IntrinsicHeight(
+                          child: Padding(
+                            padding: const EdgeInsets.all(16),
+                            child: child,
+                          ),
+                        ),
+                      ),
+                    );
+                  },
+                ),
+              ),
+            ),
+          ),
+          child: Column(
+            children: [
+              Column(
+                mainAxisSize: MainAxisSize.min,
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  for (int i = 0; i < resharerIndexes.length; i++)
+                    Column(
+                      mainAxisSize: MainAxisSize.min,
+                      crossAxisAlignment: CrossAxisAlignment.start,
+                      children: [
+                        Padding(
+                          padding: const EdgeInsets.symmetric(vertical: 8),
+                          child: ClipRRect(
+                            borderRadius: BorderRadius.circular(
+                              Constants.size.circularBorderRadius,
+                            ),
+                            child: TextField(
+                              key: Key("frostResharerTextFieldKey_$i"),
+                              controller: controllers[i],
+                              focusNode: focusNodes[i],
+                              readOnly: false,
+                              autocorrect: false,
+                              enableSuggestions: false,
+                              style: STextStyles.field(context),
+                              onChanged: (_) {
+                                setState(() {
+                                  fieldIsEmptyFlags[i] =
+                                      controllers[i].text.isEmpty;
+                                });
+                              },
+                              decoration: standardInputDecoration(
+                                "Enter index "
+                                "${resharerIndexes[i]}"
+                                "'s resharer",
+                                focusNodes[i],
+                                context,
+                              ).copyWith(
+                                contentPadding: const EdgeInsets.only(
+                                  left: 16,
+                                  top: 6,
+                                  bottom: 8,
+                                  right: 5,
+                                ),
+                                suffixIcon: Padding(
+                                  padding: fieldIsEmptyFlags[i]
+                                      ? const EdgeInsets.only(right: 8)
+                                      : const EdgeInsets.only(right: 0),
+                                  child: UnconstrainedBox(
+                                    child: Row(
+                                      mainAxisAlignment:
+                                          MainAxisAlignment.spaceAround,
+                                      children: [
+                                        !fieldIsEmptyFlags[i]
+                                            ? TextFieldIconButton(
+                                                semanticsLabel:
+                                                    "Clear Button. Clears The Resharer Field Input.",
+                                                key: Key(
+                                                    "frostResharerClearButtonKey_$i"),
+                                                onTap: () {
+                                                  controllers[i].text = "";
+
+                                                  setState(() {
+                                                    fieldIsEmptyFlags[i] = true;
+                                                  });
+                                                },
+                                                child: const XIcon(),
+                                              )
+                                            : TextFieldIconButton(
+                                                semanticsLabel:
+                                                    "Paste Button. Pastes From Clipboard To Resharer Field Input.",
+                                                key: Key(
+                                                    "frostResharerPasteButtonKey_$i"),
+                                                onTap: () async {
+                                                  final ClipboardData? data =
+                                                      await Clipboard.getData(
+                                                          Clipboard.kTextPlain);
+                                                  if (data?.text != null &&
+                                                      data!.text!.isNotEmpty) {
+                                                    controllers[i].text =
+                                                        data.text!.trim();
+                                                  }
+
+                                                  setState(() {
+                                                    fieldIsEmptyFlags[i] =
+                                                        controllers[i]
+                                                            .text
+                                                            .isEmpty;
+                                                  });
+                                                },
+                                                child: fieldIsEmptyFlags[i]
+                                                    ? const ClipboardIcon()
+                                                    : const XIcon(),
+                                              ),
+                                        if (fieldIsEmptyFlags[i])
+                                          TextFieldIconButton(
+                                            semanticsLabel: "Scan QR Button. "
+                                                "Opens Camera For Scanning QR Code.",
+                                            key: Key(
+                                                "frostCommitmentsScanQrButtonKey_$i"),
+                                            onTap: () async {
+                                              try {
+                                                if (FocusScope.of(context)
+                                                    .hasFocus) {
+                                                  FocusScope.of(context)
+                                                      .unfocus();
+                                                  await Future<void>.delayed(
+                                                      const Duration(
+                                                          milliseconds: 75));
+                                                }
+
+                                                final qrResult =
+                                                    await BarcodeScanner.scan();
+
+                                                controllers[i].text =
+                                                    qrResult.rawContent;
+
+                                                setState(() {
+                                                  fieldIsEmptyFlags[i] =
+                                                      controllers[i]
+                                                          .text
+                                                          .isEmpty;
+                                                });
+                                              } on PlatformException catch (e, s) {
+                                                Logging.instance.log(
+                                                  "Failed to get camera permissions "
+                                                  "while trying to scan qr code: $e\n$s",
+                                                  level: LogLevel.Warning,
+                                                );
+                                              }
+                                            },
+                                            child: const QrCodeIcon(),
+                                          ),
+                                      ],
+                                    ),
+                                  ),
+                                ),
+                              ),
+                            ),
+                          ),
+                        ),
+                      ],
+                    ),
+                ],
+              ),
+              if (!Util.isDesktop) const Spacer(),
+              const _Div(),
+              PrimaryButton(
+                label: "Continue",
+                enabled: !fieldIsEmptyFlags.reduce((v, e) => v |= e),
+                onPressed: _onPressed,
+              ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+}
+
+class _Div extends StatelessWidget {
+  const _Div({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return const SizedBox(
+      height: 12,
+    );
+  }
+}
diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/verify_updated_wallet_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/verify_updated_wallet_view.dart
new file mode 100644
index 000000000..85d02c0ff
--- /dev/null
+++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/verify_updated_wallet_view.dart
@@ -0,0 +1,315 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:stackwallet/pages/home_view/home_view.dart';
+import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
+import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
+import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart';
+import 'package:stackwallet/providers/db/main_db_provider.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/providers/global/node_service_provider.dart';
+import 'package:stackwallet/providers/global/prefs_provider.dart';
+import 'package:stackwallet/providers/global/secure_store_provider.dart';
+import 'package:stackwallet/providers/global/wallets_provider.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/show_loading.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/detail_item.dart';
+import 'package:stackwallet/widgets/dialogs/frost_interruption_dialog.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+
+class VerifyUpdatedWalletView extends ConsumerStatefulWidget {
+  const VerifyUpdatedWalletView({
+    super.key,
+    required this.walletId,
+  });
+
+  static const String routeName = "/verifyUpdatedWalletView";
+
+  final String walletId;
+
+  @override
+  ConsumerState<VerifyUpdatedWalletView> createState() =>
+      _VerifyUpdatedWalletViewState();
+}
+
+class _VerifyUpdatedWalletViewState
+    extends ConsumerState<VerifyUpdatedWalletView> {
+  late final String config;
+  late final String serializedKeys;
+  late final String reshareId;
+
+  late final bool isNew;
+
+  bool _buttonLock = false;
+  Future<void> _onPressed() async {
+    if (_buttonLock) {
+      return;
+    }
+    _buttonLock = true;
+
+    try {
+      Exception? ex;
+
+      final BitcoinFrostWallet wallet;
+
+      if (isNew) {
+        wallet = await ref
+            .read(pFrostResharingData)
+            .incompleteWallet!
+            .toBitcoinFrostWallet(
+              mainDB: ref.read(mainDBProvider),
+              secureStorageInterface: ref.read(secureStoreProvider),
+              nodeService: ref.read(nodeServiceChangeNotifierProvider),
+              prefs: ref.read(prefsChangeNotifierProvider),
+            );
+
+        await wallet.info.setMnemonicVerified(
+          isar: ref.read(mainDBProvider).isar,
+        );
+
+        ref.read(pWallets).addWallet(wallet);
+      } else {
+        wallet =
+            ref.read(pWallets).getWallet(widget.walletId) as BitcoinFrostWallet;
+      }
+
+      if (mounted) {
+        await showLoading(
+          whileFuture: wallet.updateWithResharedData(
+            serializedKeys: serializedKeys,
+            multisigConfig: config,
+            isNewWallet: isNew,
+          ),
+          context: context,
+          message: isNew ? "Creating wallet" : "Updating wallet data",
+          isDesktop: Util.isDesktop,
+          onException: (e) => ex = e,
+        );
+
+        if (ex != null) {
+          throw ex!;
+        }
+
+        if (mounted) {
+          ref.read(pFrostResharingData).reset();
+
+          Navigator.of(context).popUntil(
+            ModalRoute.withName(
+              _popUntilPath,
+            ),
+          );
+        }
+      }
+    } catch (e, s) {
+      Logging.instance.log(
+        "$e\n$s",
+        level: LogLevel.Fatal,
+      );
+      if (mounted) {
+        await showDialog<void>(
+          context: context,
+          builder: (_) => StackOkDialog(
+            title: "Error",
+            message: e.toString(),
+            desktopPopRootNavigator: Util.isDesktop,
+          ),
+        );
+      }
+    } finally {
+      _buttonLock = false;
+    }
+  }
+
+  String get _popUntilPath => isNew
+      ? Util.isDesktop
+          ? DesktopHomeView.routeName
+          : HomeView.routeName
+      : Util.isDesktop
+          ? DesktopWalletView.routeName
+          : WalletView.routeName;
+
+  @override
+  void initState() {
+    config = ref.read(pFrostResharingData).newWalletData!.multisigConfig;
+    serializedKeys =
+        ref.read(pFrostResharingData).newWalletData!.serializedKeys;
+    reshareId = ref.read(pFrostResharingData).newWalletData!.resharedId;
+
+    isNew = ref.read(pFrostResharingData).incompleteWallet != null &&
+        ref.read(pFrostResharingData).incompleteWallet!.walletId ==
+            widget.walletId;
+
+    super.initState();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return WillPopScope(
+      onWillPop: () async {
+        await showDialog<void>(
+          context: context,
+          builder: (_) => FrostInterruptionDialog(
+            type: FrostInterruptionDialogType.resharing,
+            popUntilOnYesRouteName: _popUntilPath,
+          ),
+        );
+        return false;
+      },
+      child: ConditionalParent(
+        condition: Util.isDesktop,
+        builder: (child) => DesktopScaffold(
+          background: Theme.of(context).extension<StackColors>()!.background,
+          appBar: DesktopAppBar(
+            isCompactHeight: false,
+            leading: AppBarBackButton(
+              onPressed: () async {
+                await showDialog<void>(
+                  context: context,
+                  builder: (_) => FrostInterruptionDialog(
+                    type: FrostInterruptionDialogType.resharing,
+                    popUntilOnYesRouteName: _popUntilPath,
+                  ),
+                );
+              },
+            ),
+            trailing: ExitToMyStackButton(
+              onPressed: () async {
+                await showDialog<void>(
+                  context: context,
+                  builder: (_) => FrostInterruptionDialog(
+                    type: FrostInterruptionDialogType.resharing,
+                    popUntilOnYesRouteName: _popUntilPath,
+                  ),
+                );
+              },
+            ),
+          ),
+          body: SizedBox(
+            width: 480,
+            child: child,
+          ),
+        ),
+        child: ConditionalParent(
+          condition: !Util.isDesktop,
+          builder: (child) => Background(
+            child: Scaffold(
+              backgroundColor:
+                  Theme.of(context).extension<StackColors>()!.background,
+              appBar: AppBar(
+                leading: AppBarBackButton(
+                  onPressed: () async {
+                    await showDialog<void>(
+                      context: context,
+                      builder: (_) => FrostInterruptionDialog(
+                        type: FrostInterruptionDialogType.resharing,
+                        popUntilOnYesRouteName: _popUntilPath,
+                      ),
+                    );
+                  },
+                ),
+              ),
+              body: SafeArea(
+                child: LayoutBuilder(
+                  builder: (context, constraints) {
+                    return SingleChildScrollView(
+                      child: ConstrainedBox(
+                        constraints: BoxConstraints(
+                          minHeight: constraints.maxHeight,
+                        ),
+                        child: IntrinsicHeight(
+                          child: Padding(
+                            padding: const EdgeInsets.all(16),
+                            child: child,
+                          ),
+                        ),
+                      ),
+                    );
+                  },
+                ),
+              ),
+            ),
+          ),
+          child: Column(
+            children: [
+              Text(
+                "Ensure your reshare ID matches that of each other participant",
+                style: STextStyles.pageTitleH2(context),
+              ),
+              const _Div(),
+              DetailItem(
+                title: "ID",
+                detail: reshareId,
+                button: Util.isDesktop
+                    ? IconCopyButton(
+                        data: reshareId,
+                      )
+                    : SimpleCopyButton(
+                        data: reshareId,
+                      ),
+              ),
+              const _Div(),
+              const _Div(),
+              Text(
+                "Back up your keys and config",
+                style: STextStyles.pageTitleH2(context),
+              ),
+              const _Div(),
+              DetailItem(
+                title: "Config",
+                detail: config,
+                button: Util.isDesktop
+                    ? IconCopyButton(
+                        data: config,
+                      )
+                    : SimpleCopyButton(
+                        data: config,
+                      ),
+              ),
+              const _Div(),
+              DetailItem(
+                title: "Keys",
+                detail: serializedKeys,
+                button: Util.isDesktop
+                    ? IconCopyButton(
+                        data: serializedKeys,
+                      )
+                    : SimpleCopyButton(
+                        data: serializedKeys,
+                      ),
+              ),
+              if (!Util.isDesktop) const Spacer(),
+              const _Div(),
+              PrimaryButton(
+                label: "Confirm",
+                onPressed: _onPressed,
+              ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+}
+
+class _Div extends StatelessWidget {
+  const _Div({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return const SizedBox(
+      height: 12,
+    );
+  }
+}
diff --git a/lib/providers/frost_wallet/frost_wallet_providers.dart b/lib/providers/frost_wallet/frost_wallet_providers.dart
new file mode 100644
index 000000000..3b181b7b8
--- /dev/null
+++ b/lib/providers/frost_wallet/frost_wallet_providers.dart
@@ -0,0 +1,103 @@
+import 'dart:ffi';
+import 'dart:typed_data';
+
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:frostdart/frostdart_bindings_generated.dart';
+import 'package:stackwallet/services/frost.dart';
+import 'package:stackwallet/wallets/models/incomplete_frost_wallet.dart';
+import 'package:stackwallet/wallets/models/tx_data.dart';
+
+// =================== wallet creation =========================================
+final pFrostMultisigConfig = StateProvider<String?>((ref) => null);
+final pFrostMyName = StateProvider<String?>((ref) => null);
+
+final pFrostStartKeyGenData = StateProvider<
+    ({
+      String seed,
+      String commitments,
+      Pointer<MultisigConfigWithName> multisigConfigWithNamePtr,
+      Pointer<SecretShareMachineWrapper> secretShareMachineWrapperPtr,
+    })?>((_) => null);
+
+final pFrostSecretSharesData = StateProvider<
+    ({
+      String share,
+      Pointer<SecretSharesRes> secretSharesResPtr,
+    })?>((ref) => null);
+
+final pFrostCompletedKeyGenData = StateProvider<
+    ({
+      Uint8List multisigId,
+      String recoveryString,
+      String serializedKeys,
+    })?>((ref) => null);
+
+// ================= transaction creation ======================================
+final pFrostTxData = StateProvider<TxData?>((ref) => null);
+
+final pFrostAttemptSignData = StateProvider<
+    ({
+      Pointer<TransactionSignMachineWrapper> machinePtr,
+      String preprocess,
+    })?>((ref) => null);
+
+final pFrostContinueSignData = StateProvider<
+    ({
+      Pointer<TransactionSignatureMachineWrapper> machinePtr,
+      String share,
+    })?>((ref) => null);
+
+// ===================== shared/util ===========================================
+final pFrostSelectParticipantsUnordered =
+    StateProvider<List<String>?>((ref) => null);
+
+// ========================= resharing =========================================
+final pFrostResharingData = Provider((ref) => _ResharingData());
+
+class _ResharingData {
+  String? myName;
+
+  IncompleteFrostWallet? incompleteWallet;
+
+  // resharer encoded config string
+  String? resharerConfig;
+  ({
+    int newThreshold,
+    List<int> resharers,
+    List<String> newParticipants,
+  })? get configData => resharerConfig != null
+      ? Frost.extractResharerConfigData(resharerConfig: resharerConfig!)
+      : null;
+
+  // resharer start string (for sharing) and machine
+  ({
+    String resharerStart,
+    Pointer<StartResharerRes> machine,
+  })? startResharerData;
+
+  // reshared start string (for sharing) and machine
+  ({
+    String resharedStart,
+    Pointer<StartResharedRes> prior,
+  })? startResharedData;
+
+  // resharer complete string (for sharing)
+  String? resharerComplete;
+
+  // new keys and config with an ID
+  ({
+    String multisigConfig,
+    String serializedKeys,
+    String resharedId,
+  })? newWalletData;
+
+  // reset/clear all data
+  void reset() {
+    resharerConfig = null;
+    startResharerData = null;
+    startResharedData = null;
+    resharerComplete = null;
+    newWalletData = null;
+    incompleteWallet = null;
+  }
+}
diff --git a/lib/route_generator.dart b/lib/route_generator.dart
index a046cc01d..faf8967e8 100644
--- a/lib/route_generator.dart
+++ b/lib/route_generator.dart
@@ -26,6 +26,13 @@ import 'package:stackwallet/pages/add_wallet_views/add_token_view/add_custom_tok
 import 'package:stackwallet/pages/add_wallet_views/add_token_view/edit_wallet_tokens_view.dart';
 import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart';
 import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/create_or_restore_wallet_view.dart';
+import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/confirm_new_frost_ms_wallet_creation_view.dart';
+import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/create_new_frost_ms_wallet_view.dart';
+import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/frost_share_commitments_view.dart';
+import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/frost_share_shares_view.dart';
+import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/import_new_frost_ms_wallet_view.dart';
+import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/share_new_multisig_config_view.dart';
+import 'package:stackwallet/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart';
 import 'package:stackwallet/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart';
 import 'package:stackwallet/pages/add_wallet_views/new_wallet_options/new_wallet_options_view.dart';
 import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart';
@@ -113,6 +120,19 @@ import 'package:stackwallet/pages/settings_views/global_settings_view/syncing_pr
 import 'package:stackwallet/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_preferences_view.dart';
 import 'package:stackwallet/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart';
 import 'package:stackwallet/pages/settings_views/global_settings_view/tor_settings/tor_settings_view.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/frost_ms_options_view.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/frost_participants_view.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/finish_resharing_view.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/begin_reshare_config_view.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/complete_reshare_config_view.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/display_reshare_config_view.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1b/import_reshare_config_view.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_2/begin_resharing_view.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_2/continue_resharing_view.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_continue_sharing_view.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_import_resharer_config_view.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_start_resharing_view.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/verify_updated_wallet_view.dart';
 import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_backup_views/wallet_backup_view.dart';
 import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart';
 import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_view.dart';
@@ -423,6 +443,319 @@ class RouteGenerator {
         }
         return _routeError("${settings.name} invalid args: ${args.toString()}");
 
+      case CreateNewFrostMsWalletView.routeName:
+        if (args is ({
+          String walletName,
+          Coin coin,
+        })) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => CreateNewFrostMsWalletView(
+              walletName: args.walletName,
+              coin: args.coin,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+      case RestoreFrostMsWalletView.routeName:
+        if (args is ({
+          String walletName,
+          Coin coin,
+        })) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => RestoreFrostMsWalletView(
+              walletName: args.walletName,
+              coin: args.coin,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+      case ShareNewMultisigConfigView.routeName:
+        if (args is ({
+          String walletName,
+          Coin coin,
+        })) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => ShareNewMultisigConfigView(
+              walletName: args.walletName,
+              coin: args.coin,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+      case ImportNewFrostMsWalletView.routeName:
+        if (args is ({
+          String walletName,
+          Coin coin,
+        })) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => ImportNewFrostMsWalletView(
+              walletName: args.walletName,
+              coin: args.coin,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+      case NewImportResharerConfigView.routeName:
+        if (args is ({
+          String walletName,
+          Coin coin,
+        })) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => NewImportResharerConfigView(
+              walletName: args.walletName,
+              coin: args.coin,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+      case NewStartResharingView.routeName:
+        if (args is String) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => NewStartResharingView(
+              walletId: args,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+      case NewContinueSharingView.routeName:
+        if (args is String) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => NewContinueSharingView(
+              walletId: args,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+      case FrostShareCommitmentsView.routeName:
+        if (args is ({
+          String walletName,
+          Coin coin,
+        })) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => FrostShareCommitmentsView(
+              walletName: args.walletName,
+              coin: args.coin,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+      case FrostShareSharesView.routeName:
+        if (args is ({
+          String walletName,
+          Coin coin,
+        })) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => FrostShareSharesView(
+              walletName: args.walletName,
+              coin: args.coin,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+      case ConfirmNewFrostMSWalletCreationView.routeName:
+        if (args is ({
+          String walletName,
+          Coin coin,
+        })) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => ConfirmNewFrostMSWalletCreationView(
+              walletName: args.walletName,
+              coin: args.coin,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+      case FrostMSWalletOptionsView.routeName:
+        if (args is String) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => FrostMSWalletOptionsView(
+              walletId: args,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+      case FrostParticipantsView.routeName:
+        if (args is String) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => FrostParticipantsView(
+              walletId: args,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+      case ImportReshareConfigView.routeName:
+        if (args is String) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => ImportReshareConfigView(
+              walletId: args,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+      case BeginReshareConfigView.routeName:
+        if (args is String) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => BeginReshareConfigView(
+              walletId: args,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+      case CompleteReshareConfigView.routeName:
+        if (args is ({String walletId, List<int> resharers})) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => CompleteReshareConfigView(
+              walletId: args.walletId,
+              resharers: args.resharers,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+      case DisplayReshareConfigView.routeName:
+        if (args is String) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => DisplayReshareConfigView(
+              walletId: args,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+      case BeginResharingView.routeName:
+        if (args is String) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => BeginResharingView(
+              walletId: args,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+      case ContinueResharingView.routeName:
+        if (args is String) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => ContinueResharingView(
+              walletId: args,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+      case FinishResharingView.routeName:
+        if (args is String) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => FinishResharingView(
+              walletId: args,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+      case VerifyUpdatedWalletView.routeName:
+        if (args is String) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => VerifyUpdatedWalletView(
+              walletId: args,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
       // case MonkeyLoadedView.routeName:
       //   if (args is Tuple2<String, ChangeNotifierProvider<Manager>>) {
       //     return getRoute(
diff --git a/lib/themes/coin_card_provider.dart b/lib/themes/coin_card_provider.dart
index b34e9e6f1..ce5e71038 100644
--- a/lib/themes/coin_card_provider.dart
+++ b/lib/themes/coin_card_provider.dart
@@ -16,6 +16,13 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart';
 final coinCardProvider = Provider.family<String?, Coin>((ref, coin) {
   final assets = ref.watch(themeAssetsProvider);
 
+  // TODO: handle this differently by adding proper frost assets to themes
+  if (coin == Coin.bitcoinFrost) {
+    coin = Coin.bitcoin;
+  } else if (coin == Coin.bitcoinFrostTestNet) {
+    coin = Coin.bitcoinTestNet;
+  }
+
   if (assets is ThemeAssetsV3) {
     return assets.coinCardImages?[coin.mainNetVersion];
   } else {
@@ -26,6 +33,13 @@ final coinCardProvider = Provider.family<String?, Coin>((ref, coin) {
 final coinCardFavoritesProvider = Provider.family<String?, Coin>((ref, coin) {
   final assets = ref.watch(themeAssetsProvider);
 
+  // TODO: handle this differently by adding proper frost assets to themes
+  if (coin == Coin.bitcoinFrost) {
+    coin = Coin.bitcoin;
+  } else if (coin == Coin.bitcoinFrostTestNet) {
+    coin = Coin.bitcoinTestNet;
+  }
+
   if (assets is ThemeAssetsV3) {
     return assets.coinCardFavoritesImages?[coin.mainNetVersion] ??
         assets.coinCardImages?[coin.mainNetVersion];
diff --git a/lib/themes/coin_icon_provider.dart b/lib/themes/coin_icon_provider.dart
index 9bd3990bb..f0c0df842 100644
--- a/lib/themes/coin_icon_provider.dart
+++ b/lib/themes/coin_icon_provider.dart
@@ -16,6 +16,13 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart';
 final coinIconProvider = Provider.family<String, Coin>((ref, coin) {
   final assets = ref.watch(themeAssetsProvider);
 
+  // TODO: handle this differently by adding proper frost assets to themes
+  if (coin == Coin.bitcoinFrost) {
+    coin = Coin.bitcoin;
+  } else if (coin == Coin.bitcoinFrostTestNet) {
+    coin = Coin.bitcoinTestNet;
+  }
+
   if (assets is ThemeAssets) {
     switch (coin) {
       case Coin.bitcoin:
diff --git a/lib/themes/coin_image_provider.dart b/lib/themes/coin_image_provider.dart
index 6ca839fb9..fa1fdde4c 100644
--- a/lib/themes/coin_image_provider.dart
+++ b/lib/themes/coin_image_provider.dart
@@ -16,6 +16,13 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart';
 final coinImageProvider = Provider.family<String, Coin>((ref, coin) {
   final assets = ref.watch(themeAssetsProvider);
 
+  // TODO: handle this differently by adding proper frost assets to themes
+  if (coin == Coin.bitcoinFrost) {
+    coin = Coin.bitcoin;
+  } else if (coin == Coin.bitcoinFrostTestNet) {
+    coin = Coin.bitcoinTestNet;
+  }
+
   if (assets is ThemeAssets) {
     switch (coin) {
       case Coin.bitcoin:
@@ -64,6 +71,13 @@ final coinImageProvider = Provider.family<String, Coin>((ref, coin) {
 final coinImageSecondaryProvider = Provider.family<String, Coin>((ref, coin) {
   final assets = ref.watch(themeAssetsProvider);
 
+  // TODO: handle this differently by adding proper frost assets to themes
+  if (coin == Coin.bitcoinFrost) {
+    coin = Coin.bitcoin;
+  } else if (coin == Coin.bitcoinFrostTestNet) {
+    coin = Coin.bitcoinTestNet;
+  }
+
   if (assets is ThemeAssets) {
     switch (coin) {
       case Coin.bitcoin:
diff --git a/lib/utilities/enums/coin_enum.dart b/lib/utilities/enums/coin_enum.dart
index 305183448..0356c1e7c 100644
--- a/lib/utilities/enums/coin_enum.dart
+++ b/lib/utilities/enums/coin_enum.dart
@@ -297,6 +297,17 @@ extension CoinExt on Coin {
     }
   }
 
+  bool get isFrost {
+    switch (this) {
+      case Coin.bitcoinFrost:
+      case Coin.bitcoinFrostTestNet:
+        return true;
+
+      default:
+        return false;
+    }
+  }
+
   Coin get mainNetVersion {
     switch (this) {
       case Coin.bitcoin:
@@ -495,6 +506,15 @@ Coin coinFromPrettyName(String name) {
     case "tStellar":
       return Coin.stellarTestnet;
 
+    case "Bitcoin Frost":
+    case "bitcoinFrost":
+      return Coin.bitcoinFrost;
+
+    case "Bitcoin Frost Testnet":
+    case "tBitcoin Frost":
+    case "bitcoinFrostTestNet":
+      return Coin.bitcoinFrostTestNet;
+
     default:
       throw ArgumentError.value(
         name,
diff --git a/lib/wallets/models/incomplete_frost_wallet.dart b/lib/wallets/models/incomplete_frost_wallet.dart
new file mode 100644
index 000000000..e5075da63
--- /dev/null
+++ b/lib/wallets/models/incomplete_frost_wallet.dart
@@ -0,0 +1,42 @@
+import 'package:stackwallet/db/isar/main_db.dart';
+import 'package:stackwallet/services/node_service.dart';
+import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
+import 'package:stackwallet/utilities/prefs.dart';
+import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart';
+import 'package:stackwallet/wallets/isar/models/wallet_info.dart';
+import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
+import 'package:stackwallet/wallets/wallet/wallet.dart';
+
+class IncompleteFrostWallet {
+  WalletInfo? info;
+
+  String? get walletId => info?.walletId;
+
+  Future<BitcoinFrostWallet> toBitcoinFrostWallet({
+    required MainDB mainDB,
+    required SecureStorageInterface secureStorageInterface,
+    required NodeService nodeService,
+    required Prefs prefs,
+  }) async {
+    final wallet = await Wallet.create(
+      walletInfo: info!,
+      mainDB: mainDB,
+      secureStorageInterface: secureStorageInterface,
+      nodeService: nodeService,
+      prefs: prefs,
+    );
+
+    // dummy entry so updaters work when `wallet.updateWithResharedData` is called
+    final frostInfo = FrostWalletInfo(
+      walletId: info!.walletId,
+      knownSalts: [],
+      participants: [],
+      myName: "",
+      threshold: -1,
+    );
+
+    await mainDB.isar.frostWalletInfo.put(frostInfo);
+
+    return wallet as BitcoinFrostWallet;
+  }
+}
diff --git a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
index 102beb1e3..4f1c3febf 100644
--- a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
+++ b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
@@ -171,7 +171,7 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
         }
       }
 
-      final serializedKeys = await _getSerializedKeys();
+      final serializedKeys = await getSerializedKeys();
       final keys = frost.deserializeKeys(keys: serializedKeys!);
 
       final int network = cryptoCurrency.network == CryptoCurrencyNetwork.main
@@ -213,7 +213,7 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
     final int network = cryptoCurrency.network == CryptoCurrencyNetwork.main
         ? Network.Mainnet
         : Network.Testnet;
-    final serializedKeys = await _getSerializedKeys();
+    final serializedKeys = await getSerializedKeys();
 
     return Frost.attemptSignConfig(
       network: network,
@@ -859,7 +859,7 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
 
   // =================== Secure storage ========================================
 
-  Future<String?> _getSerializedKeys() async =>
+  Future<String?> getSerializedKeys() async =>
       await secureStorageInterface.read(
         key: "{$walletId}_serializedFROSTKeys",
       );
@@ -867,7 +867,7 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
   Future<void> _saveSerializedKeys(
     String keys,
   ) async {
-    final current = await _getSerializedKeys();
+    final current = await getSerializedKeys();
 
     if (current == null) {
       // do nothing
diff --git a/lib/widgets/detail_item.dart b/lib/widgets/detail_item.dart
new file mode 100644
index 000000000..75e0e6a1e
--- /dev/null
+++ b/lib/widgets/detail_item.dart
@@ -0,0 +1,90 @@
+import 'package:flutter/material.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/rounded_white_container.dart';
+
+class DetailItem extends StatelessWidget {
+  const DetailItem({
+    Key? key,
+    required this.title,
+    required this.detail,
+    this.button,
+    this.showEmptyDetail = true,
+    this.disableSelectableText = false,
+  }) : super(key: key);
+
+  final String title;
+  final String detail;
+  final Widget? button;
+  final bool showEmptyDetail;
+  final bool disableSelectableText;
+
+  @override
+  Widget build(BuildContext context) {
+    return ConditionalParent(
+      condition: !Util.isDesktop,
+      builder: (child) => RoundedWhiteContainer(
+        child: child,
+      ),
+      child: ConditionalParent(
+        condition: Util.isDesktop,
+        builder: (child) => Padding(
+          padding: const EdgeInsets.all(16),
+          child: child,
+        ),
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            Row(
+              mainAxisAlignment: MainAxisAlignment.spaceBetween,
+              children: [
+                disableSelectableText
+                    ? Text(
+                        title,
+                        style: STextStyles.itemSubtitle(context),
+                      )
+                    : SelectableText(
+                        title,
+                        style: STextStyles.itemSubtitle(context),
+                      ),
+                button ?? Container(),
+              ],
+            ),
+            const SizedBox(
+              height: 5,
+            ),
+            detail.isEmpty && showEmptyDetail
+                ? disableSelectableText
+                    ? Text(
+                        "$title will appear here",
+                        style: STextStyles.w500_14(context).copyWith(
+                          color: Theme.of(context)
+                              .extension<StackColors>()!
+                              .textSubtitle3,
+                        ),
+                      )
+                    : SelectableText(
+                        "$title will appear here",
+                        style: STextStyles.w500_14(context).copyWith(
+                          color: Theme.of(context)
+                              .extension<StackColors>()!
+                              .textSubtitle3,
+                        ),
+                      )
+                : disableSelectableText
+                    ? Text(
+                        detail,
+                        style: STextStyles.w500_14(context),
+                      )
+                    : SelectableText(
+                        detail,
+                        style: STextStyles.w500_14(context),
+                      ),
+          ],
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/widgets/dialogs/frost_interruption_dialog.dart b/lib/widgets/dialogs/frost_interruption_dialog.dart
new file mode 100644
index 000000000..4d36456bb
--- /dev/null
+++ b/lib/widgets/dialogs/frost_interruption_dialog.dart
@@ -0,0 +1,70 @@
+import 'package:flutter/material.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/desktop/secondary_button.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+
+enum FrostInterruptionDialogType {
+  walletCreation,
+  resharing,
+  transactionCreation;
+}
+
+class FrostInterruptionDialog extends StatelessWidget {
+  const FrostInterruptionDialog({
+    super.key,
+    required this.type,
+    required this.popUntilOnYesRouteName,
+    this.onNoPressedOverride,
+    this.onYesPressedOverride,
+  });
+
+  final FrostInterruptionDialogType type;
+  final String popUntilOnYesRouteName;
+  final VoidCallback? onNoPressedOverride;
+  final VoidCallback? onYesPressedOverride;
+
+  String get message {
+    switch (type) {
+      case FrostInterruptionDialogType.walletCreation:
+        return "wallet creation";
+      case FrostInterruptionDialogType.resharing:
+        return "resharing";
+      case FrostInterruptionDialogType.transactionCreation:
+        return "transaction signing";
+    }
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return StackDialog(
+      title: "Cancel $message process",
+      message: "Are you sure you want to cancel the $message process?",
+      leftButton: SecondaryButton(
+        label: "No",
+        onPressed: onNoPressedOverride ??
+            Navigator.of(
+              context,
+              rootNavigator: Util.isDesktop,
+            ).pop,
+      ),
+      rightButton: PrimaryButton(
+        label: "Yes",
+        onPressed: onYesPressedOverride ??
+            () {
+              // pop dialog
+              Navigator.of(
+                context,
+                rootNavigator: Util.isDesktop,
+              ).pop();
+
+              Navigator.of(context).popUntil(
+                ModalRoute.withName(
+                  popUntilOnYesRouteName,
+                ),
+              );
+            },
+      ),
+    );
+  }
+}
diff --git a/lib/widgets/stack_dialog.dart b/lib/widgets/stack_dialog.dart
index be7f22ed9..bc247c2f2 100644
--- a/lib/widgets/stack_dialog.dart
+++ b/lib/widgets/stack_dialog.dart
@@ -147,8 +147,10 @@ class StackOkDialog extends StatelessWidget {
     this.icon,
     required this.title,
     this.message,
+    this.desktopPopRootNavigator = false,
   }) : super(key: key);
 
+  final bool desktopPopRootNavigator;
   final Widget? leftButton;
   final void Function(String)? onOkPressed;
 
@@ -208,9 +210,13 @@ class StackOkDialog extends StatelessWidget {
                           onOkPressed?.call("OK");
                         }
                       : () {
-                          int count = 0;
-                          Navigator.of(context).popUntil((_) => count++ >= 2);
-                          // onOkPressed?.call("OK");
+                          if (desktopPopRootNavigator) {
+                            Navigator.of(context, rootNavigator: true).pop();
+                          } else {
+                            int count = 0;
+                            Navigator.of(context).popUntil((_) => count++ >= 2);
+                            // onOkPressed?.call("OK");
+                          }
                         },
                   style: Theme.of(context)
                       .extension<StackColors>()!

From 9deb8a5d0c4688f434c640a5ea337e836652b79d Mon Sep 17 00:00:00 2001
From: Diego Salazar <diego@cypherstack.com>
Date: Fri, 19 Jan 2024 20:16:01 -0700
Subject: [PATCH 07/57] Update version (v1.9.1, build 200)

---
 pubspec.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pubspec.yaml b/pubspec.yaml
index 9a243905b..1355dbd4e 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.9.0+199
+version: 1.9.1+200
 
 environment:
   sdk: ">=3.0.2 <4.0.0"

From 444afb88ae90b504921d2eada0eceeb397f3813a Mon Sep 17 00:00:00 2001
From: julian <julian@cypherstack.com>
Date: Tue, 23 Jan 2024 18:33:40 -0600
Subject: [PATCH 08/57] WIP frost send

---
 .../frost_attempt_sign_config_view.dart       | 405 ++++++++++++
 .../frost_ms/frost_complete_sign_view.dart    | 206 ++++++
 .../frost_continue_sign_config_view.dart      | 445 +++++++++++++
 .../frost_create_sign_config_view.dart        | 180 ++++++
 .../frost_import_sign_config_view.dart        | 330 ++++++++++
 .../send_view/frost_ms/frost_send_view.dart   | 602 ++++++++++++++++++
 lib/pages/send_view/frost_ms/recipient.dart   | 501 +++++++++++++++
 lib/pages/wallet_view/wallet_view.dart        |  13 +-
 .../wallet_view/sub_widgets/my_wallet.dart    |  49 +-
 lib/route_generator.dart                      |  18 +
 .../wallet/impl/bitcoin_frost_wallet.dart     |   6 +
 lib/wallets/wallet/wallet.dart                |   3 +
 12 files changed, 2746 insertions(+), 12 deletions(-)
 create mode 100644 lib/pages/send_view/frost_ms/frost_attempt_sign_config_view.dart
 create mode 100644 lib/pages/send_view/frost_ms/frost_complete_sign_view.dart
 create mode 100644 lib/pages/send_view/frost_ms/frost_continue_sign_config_view.dart
 create mode 100644 lib/pages/send_view/frost_ms/frost_create_sign_config_view.dart
 create mode 100644 lib/pages/send_view/frost_ms/frost_import_sign_config_view.dart
 create mode 100644 lib/pages/send_view/frost_ms/frost_send_view.dart
 create mode 100644 lib/pages/send_view/frost_ms/recipient.dart

diff --git a/lib/pages/send_view/frost_ms/frost_attempt_sign_config_view.dart b/lib/pages/send_view/frost_ms/frost_attempt_sign_config_view.dart
new file mode 100644
index 000000000..64b33e9f9
--- /dev/null
+++ b/lib/pages/send_view/frost_ms/frost_attempt_sign_config_view.dart
@@ -0,0 +1,405 @@
+import 'package:barcode_scan2/barcode_scan2.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:qr_flutter/qr_flutter.dart';
+import 'package:stackwallet/pages/send_view/frost_ms/frost_continue_sign_config_view.dart';
+import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/providers/global/wallets_provider.dart';
+import 'package:stackwallet/services/coins/bitcoin/frost_wallet.dart';
+import 'package:stackwallet/services/frost.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/detail_item.dart';
+import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+import 'package:stackwallet/widgets/stack_text_field.dart';
+import 'package:stackwallet/widgets/textfield_icon_button.dart';
+
+class FrostAttemptSignConfigView extends ConsumerStatefulWidget {
+  const FrostAttemptSignConfigView({
+    super.key,
+    required this.walletId,
+  });
+
+  static const String routeName = "/frostAttemptSignConfigView";
+
+  final String walletId;
+
+  @override
+  ConsumerState<FrostAttemptSignConfigView> createState() =>
+      _FrostAttemptSignConfigViewState();
+}
+
+class _FrostAttemptSignConfigViewState
+    extends ConsumerState<FrostAttemptSignConfigView> {
+  final List<TextEditingController> controllers = [];
+  final List<FocusNode> focusNodes = [];
+
+  late final String myName;
+  late final List<String> participantsWithoutMe;
+  late final String myPreprocess;
+  late final int myIndex;
+  late final int threshold;
+
+  final List<bool> fieldIsEmptyFlags = [];
+
+  bool hasEnoughPreprocesses() {
+    // own preprocess is not included in controllers and must be set here
+    int count = 1;
+
+    for (final controller in controllers) {
+      if (controller.text.isNotEmpty) {
+        count++;
+      }
+    }
+
+    return count >= threshold;
+  }
+
+  @override
+  void initState() {
+    final wallet = ref
+        .read(walletsChangeNotifierProvider)
+        .getManager(widget.walletId)
+        .wallet as FrostWallet;
+
+    myName = wallet.myName;
+    threshold = wallet.threshold;
+    participantsWithoutMe = wallet.participants;
+    myIndex = participantsWithoutMe.indexOf(wallet.myName);
+    myPreprocess = ref.read(pFrostAttemptSignData.state).state!.preprocess;
+
+    participantsWithoutMe.removeAt(myIndex);
+
+    for (int i = 0; i < participantsWithoutMe.length; i++) {
+      controllers.add(TextEditingController());
+      focusNodes.add(FocusNode());
+      fieldIsEmptyFlags.add(true);
+    }
+    super.initState();
+  }
+
+  @override
+  void dispose() {
+    for (int i = 0; i < controllers.length; i++) {
+      controllers[i].dispose();
+    }
+    for (int i = 0; i < focusNodes.length; i++) {
+      focusNodes[i].dispose();
+    }
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return ConditionalParent(
+      condition: Util.isDesktop,
+      builder: (child) => DesktopScaffold(
+        background: Theme.of(context).extension<StackColors>()!.background,
+        appBar: const DesktopAppBar(
+          isCompactHeight: false,
+          leading: AppBarBackButton(),
+        ),
+        body: SizedBox(
+          width: 480,
+          child: child,
+        ),
+      ),
+      child: ConditionalParent(
+        condition: !Util.isDesktop,
+        builder: (child) => Background(
+          child: Scaffold(
+            backgroundColor:
+                Theme.of(context).extension<StackColors>()!.background,
+            appBar: AppBar(
+              leading: AppBarBackButton(
+                onPressed: () {
+                  Navigator.of(context).pop();
+                },
+              ),
+              title: Text(
+                "Preprocesses",
+                style: STextStyles.navBarTitle(context),
+              ),
+            ),
+            body: SafeArea(
+              child: LayoutBuilder(
+                builder: (context, constraints) {
+                  return SingleChildScrollView(
+                    child: ConstrainedBox(
+                      constraints: BoxConstraints(
+                        minHeight: constraints.maxHeight,
+                      ),
+                      child: IntrinsicHeight(
+                        child: Padding(
+                          padding: const EdgeInsets.all(16),
+                          child: child,
+                        ),
+                      ),
+                    ),
+                  );
+                },
+              ),
+            ),
+          ),
+        ),
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            SizedBox(
+              height: 220,
+              child: Row(
+                mainAxisAlignment: MainAxisAlignment.center,
+                children: [
+                  QrImageView(
+                    data: myPreprocess,
+                    size: 220,
+                    backgroundColor:
+                        Theme.of(context).extension<StackColors>()!.background,
+                    foregroundColor: Theme.of(context)
+                        .extension<StackColors>()!
+                        .accentColorDark,
+                  ),
+                ],
+              ),
+            ),
+            const _Div(),
+            DetailItem(
+              title: "My name",
+              detail: myName,
+            ),
+            const _Div(),
+            DetailItem(
+              title: "My preprocess",
+              detail: myPreprocess,
+              button: Util.isDesktop
+                  ? IconCopyButton(
+                      data: myPreprocess,
+                    )
+                  : SimpleCopyButton(
+                      data: myPreprocess,
+                    ),
+            ),
+            const _Div(),
+            Column(
+              mainAxisSize: MainAxisSize.min,
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [
+                for (int i = 0; i < participantsWithoutMe.length; i++)
+                  Column(
+                    mainAxisSize: MainAxisSize.min,
+                    crossAxisAlignment: CrossAxisAlignment.start,
+                    children: [
+                      Padding(
+                        padding: const EdgeInsets.symmetric(vertical: 8),
+                        child: ClipRRect(
+                          borderRadius: BorderRadius.circular(
+                            Constants.size.circularBorderRadius,
+                          ),
+                          child: TextField(
+                            key: Key("frostPreprocessesTextFieldKey_$i"),
+                            controller: controllers[i],
+                            focusNode: focusNodes[i],
+                            readOnly: false,
+                            autocorrect: false,
+                            enableSuggestions: false,
+                            style: STextStyles.field(context),
+                            onChanged: (_) {
+                              setState(() {
+                                fieldIsEmptyFlags[i] =
+                                    controllers[i].text.isEmpty;
+                              });
+                            },
+                            decoration: standardInputDecoration(
+                              "Enter ${participantsWithoutMe[i]}'s preprocess",
+                              focusNodes[i],
+                              context,
+                            ).copyWith(
+                              contentPadding: const EdgeInsets.only(
+                                left: 16,
+                                top: 6,
+                                bottom: 8,
+                                right: 5,
+                              ),
+                              suffixIcon: Padding(
+                                padding: fieldIsEmptyFlags[i]
+                                    ? const EdgeInsets.only(right: 8)
+                                    : const EdgeInsets.only(right: 0),
+                                child: UnconstrainedBox(
+                                  child: Row(
+                                    mainAxisAlignment:
+                                        MainAxisAlignment.spaceAround,
+                                    children: [
+                                      !fieldIsEmptyFlags[i]
+                                          ? TextFieldIconButton(
+                                              semanticsLabel:
+                                                  "Clear Button. Clears The Preprocess Field Input.",
+                                              key: Key(
+                                                "frostPreprocessesClearButtonKey_$i",
+                                              ),
+                                              onTap: () {
+                                                controllers[i].text = "";
+
+                                                setState(() {
+                                                  fieldIsEmptyFlags[i] = true;
+                                                });
+                                              },
+                                              child: const XIcon(),
+                                            )
+                                          : TextFieldIconButton(
+                                              semanticsLabel:
+                                                  "Paste Button. Pastes From Clipboard To Preprocess Field Input.",
+                                              key: Key(
+                                                "frostPreprocessesPasteButtonKey_$i",
+                                              ),
+                                              onTap: () async {
+                                                final ClipboardData? data =
+                                                    await Clipboard.getData(
+                                                        Clipboard.kTextPlain);
+                                                if (data?.text != null &&
+                                                    data!.text!.isNotEmpty) {
+                                                  controllers[i].text =
+                                                      data.text!.trim();
+                                                }
+
+                                                setState(() {
+                                                  fieldIsEmptyFlags[i] =
+                                                      controllers[i]
+                                                          .text
+                                                          .isEmpty;
+                                                });
+                                              },
+                                              child: fieldIsEmptyFlags[i]
+                                                  ? const ClipboardIcon()
+                                                  : const XIcon(),
+                                            ),
+                                      if (fieldIsEmptyFlags[i])
+                                        TextFieldIconButton(
+                                          semanticsLabel:
+                                              "Scan QR Button. Opens Camera For Scanning QR Code.",
+                                          key: Key(
+                                            "frostPreprocessesScanQrButtonKey_$i",
+                                          ),
+                                          onTap: () async {
+                                            try {
+                                              if (FocusScope.of(context)
+                                                  .hasFocus) {
+                                                FocusScope.of(context)
+                                                    .unfocus();
+                                                await Future<void>.delayed(
+                                                    const Duration(
+                                                        milliseconds: 75));
+                                              }
+
+                                              final qrResult =
+                                                  await BarcodeScanner.scan();
+
+                                              controllers[i].text =
+                                                  qrResult.rawContent;
+
+                                              setState(() {
+                                                fieldIsEmptyFlags[i] =
+                                                    controllers[i].text.isEmpty;
+                                              });
+                                            } on PlatformException catch (e, s) {
+                                              Logging.instance.log(
+                                                "Failed to get camera permissions while trying to scan qr code: $e\n$s",
+                                                level: LogLevel.Warning,
+                                              );
+                                            }
+                                          },
+                                          child: const QrCodeIcon(),
+                                        )
+                                    ],
+                                  ),
+                                ),
+                              ),
+                            ),
+                          ),
+                        ),
+                      ),
+                    ],
+                  ),
+              ],
+            ),
+            if (!Util.isDesktop) const Spacer(),
+            const _Div(),
+            PrimaryButton(
+              label: "Continue signing",
+              enabled: hasEnoughPreprocesses(),
+              onPressed: () async {
+                // collect Preprocess strings (not including my own)
+                final preprocesses = controllers.map((e) => e.text).toList();
+
+                // collect participants who are involved in this transaction
+                final List<String> requiredParticipantsUnordered = [];
+                for (int i = 0; i < participantsWithoutMe.length; i++) {
+                  if (preprocesses[i].isNotEmpty) {
+                    requiredParticipantsUnordered.add(participantsWithoutMe[i]);
+                  }
+                }
+                ref.read(pFrostSelectParticipantsUnordered.notifier).state =
+                    requiredParticipantsUnordered;
+
+                // insert an empty string at my index
+                preprocesses.insert(myIndex, "");
+
+                try {
+                  ref.read(pFrostContinueSignData.notifier).state =
+                      Frost.continueSigning(
+                    machinePtr:
+                        ref.read(pFrostAttemptSignData.state).state!.machinePtr,
+                    preprocesses: preprocesses,
+                  );
+
+                  await Navigator.of(context).pushNamed(
+                    FrostContinueSignView.routeName,
+                    arguments: widget.walletId,
+                  );
+                } catch (e, s) {
+                  Logging.instance.log(
+                    "$e\n$s",
+                    level: LogLevel.Fatal,
+                  );
+
+                  return await showDialog<void>(
+                    context: context,
+                    builder: (_) => StackOkDialog(
+                      title: "Failed to continue signing",
+                      desktopPopRootNavigator: Util.isDesktop,
+                    ),
+                  );
+                }
+              },
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}
+
+class _Div extends StatelessWidget {
+  const _Div({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return const SizedBox(
+      height: 12,
+    );
+  }
+}
diff --git a/lib/pages/send_view/frost_ms/frost_complete_sign_view.dart b/lib/pages/send_view/frost_ms/frost_complete_sign_view.dart
new file mode 100644
index 000000000..c63dca04d
--- /dev/null
+++ b/lib/pages/send_view/frost_ms/frost_complete_sign_view.dart
@@ -0,0 +1,206 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:qr_flutter/qr_flutter.dart';
+import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
+import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/my_stack_view.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/providers/global/wallets_provider.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/show_loading.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/detail_item.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+
+class FrostCompleteSignView extends ConsumerStatefulWidget {
+  const FrostCompleteSignView({
+    super.key,
+    required this.walletId,
+  });
+
+  static const String routeName = "/frostCompleteSignView";
+
+  final String walletId;
+
+  @override
+  ConsumerState<FrostCompleteSignView> createState() =>
+      _FrostCompleteSignViewState();
+}
+
+class _FrostCompleteSignViewState extends ConsumerState<FrostCompleteSignView> {
+  bool _broadcastLock = false;
+
+  @override
+  Widget build(BuildContext context) {
+    return ConditionalParent(
+      condition: Util.isDesktop,
+      builder: (child) => DesktopScaffold(
+        background: Theme.of(context).extension<StackColors>()!.background,
+        appBar: const DesktopAppBar(
+          isCompactHeight: false,
+          leading: AppBarBackButton(),
+        ),
+        body: SizedBox(
+          width: 480,
+          child: child,
+        ),
+      ),
+      child: ConditionalParent(
+        condition: !Util.isDesktop,
+        builder: (child) => Background(
+          child: Scaffold(
+            backgroundColor:
+                Theme.of(context).extension<StackColors>()!.background,
+            appBar: AppBar(
+              leading: AppBarBackButton(
+                onPressed: () {
+                  Navigator.of(context).pop();
+                },
+              ),
+              title: Text(
+                "Preview transaction",
+                style: STextStyles.navBarTitle(context),
+              ),
+            ),
+            body: SafeArea(
+              child: LayoutBuilder(
+                builder: (context, constraints) {
+                  return SingleChildScrollView(
+                    child: ConstrainedBox(
+                      constraints: BoxConstraints(
+                        minHeight: constraints.maxHeight,
+                      ),
+                      child: IntrinsicHeight(
+                        child: Padding(
+                          padding: const EdgeInsets.all(16),
+                          child: child,
+                        ),
+                      ),
+                    ),
+                  );
+                },
+              ),
+            ),
+          ),
+        ),
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            SizedBox(
+              height: 220,
+              child: Row(
+                mainAxisAlignment: MainAxisAlignment.center,
+                children: [
+                  QrImageView(
+                    data: ref.watch(pFrostTxData.state).state!.raw!,
+                    size: 220,
+                    backgroundColor:
+                        Theme.of(context).extension<StackColors>()!.background,
+                    foregroundColor: Theme.of(context)
+                        .extension<StackColors>()!
+                        .accentColorDark,
+                  ),
+                ],
+              ),
+            ),
+            const _Div(),
+            DetailItem(
+              title: "Raw transaction hex",
+              detail: ref.watch(pFrostTxData.state).state!.raw!,
+              button: Util.isDesktop
+                  ? IconCopyButton(
+                      data: ref.watch(pFrostTxData.state).state!.raw!,
+                    )
+                  : SimpleCopyButton(
+                      data: ref.watch(pFrostTxData.state).state!.raw!,
+                    ),
+            ),
+            const _Div(),
+            if (!Util.isDesktop) const Spacer(),
+            const _Div(),
+            PrimaryButton(
+              label: "Broadcast Transaction",
+              onPressed: () async {
+                if (_broadcastLock) {
+                  return;
+                }
+                _broadcastLock = true;
+
+                try {
+                  Exception? ex;
+                  final txData = await showLoading(
+                    whileFuture: ref
+                        .read(walletsChangeNotifierProvider)
+                        .getManager(widget.walletId)
+                        .confirmSend(
+                          txData: ref.read(pFrostTxData.state).state!,
+                        ),
+                    context: context,
+                    message: "Broadcasting transaction to network",
+                    isDesktop: Util.isDesktop,
+                    onException: (e) {
+                      ex = e;
+                    },
+                  );
+
+                  if (ex != null) {
+                    throw ex!;
+                  }
+
+                  if (mounted) {
+                    if (txData != null) {
+                      ref.read(pFrostTxData.state).state = txData;
+                      Navigator.of(context).popUntil(
+                        ModalRoute.withName(
+                          Util.isDesktop
+                              ? MyStackView.routeName
+                              : WalletView.routeName,
+                        ),
+                      );
+                    }
+                  }
+                } catch (e, s) {
+                  Logging.instance.log(
+                    "$e\n$s",
+                    level: LogLevel.Fatal,
+                  );
+
+                  return await showDialog<void>(
+                    context: context,
+                    builder: (_) => StackOkDialog(
+                      title: "Broadcast error",
+                      message: e.toString(),
+                      desktopPopRootNavigator: Util.isDesktop,
+                    ),
+                  );
+                } finally {
+                  _broadcastLock = false;
+                }
+              },
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}
+
+class _Div extends StatelessWidget {
+  const _Div({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return const SizedBox(
+      height: 12,
+    );
+  }
+}
diff --git a/lib/pages/send_view/frost_ms/frost_continue_sign_config_view.dart b/lib/pages/send_view/frost_ms/frost_continue_sign_config_view.dart
new file mode 100644
index 000000000..9d6494c62
--- /dev/null
+++ b/lib/pages/send_view/frost_ms/frost_continue_sign_config_view.dart
@@ -0,0 +1,445 @@
+import 'package:barcode_scan2/barcode_scan2.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:qr_flutter/qr_flutter.dart';
+import 'package:stackwallet/pages/send_view/frost_ms/frost_complete_sign_view.dart';
+import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
+import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/providers/global/wallets_provider.dart';
+import 'package:stackwallet/services/coins/bitcoin/frost_wallet.dart';
+import 'package:stackwallet/services/frost.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/detail_item.dart';
+import 'package:stackwallet/widgets/dialogs/frost_interruption_dialog.dart';
+import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+import 'package:stackwallet/widgets/stack_text_field.dart';
+import 'package:stackwallet/widgets/textfield_icon_button.dart';
+
+class FrostContinueSignView extends ConsumerStatefulWidget {
+  const FrostContinueSignView({
+    super.key,
+    required this.walletId,
+  });
+
+  static const String routeName = "/frostContinueSignView";
+
+  final String walletId;
+
+  @override
+  ConsumerState<FrostContinueSignView> createState() =>
+      _FrostContinueSignViewState();
+}
+
+class _FrostContinueSignViewState extends ConsumerState<FrostContinueSignView> {
+  final List<TextEditingController> controllers = [];
+  final List<FocusNode> focusNodes = [];
+
+  late final String myName;
+  late final List<String> participantsWithoutMe;
+  late final List<String> participantsAll;
+  late final String myShare;
+  late final int myIndex;
+
+  final List<bool> fieldIsEmptyFlags = [];
+
+  @override
+  void initState() {
+    final wallet = ref
+        .read(walletsChangeNotifierProvider)
+        .getManager(widget.walletId)
+        .wallet as FrostWallet;
+
+    myName = wallet.myName;
+    participantsAll = wallet.participants;
+    myIndex = wallet.participants.indexOf(wallet.myName);
+    myShare = ref.read(pFrostContinueSignData.state).state!.share;
+
+    participantsWithoutMe = wallet.participants
+        .toSet()
+        .intersection(
+            ref.read(pFrostSelectParticipantsUnordered.state).state!.toSet())
+        .toList();
+
+    participantsWithoutMe.remove(myName);
+
+    for (int i = 0; i < participantsWithoutMe.length; i++) {
+      controllers.add(TextEditingController());
+      focusNodes.add(FocusNode());
+      fieldIsEmptyFlags.add(true);
+    }
+    super.initState();
+  }
+
+  @override
+  void dispose() {
+    for (int i = 0; i < controllers.length; i++) {
+      controllers[i].dispose();
+    }
+    for (int i = 0; i < focusNodes.length; i++) {
+      focusNodes[i].dispose();
+    }
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return WillPopScope(
+      onWillPop: () async {
+        await showDialog<void>(
+          context: context,
+          builder: (_) => FrostInterruptionDialog(
+            type: FrostInterruptionDialogType.transactionCreation,
+            popUntilOnYesRouteName: Util.isDesktop
+                ? DesktopWalletView.routeName
+                : WalletView.routeName,
+          ),
+        );
+        return false;
+      },
+      child: ConditionalParent(
+        condition: Util.isDesktop,
+        builder: (child) => DesktopScaffold(
+          background: Theme.of(context).extension<StackColors>()!.background,
+          appBar: DesktopAppBar(
+            isCompactHeight: false,
+            leading: AppBarBackButton(
+              onPressed: () async {
+                await showDialog<void>(
+                  context: context,
+                  builder: (_) => const FrostInterruptionDialog(
+                    type: FrostInterruptionDialogType.transactionCreation,
+                    popUntilOnYesRouteName: DesktopWalletView.routeName,
+                  ),
+                );
+              },
+            ),
+          ),
+          body: SizedBox(
+            width: 480,
+            child: child,
+          ),
+        ),
+        child: ConditionalParent(
+          condition: !Util.isDesktop,
+          builder: (child) => Background(
+            child: Scaffold(
+              backgroundColor:
+                  Theme.of(context).extension<StackColors>()!.background,
+              appBar: AppBar(
+                leading: AppBarBackButton(
+                  onPressed: () async {
+                    await showDialog<void>(
+                      context: context,
+                      builder: (_) => const FrostInterruptionDialog(
+                        type: FrostInterruptionDialogType.transactionCreation,
+                        popUntilOnYesRouteName: WalletView.routeName,
+                      ),
+                    );
+                  },
+                ),
+                title: Text(
+                  "Shares",
+                  style: STextStyles.navBarTitle(context),
+                ),
+              ),
+              body: SafeArea(
+                child: LayoutBuilder(
+                  builder: (context, constraints) {
+                    return SingleChildScrollView(
+                      child: ConstrainedBox(
+                        constraints: BoxConstraints(
+                          minHeight: constraints.maxHeight,
+                        ),
+                        child: IntrinsicHeight(
+                          child: Padding(
+                            padding: const EdgeInsets.all(16),
+                            child: child,
+                          ),
+                        ),
+                      ),
+                    );
+                  },
+                ),
+              ),
+            ),
+          ),
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              SizedBox(
+                height: 220,
+                child: Row(
+                  mainAxisAlignment: MainAxisAlignment.center,
+                  children: [
+                    QrImageView(
+                      data: myShare,
+                      size: 220,
+                      backgroundColor: Theme.of(context)
+                          .extension<StackColors>()!
+                          .background,
+                      foregroundColor: Theme.of(context)
+                          .extension<StackColors>()!
+                          .accentColorDark,
+                    ),
+                  ],
+                ),
+              ),
+              const _Div(),
+              DetailItem(
+                title: "My name",
+                detail: myName,
+              ),
+              const _Div(),
+              DetailItem(
+                title: "My shares",
+                detail: myShare,
+                button: Util.isDesktop
+                    ? IconCopyButton(
+                        data: myShare,
+                      )
+                    : SimpleCopyButton(
+                        data: myShare,
+                      ),
+              ),
+              const _Div(),
+              Column(
+                mainAxisSize: MainAxisSize.min,
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  for (int i = 0; i < participantsWithoutMe.length; i++)
+                    Column(
+                      mainAxisSize: MainAxisSize.min,
+                      crossAxisAlignment: CrossAxisAlignment.start,
+                      children: [
+                        Padding(
+                          padding: const EdgeInsets.symmetric(vertical: 8),
+                          child: ClipRRect(
+                            borderRadius: BorderRadius.circular(
+                              Constants.size.circularBorderRadius,
+                            ),
+                            child: TextField(
+                              key: Key("frostSharesTextFieldKey_$i"),
+                              controller: controllers[i],
+                              focusNode: focusNodes[i],
+                              readOnly: false,
+                              autocorrect: false,
+                              enableSuggestions: false,
+                              style: STextStyles.field(context),
+                              decoration: standardInputDecoration(
+                                "Enter ${participantsWithoutMe[i]}'s share",
+                                focusNodes[i],
+                                context,
+                              ).copyWith(
+                                contentPadding: const EdgeInsets.only(
+                                  left: 16,
+                                  top: 6,
+                                  bottom: 8,
+                                  right: 5,
+                                ),
+                                suffixIcon: Padding(
+                                  padding: fieldIsEmptyFlags[i]
+                                      ? const EdgeInsets.only(right: 8)
+                                      : const EdgeInsets.only(right: 0),
+                                  child: UnconstrainedBox(
+                                    child: Row(
+                                      mainAxisAlignment:
+                                          MainAxisAlignment.spaceAround,
+                                      children: [
+                                        !fieldIsEmptyFlags[i]
+                                            ? TextFieldIconButton(
+                                                semanticsLabel:
+                                                    "Clear Button. Clears "
+                                                    "The Share Field Input.",
+                                                key: Key(
+                                                  "frostSharesClearButtonKey_$i",
+                                                ),
+                                                onTap: () {
+                                                  controllers[i].text = "";
+
+                                                  setState(() {
+                                                    fieldIsEmptyFlags[i] = true;
+                                                  });
+                                                },
+                                                child: const XIcon(),
+                                              )
+                                            : TextFieldIconButton(
+                                                semanticsLabel:
+                                                    "Paste Button. Pastes From "
+                                                    "Clipboard To Share Field Input.",
+                                                key: Key(
+                                                    "frostSharesPasteButtonKey_$i"),
+                                                onTap: () async {
+                                                  final ClipboardData? data =
+                                                      await Clipboard.getData(
+                                                          Clipboard.kTextPlain);
+                                                  if (data?.text != null &&
+                                                      data!.text!.isNotEmpty) {
+                                                    controllers[i].text =
+                                                        data.text!.trim();
+                                                  }
+
+                                                  setState(() {
+                                                    fieldIsEmptyFlags[i] =
+                                                        controllers[i]
+                                                            .text
+                                                            .isEmpty;
+                                                  });
+                                                },
+                                                child: fieldIsEmptyFlags[i]
+                                                    ? const ClipboardIcon()
+                                                    : const XIcon(),
+                                              ),
+                                        if (fieldIsEmptyFlags[i])
+                                          TextFieldIconButton(
+                                            semanticsLabel:
+                                                "Scan QR Button. Opens Camera "
+                                                "For Scanning QR Code.",
+                                            key: Key(
+                                              "frostSharesScanQrButtonKey_$i",
+                                            ),
+                                            onTap: () async {
+                                              try {
+                                                if (FocusScope.of(context)
+                                                    .hasFocus) {
+                                                  FocusScope.of(context)
+                                                      .unfocus();
+                                                  await Future<void>.delayed(
+                                                      const Duration(
+                                                          milliseconds: 75));
+                                                }
+
+                                                final qrResult =
+                                                    await BarcodeScanner.scan();
+
+                                                controllers[i].text =
+                                                    qrResult.rawContent;
+
+                                                setState(() {
+                                                  fieldIsEmptyFlags[i] =
+                                                      controllers[i]
+                                                          .text
+                                                          .isEmpty;
+                                                });
+                                              } on PlatformException catch (e, s) {
+                                                Logging.instance.log(
+                                                  "Failed to get camera permissions "
+                                                  "while trying to scan qr code: $e\n$s",
+                                                  level: LogLevel.Warning,
+                                                );
+                                              }
+                                            },
+                                            child: const QrCodeIcon(),
+                                          )
+                                      ],
+                                    ),
+                                  ),
+                                ),
+                              ),
+                            ),
+                          ),
+                        ),
+                      ],
+                    ),
+                ],
+              ),
+              if (!Util.isDesktop) const Spacer(),
+              const _Div(),
+              PrimaryButton(
+                label: "Complete signing",
+                onPressed: () async {
+                  // check for empty shares
+                  if (controllers
+                      .map((e) => e.text.isEmpty)
+                      .reduce((value, element) => value |= element)) {
+                    return await showDialog<void>(
+                      context: context,
+                      builder: (_) => StackOkDialog(
+                        title: "Missing Shares",
+                        desktopPopRootNavigator: Util.isDesktop,
+                      ),
+                    );
+                  }
+
+                  // collect Share strings
+                  final sharesCollected =
+                      controllers.map((e) => e.text).toList();
+
+                  final List<String> shares = [];
+                  for (final participant in participantsAll) {
+                    if (participantsWithoutMe.contains(participant)) {
+                      shares.add(sharesCollected[
+                          participantsWithoutMe.indexOf(participant)]);
+                    } else {
+                      shares.add("");
+                    }
+                  }
+
+                  try {
+                    final rawTx = Frost.completeSigning(
+                      machinePtr: ref
+                          .read(pFrostContinueSignData.state)
+                          .state!
+                          .machinePtr,
+                      shares: shares,
+                    );
+
+                    ref.read(pFrostTxData.state).state =
+                        ref.read(pFrostTxData.state).state!.copyWith(
+                              raw: rawTx,
+                            );
+
+                    await Navigator.of(context).pushNamed(
+                      FrostCompleteSignView.routeName,
+                      arguments: widget.walletId,
+                    );
+                  } catch (e, s) {
+                    Logging.instance.log(
+                      "$e\n$s",
+                      level: LogLevel.Fatal,
+                    );
+
+                    return await showDialog<void>(
+                      context: context,
+                      builder: (_) => StackOkDialog(
+                        title: "Failed to complete signing process",
+                        desktopPopRootNavigator: Util.isDesktop,
+                      ),
+                    );
+                  }
+                },
+              ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+}
+
+class _Div extends StatelessWidget {
+  const _Div({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return const SizedBox(
+      height: 12,
+    );
+  }
+}
diff --git a/lib/pages/send_view/frost_ms/frost_create_sign_config_view.dart b/lib/pages/send_view/frost_ms/frost_create_sign_config_view.dart
new file mode 100644
index 000000000..104160a76
--- /dev/null
+++ b/lib/pages/send_view/frost_ms/frost_create_sign_config_view.dart
@@ -0,0 +1,180 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:qr_flutter/qr_flutter.dart';
+import 'package:stackwallet/pages/send_view/frost_ms/frost_attempt_sign_config_view.dart';
+import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/providers/global/wallets_provider.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/detail_item.dart';
+
+class FrostCreateSignConfigView extends ConsumerStatefulWidget {
+  const FrostCreateSignConfigView({
+    super.key,
+    required this.walletId,
+  });
+
+  static const String routeName = "/frostCreateSignConfigView";
+
+  final String walletId;
+
+  @override
+  ConsumerState<FrostCreateSignConfigView> createState() =>
+      _FrostCreateSignConfigViewState();
+}
+
+class _FrostCreateSignConfigViewState
+    extends ConsumerState<FrostCreateSignConfigView> {
+  bool _attemptSignLock = false;
+
+  Future<void> _attemptSign() async {
+    if (_attemptSignLock) {
+      return;
+    }
+
+    _attemptSignLock = true;
+
+    try {
+      final wallet =
+          ref.read(pWallets).getWallet(widget.walletId) as BitcoinFrostWallet;
+
+      final attemptSignRes = await wallet.frostAttemptSignConfig(
+        config: ref.read(pFrostTxData.state).state!.frostMSConfig!,
+      );
+
+      ref.read(pFrostAttemptSignData.notifier).state = attemptSignRes;
+
+      await Navigator.of(context).pushNamed(
+        FrostAttemptSignConfigView.routeName,
+        arguments: widget.walletId,
+      );
+    } catch (e, s) {
+      Logging.instance.log(
+        "$e\n$s",
+        level: LogLevel.Error,
+      );
+    } finally {
+      _attemptSignLock = false;
+    }
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return ConditionalParent(
+      condition: Util.isDesktop,
+      builder: (child) => DesktopScaffold(
+        background: Theme.of(context).extension<StackColors>()!.background,
+        appBar: const DesktopAppBar(
+          isCompactHeight: false,
+          leading: AppBarBackButton(),
+        ),
+        body: SizedBox(
+          width: 480,
+          child: child,
+        ),
+      ),
+      child: ConditionalParent(
+        condition: !Util.isDesktop,
+        builder: (child) => Background(
+          child: Scaffold(
+            backgroundColor:
+                Theme.of(context).extension<StackColors>()!.background,
+            appBar: AppBar(
+              leading: AppBarBackButton(
+                onPressed: () {
+                  Navigator.of(context).pop();
+                },
+              ),
+              title: Text(
+                "Sign config",
+                style: STextStyles.navBarTitle(context),
+              ),
+            ),
+            body: SafeArea(
+              child: LayoutBuilder(
+                builder: (context, constraints) {
+                  return SingleChildScrollView(
+                    child: ConstrainedBox(
+                      constraints: BoxConstraints(
+                        minHeight: constraints.maxHeight,
+                      ),
+                      child: IntrinsicHeight(
+                        child: Padding(
+                          padding: const EdgeInsets.symmetric(horizontal: 16),
+                          child: child,
+                        ),
+                      ),
+                    ),
+                  );
+                },
+              ),
+            ),
+          ),
+        ),
+        child: Column(
+          children: [
+            if (!Util.isDesktop) const Spacer(),
+            SizedBox(
+              height: MediaQuery.of(context).size.width - 32,
+              child: Row(
+                mainAxisAlignment: MainAxisAlignment.center,
+                children: [
+                  QrImageView(
+                    data: ref.watch(pFrostTxData.state).state!.frostMSConfig!,
+                    size: MediaQuery.of(context).size.width - 32,
+                    backgroundColor:
+                        Theme.of(context).extension<StackColors>()!.background,
+                    foregroundColor: Theme.of(context)
+                        .extension<StackColors>()!
+                        .accentColorDark,
+                  ),
+                ],
+              ),
+            ),
+            const SizedBox(
+              height: 32,
+            ),
+            DetailItem(
+              title: "Encoded config",
+              detail: ref.watch(pFrostTxData.state).state!.frostMSConfig!,
+              button: Util.isDesktop
+                  ? IconCopyButton(
+                      data: ref.watch(pFrostTxData.state).state!.frostMSConfig!,
+                    )
+                  : SimpleCopyButton(
+                      data: ref.watch(pFrostTxData.state).state!.frostMSConfig!,
+                    ),
+            ),
+            SizedBox(
+              height: Util.isDesktop ? 64 : 16,
+            ),
+            if (!Util.isDesktop)
+              const Spacer(
+                flex: 2,
+              ),
+            PrimaryButton(
+              label: "Attempt sign",
+              onPressed: () {
+                _attemptSign();
+              },
+            ),
+            const SizedBox(
+              height: 16,
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/pages/send_view/frost_ms/frost_import_sign_config_view.dart b/lib/pages/send_view/frost_ms/frost_import_sign_config_view.dart
new file mode 100644
index 000000000..b390e0b67
--- /dev/null
+++ b/lib/pages/send_view/frost_ms/frost_import_sign_config_view.dart
@@ -0,0 +1,330 @@
+import 'package:barcode_scan2/barcode_scan2.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:isar/isar.dart';
+import 'package:stackwallet/models/isar/models/isar_models.dart';
+import 'package:stackwallet/pages/send_view/frost_ms/frost_attempt_sign_config_view.dart';
+import 'package:stackwallet/providers/db/main_db_provider.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/providers/global/wallets_provider.dart';
+import 'package:stackwallet/services/frost.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/format.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/wallets/models/tx_data.dart';
+import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+import 'package:stackwallet/widgets/stack_text_field.dart';
+import 'package:stackwallet/widgets/textfield_icon_button.dart';
+
+class FrostImportSignConfigView extends ConsumerStatefulWidget {
+  const FrostImportSignConfigView({
+    super.key,
+    required this.walletId,
+  });
+
+  static const String routeName = "/frostImportSignConfigView";
+
+  final String walletId;
+
+  @override
+  ConsumerState<FrostImportSignConfigView> createState() =>
+      _FrostImportSignConfigViewState();
+}
+
+class _FrostImportSignConfigViewState
+    extends ConsumerState<FrostImportSignConfigView> {
+  late final TextEditingController configFieldController;
+  late final FocusNode configFocusNode;
+
+  bool _configEmpty = true;
+
+  bool _attemptSignLock = false;
+
+  Future<void> _attemptSign() async {
+    if (_attemptSignLock) {
+      return;
+    }
+
+    _attemptSignLock = true;
+
+    try {
+      if (FocusScope.of(context).hasFocus) {
+        FocusScope.of(context).unfocus();
+      }
+
+      final config = configFieldController.text;
+      final wallet =
+          ref.read(pWallets).getWallet(widget.walletId) as BitcoinFrostWallet;
+
+      final data = Frost.extractDataFromSignConfig(
+        signConfig: config,
+        coin: wallet.cryptoCurrency,
+      );
+
+      final utxos = await ref
+          .read(mainDBProvider)
+          .getUTXOs(wallet.walletId)
+          .filter()
+          .anyOf(
+              data.inputs,
+              (q, e) => q
+                  .txidEqualTo(Format.uint8listToString(e.hash))
+                  .and()
+                  .valueEqualTo(e.value)
+                  .and()
+                  .voutEqualTo(e.vout))
+          .findAll();
+
+      // TODO add more data from 'data' and display to user ?
+      ref.read(pFrostTxData.notifier).state = TxData(
+        frostMSConfig: config,
+        recipients: data.recipients,
+        utxos: utxos.toSet(),
+      );
+
+      final attemptSignRes = await wallet.frostAttemptSignConfig(
+        config: ref.read(pFrostTxData.state).state!.frostMSConfig!,
+      );
+
+      ref.read(pFrostAttemptSignData.notifier).state = attemptSignRes;
+
+      await Navigator.of(context).pushNamed(
+        FrostAttemptSignConfigView.routeName,
+        arguments: widget.walletId,
+      );
+    } catch (e, s) {
+      Logging.instance.log(
+        "$e\n$s",
+        level: LogLevel.Error,
+      );
+      await showDialog<void>(
+        context: context,
+        builder: (_) => StackOkDialog(
+          title: "Import and attempt sign config failed",
+          message: e.toString(),
+          desktopPopRootNavigator: Util.isDesktop,
+        ),
+      );
+    } finally {
+      _attemptSignLock = false;
+    }
+  }
+
+  @override
+  void initState() {
+    configFieldController = TextEditingController();
+    configFocusNode = FocusNode();
+    super.initState();
+  }
+
+  @override
+  void dispose() {
+    configFieldController.dispose();
+    configFocusNode.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return ConditionalParent(
+      condition: Util.isDesktop,
+      builder: (child) => DesktopScaffold(
+        background: Theme.of(context).extension<StackColors>()!.background,
+        appBar: const DesktopAppBar(
+          isCompactHeight: false,
+          leading: AppBarBackButton(),
+        ),
+        body: SizedBox(
+          width: 480,
+          child: child,
+        ),
+      ),
+      child: ConditionalParent(
+        condition: !Util.isDesktop,
+        builder: (child) => Background(
+          child: Scaffold(
+            backgroundColor:
+                Theme.of(context).extension<StackColors>()!.background,
+            appBar: AppBar(
+              leading: AppBarBackButton(
+                onPressed: () {
+                  Navigator.of(context).pop();
+                },
+              ),
+              title: Text(
+                "Import FROST sign config",
+                style: STextStyles.navBarTitle(context),
+              ),
+            ),
+            body: SafeArea(
+              child: LayoutBuilder(
+                builder: (context, constraints) {
+                  return SingleChildScrollView(
+                    child: ConstrainedBox(
+                      constraints: BoxConstraints(
+                        minHeight: constraints.maxHeight,
+                      ),
+                      child: IntrinsicHeight(
+                        child: Padding(
+                          padding: const EdgeInsets.all(16),
+                          child: child,
+                        ),
+                      ),
+                    ),
+                  );
+                },
+              ),
+            ),
+          ),
+        ),
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            const SizedBox(
+              height: 16,
+            ),
+            ClipRRect(
+              borderRadius: BorderRadius.circular(
+                Constants.size.circularBorderRadius,
+              ),
+              child: TextField(
+                key: const Key("frConfigTextFieldKey"),
+                controller: configFieldController,
+                onChanged: (_) {
+                  setState(() {
+                    _configEmpty = configFieldController.text.isEmpty;
+                  });
+                },
+                focusNode: configFocusNode,
+                readOnly: false,
+                autocorrect: false,
+                enableSuggestions: false,
+                style: STextStyles.field(context),
+                decoration: standardInputDecoration(
+                  "Enter config",
+                  configFocusNode,
+                  context,
+                ).copyWith(
+                  contentPadding: const EdgeInsets.only(
+                    left: 16,
+                    top: 6,
+                    bottom: 8,
+                    right: 5,
+                  ),
+                  suffixIcon: Padding(
+                    padding: _configEmpty
+                        ? const EdgeInsets.only(right: 8)
+                        : const EdgeInsets.only(right: 0),
+                    child: UnconstrainedBox(
+                      child: Row(
+                        mainAxisAlignment: MainAxisAlignment.spaceAround,
+                        children: [
+                          !_configEmpty
+                              ? TextFieldIconButton(
+                                  semanticsLabel:
+                                      "Clear Button. Clears The Config Field.",
+                                  key: const Key("frConfigClearButtonKey"),
+                                  onTap: () {
+                                    configFieldController.text = "";
+
+                                    setState(() {
+                                      _configEmpty = true;
+                                    });
+                                  },
+                                  child: const XIcon(),
+                                )
+                              : TextFieldIconButton(
+                                  semanticsLabel:
+                                      "Paste Button. Pastes From Clipboard To Config Field Input.",
+                                  key: const Key("frConfigPasteButtonKey"),
+                                  onTap: () async {
+                                    final ClipboardData? data =
+                                        await Clipboard.getData(
+                                            Clipboard.kTextPlain);
+                                    if (data?.text != null &&
+                                        data!.text!.isNotEmpty) {
+                                      configFieldController.text =
+                                          data.text!.trim();
+                                    }
+
+                                    setState(() {
+                                      _configEmpty =
+                                          configFieldController.text.isEmpty;
+                                    });
+                                  },
+                                  child: _configEmpty
+                                      ? const ClipboardIcon()
+                                      : const XIcon(),
+                                ),
+                          if (_configEmpty)
+                            TextFieldIconButton(
+                              semanticsLabel:
+                                  "Scan QR Button. Opens Camera For Scanning QR Code.",
+                              key: const Key("frConfigScanQrButtonKey"),
+                              onTap: () async {
+                                try {
+                                  if (FocusScope.of(context).hasFocus) {
+                                    FocusScope.of(context).unfocus();
+                                    await Future<void>.delayed(
+                                        const Duration(milliseconds: 75));
+                                  }
+
+                                  final qrResult = await BarcodeScanner.scan();
+
+                                  configFieldController.text =
+                                      qrResult.rawContent;
+
+                                  setState(() {
+                                    _configEmpty =
+                                        configFieldController.text.isEmpty;
+                                  });
+                                } on PlatformException catch (e, s) {
+                                  Logging.instance.log(
+                                    "Failed to get camera permissions while trying to scan qr code: $e\n$s",
+                                    level: LogLevel.Warning,
+                                  );
+                                }
+                              },
+                              child: const QrCodeIcon(),
+                            )
+                        ],
+                      ),
+                    ),
+                  ),
+                ),
+              ),
+            ),
+            const SizedBox(
+              height: 16,
+            ),
+            if (!Util.isDesktop) const Spacer(),
+            const SizedBox(
+              height: 16,
+            ),
+            PrimaryButton(
+              label: "Start signing",
+              enabled: !_configEmpty,
+              onPressed: () {
+                _attemptSign();
+              },
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/pages/send_view/frost_ms/frost_send_view.dart b/lib/pages/send_view/frost_ms/frost_send_view.dart
new file mode 100644
index 000000000..cf64d8e54
--- /dev/null
+++ b/lib/pages/send_view/frost_ms/frost_send_view.dart
@@ -0,0 +1,602 @@
+/*
+ * This file is part of Stack Wallet.
+ *
+ * Copyright (c) 2023 Cypher Stack
+ * All Rights Reserved.
+ * The code is distributed under GPLv3 license, see LICENSE file for details.
+ * Generated by Cypher Stack on 2023-05-26
+ *
+ */
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:stackwallet/models/isar/models/isar_models.dart';
+import 'package:stackwallet/pages/coin_control/coin_control_view.dart';
+import 'package:stackwallet/pages/send_view/frost_ms/frost_create_sign_config_view.dart';
+import 'package:stackwallet/pages/send_view/frost_ms/frost_import_sign_config_view.dart';
+import 'package:stackwallet/pages/send_view/frost_ms/recipient.dart';
+import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
+import 'package:stackwallet/providers/providers.dart';
+import 'package:stackwallet/themes/coin_icon_provider.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/amount/amount.dart';
+import 'package:stackwallet/utilities/amount/amount_formatter.dart';
+import 'package:stackwallet/utilities/assets.dart';
+import 'package:stackwallet/utilities/constants.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
+import 'package:stackwallet/utilities/show_loading.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart';
+import 'package:stackwallet/wallets/models/tx_data.dart';
+import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
+import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.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/fee_slider.dart';
+import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
+import 'package:stackwallet/widgets/rounded_white_container.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+import 'package:stackwallet/widgets/stack_text_field.dart';
+import 'package:stackwallet/widgets/textfield_icon_button.dart';
+import 'package:tuple/tuple.dart';
+
+class FrostSendView extends ConsumerStatefulWidget {
+  const FrostSendView({
+    Key? key,
+    required this.walletId,
+    required this.coin,
+  }) : super(key: key);
+
+  static const String routeName = "/frostSendView";
+
+  final String walletId;
+  final Coin coin;
+
+  @override
+  ConsumerState<FrostSendView> createState() => _FrostSendViewState();
+}
+
+class _FrostSendViewState extends ConsumerState<FrostSendView> {
+  final List<int> recipientWidgetIndexes = [0];
+  int _greatestWidgetIndex = 0;
+
+  late final String walletId;
+  late final Coin coin;
+
+  late TextEditingController noteController;
+  late TextEditingController onChainNoteController;
+
+  final _noteFocusNode = FocusNode();
+
+  Set<UTXO> selectedUTXOs = {};
+
+  bool _createSignLock = false;
+
+  Future<TxData> _loadingFuture() async {
+    final wallet = ref.read(pWallets).getWallet(walletId) as BitcoinFrostWallet;
+
+    final recipients = recipientWidgetIndexes
+        .map((i) => ref.read(pRecipient(i).state).state)
+        .map((e) => (address: e!.address, amount: e.amount!, isChange: false))
+        .toList(growable: false);
+
+    final txData = await wallet.frostCreateSignConfig(
+      txData: TxData(recipients: recipients),
+      changeAddress: (await wallet.getCurrentReceivingAddress())!.value,
+      feePerWeight: customFeeRate,
+    );
+
+    return txData;
+  }
+
+  Future<void> _createSignConfig() async {
+    if (_createSignLock) {
+      return;
+    }
+    _createSignLock = true;
+
+    try {
+      // wait for keyboard to disappear
+      FocusScope.of(context).unfocus();
+      await Future<void>.delayed(
+        const Duration(milliseconds: 100),
+      );
+
+      TxData? txData;
+      if (mounted) {
+        txData = await showLoading<TxData>(
+          whileFuture: _loadingFuture(),
+          context: context,
+          message: "Generating sign config",
+          isDesktop: Util.isDesktop,
+          onException: (e) {
+            throw e;
+          },
+        );
+      }
+
+      if (mounted && txData != null) {
+        ref.read(pFrostTxData.notifier).state = txData;
+
+        await Navigator.of(context).pushNamed(
+          FrostCreateSignConfigView.routeName,
+          arguments: widget.walletId,
+        );
+      }
+    } catch (e) {
+      if (mounted) {
+        unawaited(
+          showDialog<dynamic>(
+            context: context,
+            useSafeArea: false,
+            barrierDismissible: true,
+            builder: (context) {
+              return StackDialog(
+                title: "Create sign config failed",
+                message: e.toString(),
+                rightButton: TextButton(
+                  style: Theme.of(context)
+                      .extension<StackColors>()!
+                      .getSecondaryEnabledButtonStyle(context),
+                  child: Text(
+                    "Ok",
+                    style: STextStyles.button(context).copyWith(
+                        color: Theme.of(context)
+                            .extension<StackColors>()!
+                            .accentColorDark),
+                  ),
+                  onPressed: () {
+                    Navigator.of(context).pop();
+                  },
+                ),
+              );
+            },
+          ),
+        );
+      }
+    } finally {
+      _createSignLock = false;
+    }
+  }
+
+  int customFeeRate = 1;
+
+  void _validateRecipientFormStates() {
+    for (final i in recipientWidgetIndexes) {
+      final state = ref.read(pRecipient(i).state).state;
+      if (state?.amount == null || state?.address == null) {
+        ref.read(previewTxButtonStateProvider.notifier).state = false;
+        return;
+      }
+    }
+    ref.read(previewTxButtonStateProvider.notifier).state = true;
+    return;
+  }
+
+  @override
+  void initState() {
+    coin = widget.coin;
+    walletId = widget.walletId;
+
+    noteController = TextEditingController();
+
+    super.initState();
+  }
+
+  @override
+  void dispose() {
+    noteController.dispose();
+
+    _noteFocusNode.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    debugPrint("BUILD: $runtimeType");
+    final wallet = ref.watch(pWallets).getWallet(walletId);
+
+    final showCoinControl = wallet is CoinControlInterface &&
+        ref.watch(
+          prefsChangeNotifierProvider.select(
+            (value) => value.enableCoinControl,
+          ),
+        );
+
+    return ConditionalParent(
+      condition: !Util.isDesktop,
+      builder: (child) => Background(
+        child: Scaffold(
+          backgroundColor:
+              Theme.of(context).extension<StackColors>()!.background,
+          appBar: AppBar(
+            leading: AppBarBackButton(
+              onPressed: () async {
+                if (FocusScope.of(context).hasFocus) {
+                  FocusScope.of(context).unfocus();
+                  await Future<void>.delayed(const Duration(milliseconds: 50));
+                }
+                if (mounted) {
+                  Navigator.of(context).pop();
+                }
+              },
+            ),
+            title: Text(
+              "Send ${coin.ticker}",
+              style: STextStyles.navBarTitle(context),
+            ),
+            actions: [
+              Padding(
+                padding: const EdgeInsets.only(
+                  top: 10,
+                  bottom: 10,
+                  right: 10,
+                ),
+                child: AspectRatio(
+                  aspectRatio: 1,
+                  child: AppBarIconButton(
+                    semanticsLabel: "Import sign config Button.",
+                    key: const Key("importSignConfigButtonKey"),
+                    size: 36,
+                    shadows: const [],
+                    color:
+                        Theme.of(context).extension<StackColors>()!.background,
+                    icon: SvgPicture.asset(
+                      Assets.svg.circlePlus,
+                      color: Theme.of(context)
+                          .extension<StackColors>()!
+                          .accentColorDark,
+                      width: 20,
+                      height: 20,
+                    ),
+                    onPressed: () {
+                      Navigator.of(context).pushNamed(
+                        FrostImportSignConfigView.routeName,
+                        arguments: walletId,
+                      );
+                    },
+                  ),
+                ),
+              ),
+            ],
+          ),
+          body: LayoutBuilder(
+            builder: (builderContext, constraints) {
+              return SingleChildScrollView(
+                child: ConstrainedBox(
+                  constraints: BoxConstraints(
+                    // subtract top and bottom padding set in parent
+                    minHeight: constraints.maxHeight,
+                  ),
+                  child: IntrinsicHeight(
+                    child: Padding(
+                      padding: const EdgeInsets.symmetric(horizontal: 16),
+                      child: child,
+                    ),
+                  ),
+                ),
+              );
+            },
+          ),
+        ),
+      ),
+      child: Column(
+        crossAxisAlignment: CrossAxisAlignment.stretch,
+        children: [
+          if (!Util.isDesktop)
+            Container(
+              decoration: BoxDecoration(
+                color: Theme.of(context).extension<StackColors>()!.popupBG,
+                borderRadius: BorderRadius.circular(
+                  Constants.size.circularBorderRadius,
+                ),
+              ),
+              child: Padding(
+                padding: const EdgeInsets.all(12.0),
+                child: Row(
+                  children: [
+                    SvgPicture.file(
+                      File(
+                        ref.watch(
+                          coinIconProvider(coin),
+                        ),
+                      ),
+                      width: 22,
+                      height: 22,
+                    ),
+                    const SizedBox(
+                      width: 6,
+                    ),
+                    Column(
+                      crossAxisAlignment: CrossAxisAlignment.start,
+                      children: [
+                        Text(
+                          ref.watch(pWalletName(walletId)),
+                          style: STextStyles.titleBold12(context)
+                              .copyWith(fontSize: 14),
+                          overflow: TextOverflow.ellipsis,
+                          maxLines: 1,
+                        ),
+                        // const SizedBox(
+                        //   height: 2,
+                        // ),
+                        Text(
+                          "Available balance",
+                          style:
+                              STextStyles.label(context).copyWith(fontSize: 10),
+                        ),
+                      ],
+                    ),
+                    Util.isDesktop
+                        ? const SizedBox(
+                            height: 24,
+                          )
+                        : const Spacer(),
+                    GestureDetector(
+                      onTap: () {
+                        // cryptoAmountController.text = ref
+                        //     .read(pAmountFormatter(coin))
+                        //     .format(
+                        //       _cachedBalance!,
+                        //       withUnitName: false,
+                        //     );
+                      },
+                      child: Container(
+                        color: Colors.transparent,
+                        child: Column(
+                          crossAxisAlignment: CrossAxisAlignment.end,
+                          children: [
+                            Text(
+                              ref.watch(pAmountFormatter(coin)).format(ref
+                                  .watch(pWalletBalance(walletId))
+                                  .spendable),
+                              style: STextStyles.titleBold12(context).copyWith(
+                                fontSize: 10,
+                              ),
+                              textAlign: TextAlign.right,
+                            ),
+                            // Text(
+                            //   "${(manager.balance.spendable.decimal * ref.watch(
+                            //             priceAnd24hChangeNotifierProvider.select(
+                            //               (value) => value.getPrice(coin).item1,
+                            //             ),
+                            //           )).toAmount(
+                            //         fractionDigits: 2,
+                            //       ).fiatString(
+                            //         locale: locale,
+                            //       )} ${ref.watch(
+                            //     prefsChangeNotifierProvider
+                            //         .select((value) => value.currency),
+                            //   )}",
+                            //   style: STextStyles.subtitle(context).copyWith(
+                            //     fontSize: 8,
+                            //   ),
+                            //   textAlign: TextAlign.right,
+                            // )
+                          ],
+                        ),
+                      ),
+                    )
+                  ],
+                ),
+              ),
+            ),
+          const SizedBox(
+            height: 16,
+          ),
+          Row(
+            mainAxisAlignment: MainAxisAlignment.spaceBetween,
+            children: [
+              Text(
+                "Recipients",
+                style: STextStyles.smallMed12(context),
+                textAlign: TextAlign.left,
+              ),
+              CustomTextButton(
+                text: "Add",
+                onTap: () {
+                  // used for tracking recipient forms
+                  _greatestWidgetIndex++;
+                  recipientWidgetIndexes.add(_greatestWidgetIndex);
+                  setState(() {});
+                },
+              ),
+            ],
+          ),
+          const SizedBox(
+            height: 8,
+          ),
+          Column(
+            children: [
+              for (int i = 0; i < recipientWidgetIndexes.length; i++)
+                ConditionalParent(
+                  condition: recipientWidgetIndexes.length > 1,
+                  builder: (child) => Padding(
+                    padding: const EdgeInsets.only(top: 8),
+                    child: child,
+                  ),
+                  child: Recipient(
+                    key: Key(
+                      "recipientKey_${recipientWidgetIndexes[i]}",
+                    ),
+                    index: recipientWidgetIndexes[i],
+                    coin: coin,
+                    onChanged: () {
+                      _validateRecipientFormStates();
+                    },
+                    remove: i == 0 && recipientWidgetIndexes.length == 1
+                        ? null
+                        : () {
+                            recipientWidgetIndexes.removeAt(i);
+                            setState(() {});
+                          },
+                  ),
+                ),
+            ],
+          ),
+          if (showCoinControl)
+            const SizedBox(
+              height: 8,
+            ),
+          if (showCoinControl)
+            RoundedWhiteContainer(
+              child: Row(
+                mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                children: [
+                  Text(
+                    "Coin control",
+                    style: STextStyles.w500_14(context).copyWith(
+                      color: Theme.of(context)
+                          .extension<StackColors>()!
+                          .textSubtitle1,
+                    ),
+                  ),
+                  CustomTextButton(
+                    text: selectedUTXOs.isEmpty
+                        ? "Select coins"
+                        : "Selected coins (${selectedUTXOs.length})",
+                    onTap: () async {
+                      if (FocusScope.of(context).hasFocus) {
+                        FocusScope.of(context).unfocus();
+                        await Future<void>.delayed(
+                          const Duration(milliseconds: 100),
+                        );
+                      }
+
+                      if (mounted) {
+                        // finally spendable = ref
+                        //     .read(walletsChangeNotifierProvider)
+                        //     .getManager(widget.walletId)
+                        //     .balance
+                        //     .spendable;
+
+                        // TODO: [prio=high] make sure this coincontrol works correctly
+
+                        Amount? amount;
+
+                        final result = await Navigator.of(context).pushNamed(
+                          CoinControlView.routeName,
+                          arguments: Tuple4(
+                            walletId,
+                            CoinControlViewType.use,
+                            amount,
+                            selectedUTXOs,
+                          ),
+                        );
+
+                        if (result is Set<UTXO>) {
+                          setState(() {
+                            selectedUTXOs = result;
+                          });
+                        }
+                      }
+                    },
+                  ),
+                ],
+              ),
+            ),
+          const SizedBox(
+            height: 12,
+          ),
+          Text(
+            "Note (optional)",
+            style: STextStyles.smallMed12(context),
+            textAlign: TextAlign.left,
+          ),
+          const SizedBox(
+            height: 8,
+          ),
+          ClipRRect(
+            borderRadius: BorderRadius.circular(
+              Constants.size.circularBorderRadius,
+            ),
+            child: TextField(
+              autocorrect: Util.isDesktop ? false : true,
+              enableSuggestions: Util.isDesktop ? false : true,
+              controller: noteController,
+              focusNode: _noteFocusNode,
+              style: STextStyles.field(context),
+              onChanged: (_) => setState(() {}),
+              decoration: standardInputDecoration(
+                "Type something...",
+                _noteFocusNode,
+                context,
+              ).copyWith(
+                suffixIcon: noteController.text.isNotEmpty
+                    ? Padding(
+                        padding: const EdgeInsets.only(right: 0),
+                        child: UnconstrainedBox(
+                          child: Row(
+                            children: [
+                              TextFieldIconButton(
+                                child: const XIcon(),
+                                onTap: () async {
+                                  setState(() {
+                                    noteController.text = "";
+                                  });
+                                },
+                              ),
+                            ],
+                          ),
+                        ),
+                      )
+                    : null,
+              ),
+            ),
+          ),
+          const SizedBox(
+            height: 12,
+          ),
+          Padding(
+            padding: const EdgeInsets.only(
+              bottom: 12,
+              top: 16,
+            ),
+            child: FeeSlider(
+              coin: coin,
+              onSatVByteChanged: (rate) {
+                customFeeRate = rate;
+              },
+            ),
+          ),
+          Util.isDesktop
+              ? const SizedBox(
+                  height: 12,
+                )
+              : const Spacer(),
+          const SizedBox(
+            height: 12,
+          ),
+          TextButton(
+            onPressed: ref.watch(previewTxButtonStateProvider.state).state
+                ? _createSignConfig
+                : null,
+            style: ref.watch(previewTxButtonStateProvider.state).state
+                ? Theme.of(context)
+                    .extension<StackColors>()!
+                    .getPrimaryEnabledButtonStyle(context)
+                : Theme.of(context)
+                    .extension<StackColors>()!
+                    .getPrimaryDisabledButtonStyle(context),
+            child: Text(
+              "Create config",
+              style: STextStyles.button(context),
+            ),
+          ),
+          const SizedBox(
+            height: 16,
+          ),
+        ],
+      ),
+    );
+  }
+}
+
+final previewTxButtonStateProvider = StateProvider((_) => false);
diff --git a/lib/pages/send_view/frost_ms/recipient.dart b/lib/pages/send_view/frost_ms/recipient.dart
new file mode 100644
index 000000000..e59d3e9ad
--- /dev/null
+++ b/lib/pages/send_view/frost_ms/recipient.dart
@@ -0,0 +1,501 @@
+import 'package:decimal/decimal.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:stackwallet/providers/global/locale_provider.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/address_utils.dart';
+import 'package:stackwallet/utilities/amount/amount.dart';
+import 'package:stackwallet/utilities/amount/amount_formatter.dart';
+import 'package:stackwallet/utilities/amount/amount_input_formatter.dart';
+import 'package:stackwallet/utilities/amount/amount_unit.dart';
+import 'package:stackwallet/utilities/barcode_scanner_interface.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/logger.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
+import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
+import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
+import 'package:stackwallet/widgets/rounded_white_container.dart';
+import 'package:stackwallet/widgets/stack_text_field.dart';
+import 'package:stackwallet/widgets/textfield_icon_button.dart';
+
+//TODO: move the following two providers elsewhere
+final pClipboard =
+    Provider<ClipboardInterface>((ref) => const ClipboardWrapper());
+final pBarcodeScanner =
+    Provider<BarcodeScannerInterface>((ref) => const BarcodeScannerWrapper());
+
+// final _pPrice = Provider.family<Decimal, Coin>((ref, coin) {
+//   return ref.watch(
+//     priceAnd24hChangeNotifierProvider
+//         .select((value) => value.getPrice(coin).item1),
+//   );
+// });
+
+final pRecipient =
+    StateProvider.family<({String address, Amount? amount})?, int>(
+        (ref, index) => null);
+
+class Recipient extends ConsumerStatefulWidget {
+  const Recipient({
+    super.key,
+    required this.index,
+    required this.coin,
+    this.remove,
+    this.onChanged,
+  });
+
+  final int index;
+  final Coin coin;
+
+  final VoidCallback? remove;
+  final VoidCallback? onChanged;
+
+  @override
+  ConsumerState<Recipient> createState() => _RecipientState();
+}
+
+class _RecipientState extends ConsumerState<Recipient> {
+  late final TextEditingController addressController, amountController;
+  late final FocusNode addressFocusNode, amountFocusNode;
+
+  bool _addressIsEmpty = true;
+  bool _cryptoAmountChangeLock = false;
+
+  void _updateRecipientData() {
+    final address = addressController.text;
+    final amount =
+        ref.read(pAmountFormatter(widget.coin)).tryParse(amountController.text);
+
+    ref.read(pRecipient(widget.index).notifier).state = (
+      address: address,
+      amount: amount,
+    );
+    widget.onChanged?.call();
+  }
+
+  void _cryptoAmountChanged() async {
+    if (!_cryptoAmountChangeLock) {
+      Amount? cryptoAmount = ref.read(pAmountFormatter(widget.coin)).tryParse(
+            amountController.text,
+          );
+      if (cryptoAmount != null) {
+        if (ref.read(pRecipient(widget.index))?.amount != null &&
+            ref.read(pRecipient(widget.index))?.amount == cryptoAmount) {
+          return;
+        }
+
+        // final price = ref.read(_pPrice(widget.coin));
+        //
+        // if (price > Decimal.zero) {
+        //   baseController.text = (cryptoAmount.decimal * price)
+        //       .toAmount(
+        //         fractionDigits: 2,
+        //       )
+        //       .fiatString(
+        //         locale: ref.read(localeServiceChangeNotifierProvider).locale,
+        //       );
+        // }
+      } else {
+        cryptoAmount = null;
+        // baseController.text = "";
+      }
+
+      _updateRecipientData();
+    }
+  }
+
+  @override
+  void initState() {
+    addressController = TextEditingController();
+    amountController = TextEditingController();
+    // baseController = TextEditingController();
+
+    addressFocusNode = FocusNode();
+    amountFocusNode = FocusNode();
+    // baseFocusNode = FocusNode();
+
+    amountController.addListener(_cryptoAmountChanged);
+
+    super.initState();
+  }
+
+  @override
+  void dispose() {
+    amountController.removeListener(_cryptoAmountChanged);
+
+    addressController.dispose();
+    amountController.dispose();
+    // baseController.dispose();
+
+    addressFocusNode.dispose();
+    amountFocusNode.dispose();
+    // baseFocusNode.dispose();
+
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    final String locale = ref.watch(
+      localeServiceChangeNotifierProvider.select(
+        (value) => value.locale,
+      ),
+    );
+
+    return RoundedWhiteContainer(
+      child: Column(
+        mainAxisSize: MainAxisSize.min,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          ClipRRect(
+            borderRadius: BorderRadius.circular(
+              Constants.size.circularBorderRadius,
+            ),
+            child: TextField(
+              key: const Key("sendViewAddressFieldKey"),
+              controller: addressController,
+              readOnly: false,
+              autocorrect: false,
+              enableSuggestions: false,
+              focusNode: addressFocusNode,
+              style: STextStyles.field(context),
+              onChanged: (_) {
+                setState(() {
+                  _addressIsEmpty = addressController.text.isEmpty;
+                });
+              },
+              decoration: standardInputDecoration(
+                "Enter ${widget.coin.ticker} address",
+                addressFocusNode,
+                context,
+              ).copyWith(
+                contentPadding: const EdgeInsets.only(
+                  left: 16,
+                  top: 6,
+                  bottom: 8,
+                  right: 5,
+                ),
+                suffixIcon: Padding(
+                  padding: _addressIsEmpty
+                      ? const EdgeInsets.only(right: 8)
+                      : const EdgeInsets.only(right: 0),
+                  child: UnconstrainedBox(
+                    child: Row(
+                      mainAxisAlignment: MainAxisAlignment.spaceAround,
+                      children: [
+                        !_addressIsEmpty
+                            ? TextFieldIconButton(
+                                semanticsLabel:
+                                    "Clear Button. Clears The Address Field Input.",
+                                key: const Key(
+                                    "sendViewClearAddressFieldButtonKey"),
+                                onTap: () {
+                                  addressController.text = "";
+
+                                  setState(() {
+                                    _addressIsEmpty = true;
+                                  });
+
+                                  _updateRecipientData();
+                                },
+                                child: const XIcon(),
+                              )
+                            : TextFieldIconButton(
+                                semanticsLabel:
+                                    "Paste Button. Pastes From Clipboard To Address Field Input.",
+                                key: const Key(
+                                    "sendViewPasteAddressFieldButtonKey"),
+                                onTap: () async {
+                                  final ClipboardData? data = await ref
+                                      .read(pClipboard)
+                                      .getData(Clipboard.kTextPlain);
+                                  if (data?.text != null &&
+                                      data!.text!.isNotEmpty) {
+                                    String content = data.text!.trim();
+                                    if (content.contains("\n")) {
+                                      content = content.substring(
+                                          0, content.indexOf("\n"));
+                                    }
+
+                                    addressController.text = content.trim();
+
+                                    setState(() {
+                                      _addressIsEmpty =
+                                          addressController.text.isEmpty;
+                                    });
+
+                                    _updateRecipientData();
+                                  }
+                                },
+                                child: _addressIsEmpty
+                                    ? const ClipboardIcon()
+                                    : const XIcon(),
+                              ),
+                        if (_addressIsEmpty)
+                          TextFieldIconButton(
+                            semanticsLabel: "Scan QR Button. "
+                                "Opens Camera For Scanning QR Code.",
+                            key: const Key(
+                              "sendViewScanQrButtonKey",
+                            ),
+                            onTap: () async {
+                              try {
+                                if (FocusScope.of(context).hasFocus) {
+                                  FocusScope.of(context).unfocus();
+                                  await Future<void>.delayed(
+                                    const Duration(
+                                      milliseconds: 75,
+                                    ),
+                                  );
+                                }
+
+                                final qrResult =
+                                    await ref.read(pBarcodeScanner).scan();
+
+                                Logging.instance.log(
+                                  "qrResult content: ${qrResult.rawContent}",
+                                  level: LogLevel.Info,
+                                );
+
+                                /// TODO: deal with address utils
+                                final results =
+                                    AddressUtils.parseUri(qrResult.rawContent);
+
+                                Logging.instance.log(
+                                  "qrResult parsed: $results",
+                                  level: LogLevel.Info,
+                                );
+
+                                if (results.isNotEmpty &&
+                                    results["scheme"] ==
+                                        widget.coin.uriScheme) {
+                                  // auto fill address
+
+                                  addressController.text =
+                                      (results["address"] ?? "").trim();
+
+                                  // autofill amount field
+                                  if (results["amount"] != null) {
+                                    final Amount amount =
+                                        Decimal.parse(results["amount"]!)
+                                            .toAmount(
+                                      fractionDigits: widget.coin.decimals,
+                                    );
+                                    amountController.text = ref
+                                        .read(pAmountFormatter(widget.coin))
+                                        .format(
+                                          amount,
+                                          withUnitName: false,
+                                        );
+                                  }
+                                } else {
+                                  addressController.text =
+                                      qrResult.rawContent.trim();
+                                }
+
+                                setState(() {
+                                  _addressIsEmpty =
+                                      addressController.text.isEmpty;
+                                });
+
+                                _updateRecipientData();
+                              } on PlatformException catch (e, s) {
+                                Logging.instance.log(
+                                  "Failed to get camera permissions while "
+                                  "trying to scan qr code in SendView: $e\n$s",
+                                  level: LogLevel.Warning,
+                                );
+                              }
+                            },
+                            child: const QrCodeIcon(),
+                          ),
+                      ],
+                    ),
+                  ),
+                ),
+              ),
+            ),
+          ),
+          const SizedBox(
+            height: 12,
+          ),
+          TextField(
+            autocorrect: false,
+            enableSuggestions: false,
+            style: STextStyles.smallMed14(context).copyWith(
+              color: Theme.of(context).extension<StackColors>()!.textDark,
+            ),
+            key: const Key("amountInputFieldCryptoTextFieldKey"),
+            controller: amountController,
+            focusNode: amountFocusNode,
+            keyboardType: Util.isDesktop
+                ? null
+                : const TextInputType.numberWithOptions(
+                    signed: false,
+                    decimal: true,
+                  ),
+            textAlign: TextAlign.right,
+            inputFormatters: [
+              AmountInputFormatter(
+                decimals: widget.coin.decimals,
+                unit: ref.watch(pAmountUnit(widget.coin)),
+                locale: locale,
+              ),
+            ],
+            decoration: InputDecoration(
+              contentPadding: const EdgeInsets.only(
+                top: 12,
+                right: 12,
+              ),
+              hintText: "0",
+              hintStyle: STextStyles.fieldLabel(context).copyWith(
+                fontSize: 14,
+              ),
+              prefixIcon: FittedBox(
+                fit: BoxFit.scaleDown,
+                child: Padding(
+                  padding: const EdgeInsets.all(12),
+                  child: Text(
+                    ref
+                        .watch(pAmountUnit(widget.coin))
+                        .unitForCoin(widget.coin),
+                    style: STextStyles.smallMed14(context).copyWith(
+                        color: Theme.of(context)
+                            .extension<StackColors>()!
+                            .accentColorDark),
+                  ),
+                ),
+              ),
+            ),
+          ),
+          // if (ref.watch(prefsChangeNotifierProvider
+          //     .select((value) => value.externalCalls)))
+          //   const SizedBox(
+          //     height: 8,
+          //   ),
+          // if (ref.watch(prefsChangeNotifierProvider
+          //     .select((value) => value.externalCalls)))
+          //   TextField(
+          //     autocorrect: Util.isDesktop ? false : true,
+          //     enableSuggestions: Util.isDesktop ? false : true,
+          //     style: STextStyles.smallMed14(context).copyWith(
+          //       color: Theme.of(context).extension<StackColors>()!.textDark,
+          //     ),
+          //     key: const Key("amountInputFieldFiatTextFieldKey"),
+          //     controller: baseController,
+          //     focusNode: baseFocusNode,
+          //     keyboardType: Util.isDesktop
+          //         ? null
+          //         : const TextInputType.numberWithOptions(
+          //             signed: false,
+          //             decimal: true,
+          //           ),
+          //     textAlign: TextAlign.right,
+          //     inputFormatters: [
+          //       AmountInputFormatter(
+          //         decimals: 2,
+          //         locale: locale,
+          //       ),
+          //     ],
+          //     onChanged: (baseAmountString) {
+          //       final baseAmount = Amount.tryParseFiatString(
+          //         baseAmountString,
+          //         locale: locale,
+          //       );
+          //       Amount? cryptoAmount;
+          //       final int decimals = widget.coin.decimals;
+          //       if (baseAmount != null) {
+          //         final _price = ref.read(_pPrice(widget.coin));
+          //
+          //         if (_price == Decimal.zero) {
+          //           cryptoAmount = 0.toAmountAsRaw(
+          //             fractionDigits: decimals,
+          //           );
+          //         } else {
+          //           cryptoAmount = baseAmount <= Amount.zero
+          //               ? 0.toAmountAsRaw(fractionDigits: decimals)
+          //               : (baseAmount.decimal / _price)
+          //                   .toDecimal(
+          //                     scaleOnInfinitePrecision: decimals,
+          //                   )
+          //                   .toAmount(fractionDigits: decimals);
+          //         }
+          //         if (ref.read(pRecipient(widget.index))?.amount != null &&
+          //             ref.read(pRecipient(widget.index))?.amount ==
+          //                 cryptoAmount) {
+          //           return;
+          //         }
+          //
+          //         final amountString =
+          //             ref.read(pAmountFormatter(widget.coin)).format(
+          //                   cryptoAmount,
+          //                   withUnitName: false,
+          //                 );
+          //
+          //         _cryptoAmountChangeLock = true;
+          //         amountController.text = amountString;
+          //         _cryptoAmountChangeLock = false;
+          //       } else {
+          //         cryptoAmount = 0.toAmountAsRaw(
+          //           fractionDigits: decimals,
+          //         );
+          //         _cryptoAmountChangeLock = true;
+          //         amountController.text = "";
+          //         _cryptoAmountChangeLock = false;
+          //       }
+          //
+          //       _updateRecipientData();
+          //     },
+          //     decoration: InputDecoration(
+          //       contentPadding: const EdgeInsets.only(
+          //         top: 12,
+          //         right: 12,
+          //       ),
+          //       hintText: "0",
+          //       hintStyle: STextStyles.fieldLabel(context).copyWith(
+          //         fontSize: 14,
+          //       ),
+          //       prefixIcon: FittedBox(
+          //         fit: BoxFit.scaleDown,
+          //         child: Padding(
+          //           padding: const EdgeInsets.all(12),
+          //           child: Text(
+          //             ref.watch(prefsChangeNotifierProvider
+          //                 .select((value) => value.currency)),
+          //             style: STextStyles.smallMed14(context).copyWith(
+          //                 color: Theme.of(context)
+          //                     .extension<StackColors>()!
+          //                     .accentColorDark),
+          //           ),
+          //         ),
+          //       ),
+          //     ),
+          //   ),
+          if (widget.remove != null)
+            const SizedBox(
+              height: 6,
+            ),
+          if (widget.remove != null)
+            Row(
+              children: [
+                const Spacer(),
+                CustomTextButton(
+                  text: "Remove",
+                  onTap: () {
+                    ref.read(pRecipient(widget.index).notifier).state = null;
+                    widget.remove?.call();
+                  },
+                ),
+              ],
+            ),
+        ],
+      ),
+    );
+  }
+}
diff --git a/lib/pages/wallet_view/wallet_view.dart b/lib/pages/wallet_view/wallet_view.dart
index bbb688f01..3bb5abbd8 100644
--- a/lib/pages/wallet_view/wallet_view.dart
+++ b/lib/pages/wallet_view/wallet_view.dart
@@ -29,6 +29,7 @@ import 'package:stackwallet/pages/ordinals/ordinals_view.dart';
 import 'package:stackwallet/pages/paynym/paynym_claim_view.dart';
 import 'package:stackwallet/pages/paynym/paynym_home_view.dart';
 import 'package:stackwallet/pages/receive_view/receive_view.dart';
+import 'package:stackwallet/pages/send_view/frost_ms/frost_send_view.dart';
 import 'package:stackwallet/pages/send_view/send_view.dart';
 import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart';
 import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_view.dart';
@@ -63,6 +64,7 @@ import 'package:stackwallet/utilities/logger.dart';
 import 'package:stackwallet/utilities/show_loading.dart';
 import 'package:stackwallet/utilities/text_styles.dart';
 import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart';
+import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
 import 'package:stackwallet/wallets/wallet/impl/firo_wallet.dart';
 import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/cash_fusion_interface.dart';
 import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart';
@@ -973,10 +975,13 @@ class _WalletViewState extends ConsumerState<WalletView> {
                       //     break;
                       // }
                       Navigator.of(context).pushNamed(
-                        SendView.routeName,
-                        arguments: Tuple2(
-                          walletId,
-                          coin,
+                        ref.read(pWallets).getWallet(walletId)
+                                is BitcoinFrostWallet
+                            ? FrostSendView.routeName
+                            : SendView.routeName,
+                        arguments: (
+                          walletId: walletId,
+                          coin: coin,
                         ),
                       );
                     },
diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/my_wallet.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/my_wallet.dart
index a330cb781..01ff6801f 100644
--- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/my_wallet.dart
+++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/my_wallet.dart
@@ -10,13 +10,17 @@
 
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:stackwallet/pages/send_view/frost_ms/frost_import_sign_config_view.dart';
+import 'package:stackwallet/pages/send_view/frost_ms/frost_send_view.dart';
 import 'package:stackwallet/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list.dart';
 import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_receive.dart';
 import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart';
 import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_token_send.dart';
 import 'package:stackwallet/providers/global/wallets_provider.dart';
 import 'package:stackwallet/utilities/enums/coin_enum.dart';
+import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
 import 'package:stackwallet/widgets/custom_tab_view.dart';
+import 'package:stackwallet/widgets/desktop/secondary_button.dart';
 import 'package:stackwallet/widgets/rounded_white_container.dart';
 
 class MyWallet extends ConsumerStatefulWidget {
@@ -40,11 +44,15 @@ class _MyWalletState extends ConsumerState<MyWallet> {
   ];
 
   late final bool isEth;
+  late final Coin coin;
+  late final bool isFrost;
 
   @override
   void initState() {
-    isEth = ref.read(pWallets).getWallet(widget.walletId).info.coin ==
-        Coin.ethereum;
+    final wallet = ref.read(pWallets).getWallet(widget.walletId);
+    coin = wallet.info.coin;
+    isFrost = wallet is BitcoinFrostWallet;
+    isEth = coin == Coin.ethereum;
 
     if (isEth && widget.contractAddress == null) {
       titles.add("Transactions");
@@ -64,12 +72,37 @@ class _MyWalletState extends ConsumerState<MyWallet> {
             titles: titles,
             children: [
               widget.contractAddress == null
-                  ? Padding(
-                      padding: const EdgeInsets.all(20),
-                      child: DesktopSend(
-                        walletId: widget.walletId,
-                      ),
-                    )
+                  ? isFrost
+                      ? Column(
+                          children: [
+                            Row(
+                              mainAxisAlignment: MainAxisAlignment.end,
+                              children: [
+                                SecondaryButton(
+                                  width: 200,
+                                  buttonHeight: ButtonHeight.l,
+                                  label: "Import sign config",
+                                  onPressed: () {
+                                    Navigator.of(context).pushNamed(
+                                      FrostImportSignConfigView.routeName,
+                                      arguments: widget.walletId,
+                                    );
+                                  },
+                                ),
+                              ],
+                            ),
+                            FrostSendView(
+                              walletId: widget.walletId,
+                              coin: coin,
+                            ),
+                          ],
+                        )
+                      : Padding(
+                          padding: const EdgeInsets.all(20),
+                          child: DesktopSend(
+                            walletId: widget.walletId,
+                          ),
+                        )
                   : Padding(
                       padding: const EdgeInsets.all(20),
                       child: DesktopTokenSend(
diff --git a/lib/route_generator.dart b/lib/route_generator.dart
index faf8967e8..87e29d64c 100644
--- a/lib/route_generator.dart
+++ b/lib/route_generator.dart
@@ -756,6 +756,24 @@ class RouteGenerator {
         }
         return _routeError("${settings.name} invalid args: ${args.toString()}");
 
+      case FrostSendView.routeName:
+        if (args is ({
+          String walletId,
+          Coin coin,
+        })) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => FrostSendView(
+              walletId: args.walletId,
+              coin: args.coin,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
       // case MonkeyLoadedView.routeName:
       //   if (args is Tuple2<String, ChangeNotifierProvider<Manager>>) {
       //     return getRoute(
diff --git a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
index 4f1c3febf..4058b8b59 100644
--- a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
+++ b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
@@ -29,6 +29,12 @@ import 'package:stackwallet/wallets/models/tx_data.dart';
 import 'package:stackwallet/wallets/wallet/wallet.dart';
 
 class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
+  @override
+  int get isarTransactionVersion => 2;
+
+  @override
+  bool get supportsMultiRecipient => true;
+
   BitcoinFrostWallet(CryptoCurrencyNetwork network)
       : super(BitcoinFrost(network) as T);
 
diff --git a/lib/wallets/wallet/wallet.dart b/lib/wallets/wallet/wallet.dart
index 959b7b635..ad18d6d4e 100644
--- a/lib/wallets/wallet/wallet.dart
+++ b/lib/wallets/wallet/wallet.dart
@@ -55,6 +55,9 @@ abstract class Wallet<T extends CryptoCurrency> {
   // default to Transaction class. For TransactionV2 set to 2
   int get isarTransactionVersion => 1;
 
+  // whether the wallet currently supports multiple recipients per tx
+  bool get supportsMultiRecipient => false;
+
   Wallet(this.cryptoCurrency);
 
   //============================================================================

From 1e67f3585aa7edc821afe809402108b220437fa8 Mon Sep 17 00:00:00 2001
From: julian <julian@cypherstack.com>
Date: Thu, 25 Jan 2024 02:20:37 -0600
Subject: [PATCH 09/57] some frost clean up

---
 lib/db/isar/main_db.dart                      |  2 +
 .../restore/restore_frost_ms_wallet_view.dart |  6 +--
 .../frost_attempt_sign_config_view.dart       | 17 +++----
 .../frost_ms/frost_complete_sign_view.dart    |  4 +-
 .../frost_continue_sign_config_view.dart      | 18 +++----
 .../frost_import_sign_config_view.dart        |  4 +-
 .../send_view/frost_ms/frost_send_view.dart   |  2 +-
 lib/route_generator.dart                      |  1 +
 .../wallet/impl/bitcoin_frost_wallet.dart     | 49 +++++++++++++++----
 9 files changed, 69 insertions(+), 34 deletions(-)

diff --git a/lib/db/isar/main_db.dart b/lib/db/isar/main_db.dart
index 528c99f98..ac5a544f4 100644
--- a/lib/db/isar/main_db.dart
+++ b/lib/db/isar/main_db.dart
@@ -21,6 +21,7 @@ import 'package:stackwallet/models/isar/stack_theme.dart';
 import 'package:stackwallet/utilities/amount/amount.dart';
 import 'package:stackwallet/utilities/enums/coin_enum.dart';
 import 'package:stackwallet/utilities/stack_file_system.dart';
+import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart';
 import 'package:stackwallet/wallets/isar/models/spark_coin.dart';
 import 'package:stackwallet/wallets/isar/models/token_wallet_info.dart';
 import 'package:stackwallet/wallets/isar/models/wallet_info.dart';
@@ -67,6 +68,7 @@ class MainDB {
         SparkCoinSchema,
         WalletInfoMetaSchema,
         TokenWalletInfoSchema,
+        FrostWalletInfoSchema,
       ],
       directory: (await StackFileSystem.applicationIsarDirectory()).path,
       // inspector: kDebugMode,
diff --git a/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart b/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart
index e99655f06..e316f22c8 100644
--- a/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart
+++ b/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart
@@ -4,7 +4,7 @@ import 'package:barcode_scan2/barcode_scan2.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:frostdart/frostdart.dart';
+import 'package:frostdart/frostdart.dart' as frost;
 import 'package:stackwallet/notifications/show_flush_bar.dart';
 import 'package:stackwallet/pages/home_view/home_view.dart';
 import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
@@ -70,7 +70,7 @@ class _RestoreFrostMsWalletViewState
     final keys = keysFieldController.text;
     final config = configFieldController.text;
 
-    final myNameIndex = getParticipantIndexFromKeys(serializedKeys: keys);
+    final myNameIndex = frost.getParticipantIndexFromKeys(serializedKeys: keys);
     final participants = Frost.getParticipants(multisigConfig: config);
     final myName = participants[myNameIndex];
 
@@ -92,7 +92,7 @@ class _RestoreFrostMsWalletViewState
       knownSalts: [],
       participants: participants,
       myName: myName,
-      threshold: multisigThreshold(
+      threshold: frost.multisigThreshold(
         multisigConfig: config,
       ),
     );
diff --git a/lib/pages/send_view/frost_ms/frost_attempt_sign_config_view.dart b/lib/pages/send_view/frost_ms/frost_attempt_sign_config_view.dart
index 64b33e9f9..7cdf4a69b 100644
--- a/lib/pages/send_view/frost_ms/frost_attempt_sign_config_view.dart
+++ b/lib/pages/send_view/frost_ms/frost_attempt_sign_config_view.dart
@@ -7,13 +7,13 @@ import 'package:stackwallet/pages/send_view/frost_ms/frost_continue_sign_config_
 import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
 import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
 import 'package:stackwallet/providers/global/wallets_provider.dart';
-import 'package:stackwallet/services/coins/bitcoin/frost_wallet.dart';
 import 'package:stackwallet/services/frost.dart';
 import 'package:stackwallet/themes/stack_colors.dart';
 import 'package:stackwallet/utilities/constants.dart';
 import 'package:stackwallet/utilities/logger.dart';
 import 'package:stackwallet/utilities/text_styles.dart';
 import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
 import 'package:stackwallet/widgets/background.dart';
 import 'package:stackwallet/widgets/conditional_parent.dart';
 import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
@@ -72,15 +72,14 @@ class _FrostAttemptSignConfigViewState
 
   @override
   void initState() {
-    final wallet = ref
-        .read(walletsChangeNotifierProvider)
-        .getManager(widget.walletId)
-        .wallet as FrostWallet;
+    final wallet =
+        ref.read(pWallets).getWallet(widget.walletId) as BitcoinFrostWallet;
+    final frostInfo = wallet.frostInfo;
 
-    myName = wallet.myName;
-    threshold = wallet.threshold;
-    participantsWithoutMe = wallet.participants;
-    myIndex = participantsWithoutMe.indexOf(wallet.myName);
+    myName = frostInfo.myName;
+    threshold = frostInfo.threshold;
+    participantsWithoutMe = frostInfo.participants;
+    myIndex = participantsWithoutMe.indexOf(frostInfo.myName);
     myPreprocess = ref.read(pFrostAttemptSignData.state).state!.preprocess;
 
     participantsWithoutMe.removeAt(myIndex);
diff --git a/lib/pages/send_view/frost_ms/frost_complete_sign_view.dart b/lib/pages/send_view/frost_ms/frost_complete_sign_view.dart
index c63dca04d..6478495c0 100644
--- a/lib/pages/send_view/frost_ms/frost_complete_sign_view.dart
+++ b/lib/pages/send_view/frost_ms/frost_complete_sign_view.dart
@@ -139,8 +139,8 @@ class _FrostCompleteSignViewState extends ConsumerState<FrostCompleteSignView> {
                   Exception? ex;
                   final txData = await showLoading(
                     whileFuture: ref
-                        .read(walletsChangeNotifierProvider)
-                        .getManager(widget.walletId)
+                        .read(pWallets)
+                        .getWallet(widget.walletId)
                         .confirmSend(
                           txData: ref.read(pFrostTxData.state).state!,
                         ),
diff --git a/lib/pages/send_view/frost_ms/frost_continue_sign_config_view.dart b/lib/pages/send_view/frost_ms/frost_continue_sign_config_view.dart
index 9d6494c62..732fb2f82 100644
--- a/lib/pages/send_view/frost_ms/frost_continue_sign_config_view.dart
+++ b/lib/pages/send_view/frost_ms/frost_continue_sign_config_view.dart
@@ -9,13 +9,13 @@ import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
 import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart';
 import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
 import 'package:stackwallet/providers/global/wallets_provider.dart';
-import 'package:stackwallet/services/coins/bitcoin/frost_wallet.dart';
 import 'package:stackwallet/services/frost.dart';
 import 'package:stackwallet/themes/stack_colors.dart';
 import 'package:stackwallet/utilities/constants.dart';
 import 'package:stackwallet/utilities/logger.dart';
 import 'package:stackwallet/utilities/text_styles.dart';
 import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
 import 'package:stackwallet/widgets/background.dart';
 import 'package:stackwallet/widgets/conditional_parent.dart';
 import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
@@ -61,17 +61,17 @@ class _FrostContinueSignViewState extends ConsumerState<FrostContinueSignView> {
 
   @override
   void initState() {
-    final wallet = ref
-        .read(walletsChangeNotifierProvider)
-        .getManager(widget.walletId)
-        .wallet as FrostWallet;
+    final wallet =
+        ref.read(pWallets).getWallet(widget.walletId) as BitcoinFrostWallet;
 
-    myName = wallet.myName;
-    participantsAll = wallet.participants;
-    myIndex = wallet.participants.indexOf(wallet.myName);
+    final frostInfo = wallet.frostInfo;
+
+    myName = frostInfo.myName;
+    participantsAll = frostInfo.participants;
+    myIndex = frostInfo.participants.indexOf(frostInfo.myName);
     myShare = ref.read(pFrostContinueSignData.state).state!.share;
 
-    participantsWithoutMe = wallet.participants
+    participantsWithoutMe = frostInfo.participants
         .toSet()
         .intersection(
             ref.read(pFrostSelectParticipantsUnordered.state).state!.toSet())
diff --git a/lib/pages/send_view/frost_ms/frost_import_sign_config_view.dart b/lib/pages/send_view/frost_ms/frost_import_sign_config_view.dart
index b390e0b67..c89b6846a 100644
--- a/lib/pages/send_view/frost_ms/frost_import_sign_config_view.dart
+++ b/lib/pages/send_view/frost_ms/frost_import_sign_config_view.dart
@@ -92,7 +92,9 @@ class _FrostImportSignConfigViewState
       // TODO add more data from 'data' and display to user ?
       ref.read(pFrostTxData.notifier).state = TxData(
         frostMSConfig: config,
-        recipients: data.recipients,
+        recipients: data.recipients
+            .map((e) => (address: e.address, amount: e.amount, isChange: false))
+            .toList(),
         utxos: utxos.toSet(),
       );
 
diff --git a/lib/pages/send_view/frost_ms/frost_send_view.dart b/lib/pages/send_view/frost_ms/frost_send_view.dart
index cf64d8e54..1865556b7 100644
--- a/lib/pages/send_view/frost_ms/frost_send_view.dart
+++ b/lib/pages/send_view/frost_ms/frost_send_view.dart
@@ -84,7 +84,7 @@ class _FrostSendViewState extends ConsumerState<FrostSendView> {
 
     final recipients = recipientWidgetIndexes
         .map((i) => ref.read(pRecipient(i).state).state)
-        .map((e) => (address: e!.address, amount: e.amount!, isChange: false))
+        .map((e) => (address: e!.address, amount: e!.amount!, isChange: false))
         .toList(growable: false);
 
     final txData = await wallet.frostCreateSignConfig(
diff --git a/lib/route_generator.dart b/lib/route_generator.dart
index 87e29d64c..26e24653c 100644
--- a/lib/route_generator.dart
+++ b/lib/route_generator.dart
@@ -83,6 +83,7 @@ import 'package:stackwallet/pages/receive_view/addresses/wallet_addresses_view.d
 import 'package:stackwallet/pages/receive_view/generate_receiving_uri_qr_code_view.dart';
 import 'package:stackwallet/pages/receive_view/receive_view.dart';
 import 'package:stackwallet/pages/send_view/confirm_transaction_view.dart';
+import 'package:stackwallet/pages/send_view/frost_ms/frost_send_view.dart';
 import 'package:stackwallet/pages/send_view/send_view.dart';
 import 'package:stackwallet/pages/send_view/token_send_view.dart';
 import 'package:stackwallet/pages/settings_views/global_settings_view/about_view.dart';
diff --git a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
index 4058b8b59..be3b7b821 100644
--- a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
+++ b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
@@ -29,12 +29,6 @@ import 'package:stackwallet/wallets/models/tx_data.dart';
 import 'package:stackwallet/wallets/wallet/wallet.dart';
 
 class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
-  @override
-  int get isarTransactionVersion => 2;
-
-  @override
-  bool get supportsMultiRecipient => true;
-
   BitcoinFrostWallet(CryptoCurrencyNetwork network)
       : super(BitcoinFrost(network) as T);
 
@@ -89,7 +83,9 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
       await _saveMultisigId(multisigId);
       await _saveMultisigConfig(multisigConfig);
 
-      await mainDB.isar.frostWalletInfo.put(frostWalletInfo);
+      await mainDB.isar.writeTxn(() async {
+        await mainDB.isar.frostWalletInfo.put(frostWalletInfo);
+      });
 
       final keys = frost.deserializeKeys(keys: serializedKeys);
 
@@ -299,6 +295,9 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
 
   // ==================== Overrides ============================================
 
+  @override
+  bool get supportsMultiRecipient => true;
+
   @override
   int get isarTransactionVersion => 2;
 
@@ -527,8 +526,40 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
 
   @override
   Future<void> checkSaveInitialReceivingAddress() async {
-    // should not be needed for frost as we explicitly save the address
-    // on new init and restore
+    final address = await getCurrentReceivingAddress();
+    if (address == null) {
+      final serializedKeys = await getSerializedKeys();
+      if (serializedKeys != null) {
+        final keys = frost.deserializeKeys(keys: serializedKeys);
+
+        final addressString = frost.addressForKeys(
+          network: cryptoCurrency.network == CryptoCurrencyNetwork.main
+              ? Network.Mainnet
+              : Network.Testnet,
+          keys: keys,
+        );
+
+        final publicKey = frost.scriptPubKeyForKeys(keys: keys);
+
+        final address = Address(
+          walletId: walletId,
+          value: addressString,
+          publicKey: publicKey.toUint8ListFromHex,
+          derivationIndex: 0,
+          derivationPath: null,
+          subType: AddressSubType.receiving,
+          type: AddressType.frostMS,
+        );
+
+        await mainDB.updateOrPutAddresses([address]);
+      } else {
+        Logging.instance.log(
+          "$runtimeType.checkSaveInitialReceivingAddress() failed due"
+          " to missing serialized keys",
+          level: LogLevel.Fatal,
+        );
+      }
+    }
   }
 
   @override

From b3fa5147340f7ae873b58ceb863c79ed6e9af4e9 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Thu, 25 Jan 2024 12:13:35 -0600
Subject: [PATCH 10/57] use github.com instead of www.github.com as frostdart
 submodule url

caused issues for me initializing submodule using git on cli

see https://stackoverflow.com/a/64991733 and related
---
 .gitmodules | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.gitmodules b/.gitmodules
index 98bb17794..925be21c0 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -9,4 +9,4 @@
 	url = https://github.com/cypherstack/flutter_liblelantus.git
 [submodule "crypto_plugins/frostdart"]
 	path = crypto_plugins/frostdart
-	url = https://www.github.com/cypherstack/frostdart
+	url = https://github.com/cypherstack/frostdart

From 2aa3bebf78280f56650c3f0f7be5e7bf7a8964cf Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Thu, 25 Jan 2024 19:03:53 -0600
Subject: [PATCH 11/57] wrap send view content in padding

will probably need to be adjusted for mobile...
---
 .../send_view/frost_ms/frost_send_view.dart   | 388 +++++++++---------
 1 file changed, 198 insertions(+), 190 deletions(-)

diff --git a/lib/pages/send_view/frost_ms/frost_send_view.dart b/lib/pages/send_view/frost_ms/frost_send_view.dart
index 1865556b7..95d45cb95 100644
--- a/lib/pages/send_view/frost_ms/frost_send_view.dart
+++ b/lib/pages/send_view/frost_ms/frost_send_view.dart
@@ -391,207 +391,215 @@ class _FrostSendViewState extends ConsumerState<FrostSendView> {
           const SizedBox(
             height: 16,
           ),
-          Row(
-            mainAxisAlignment: MainAxisAlignment.spaceBetween,
-            children: [
-              Text(
-                "Recipients",
-                style: STextStyles.smallMed12(context),
-                textAlign: TextAlign.left,
-              ),
-              CustomTextButton(
-                text: "Add",
-                onTap: () {
-                  // used for tracking recipient forms
-                  _greatestWidgetIndex++;
-                  recipientWidgetIndexes.add(_greatestWidgetIndex);
-                  setState(() {});
-                },
-              ),
-            ],
-          ),
-          const SizedBox(
-            height: 8,
-          ),
-          Column(
-            children: [
-              for (int i = 0; i < recipientWidgetIndexes.length; i++)
-                ConditionalParent(
-                  condition: recipientWidgetIndexes.length > 1,
-                  builder: (child) => Padding(
-                    padding: const EdgeInsets.only(top: 8),
-                    child: child,
-                  ),
-                  child: Recipient(
-                    key: Key(
-                      "recipientKey_${recipientWidgetIndexes[i]}",
-                    ),
-                    index: recipientWidgetIndexes[i],
-                    coin: coin,
-                    onChanged: () {
-                      _validateRecipientFormStates();
-                    },
-                    remove: i == 0 && recipientWidgetIndexes.length == 1
-                        ? null
-                        : () {
-                            recipientWidgetIndexes.removeAt(i);
-                            setState(() {});
-                          },
-                  ),
-                ),
-            ],
-          ),
-          if (showCoinControl)
-            const SizedBox(
-              height: 8,
+          Padding(
+            padding: const EdgeInsets.symmetric(
+              horizontal: 20,
             ),
-          if (showCoinControl)
-            RoundedWhiteContainer(
-              child: Row(
+            child: Column(children: [
+              Row(
                 mainAxisAlignment: MainAxisAlignment.spaceBetween,
                 children: [
                   Text(
-                    "Coin control",
-                    style: STextStyles.w500_14(context).copyWith(
-                      color: Theme.of(context)
-                          .extension<StackColors>()!
-                          .textSubtitle1,
-                    ),
+                    "Recipients",
+                    style: STextStyles.smallMed12(context),
+                    textAlign: TextAlign.left,
                   ),
                   CustomTextButton(
-                    text: selectedUTXOs.isEmpty
-                        ? "Select coins"
-                        : "Selected coins (${selectedUTXOs.length})",
-                    onTap: () async {
-                      if (FocusScope.of(context).hasFocus) {
-                        FocusScope.of(context).unfocus();
-                        await Future<void>.delayed(
-                          const Duration(milliseconds: 100),
-                        );
-                      }
-
-                      if (mounted) {
-                        // finally spendable = ref
-                        //     .read(walletsChangeNotifierProvider)
-                        //     .getManager(widget.walletId)
-                        //     .balance
-                        //     .spendable;
-
-                        // TODO: [prio=high] make sure this coincontrol works correctly
-
-                        Amount? amount;
-
-                        final result = await Navigator.of(context).pushNamed(
-                          CoinControlView.routeName,
-                          arguments: Tuple4(
-                            walletId,
-                            CoinControlViewType.use,
-                            amount,
-                            selectedUTXOs,
-                          ),
-                        );
-
-                        if (result is Set<UTXO>) {
-                          setState(() {
-                            selectedUTXOs = result;
-                          });
-                        }
-                      }
+                    text: "Add",
+                    onTap: () {
+                      // used for tracking recipient forms
+                      _greatestWidgetIndex++;
+                      recipientWidgetIndexes.add(_greatestWidgetIndex);
+                      setState(() {});
                     },
                   ),
                 ],
               ),
-            ),
-          const SizedBox(
-            height: 12,
-          ),
-          Text(
-            "Note (optional)",
-            style: STextStyles.smallMed12(context),
-            textAlign: TextAlign.left,
-          ),
-          const SizedBox(
-            height: 8,
-          ),
-          ClipRRect(
-            borderRadius: BorderRadius.circular(
-              Constants.size.circularBorderRadius,
-            ),
-            child: TextField(
-              autocorrect: Util.isDesktop ? false : true,
-              enableSuggestions: Util.isDesktop ? false : true,
-              controller: noteController,
-              focusNode: _noteFocusNode,
-              style: STextStyles.field(context),
-              onChanged: (_) => setState(() {}),
-              decoration: standardInputDecoration(
-                "Type something...",
-                _noteFocusNode,
-                context,
-              ).copyWith(
-                suffixIcon: noteController.text.isNotEmpty
-                    ? Padding(
-                        padding: const EdgeInsets.only(right: 0),
-                        child: UnconstrainedBox(
-                          child: Row(
-                            children: [
-                              TextFieldIconButton(
-                                child: const XIcon(),
-                                onTap: () async {
-                                  setState(() {
-                                    noteController.text = "";
-                                  });
-                                },
-                              ),
-                            ],
-                          ),
-                        ),
-                      )
-                    : null,
+              const SizedBox(
+                height: 8,
               ),
-            ),
-          ),
-          const SizedBox(
-            height: 12,
-          ),
-          Padding(
-            padding: const EdgeInsets.only(
-              bottom: 12,
-              top: 16,
-            ),
-            child: FeeSlider(
-              coin: coin,
-              onSatVByteChanged: (rate) {
-                customFeeRate = rate;
-              },
-            ),
-          ),
-          Util.isDesktop
-              ? const SizedBox(
-                  height: 12,
-                )
-              : const Spacer(),
-          const SizedBox(
-            height: 12,
-          ),
-          TextButton(
-            onPressed: ref.watch(previewTxButtonStateProvider.state).state
-                ? _createSignConfig
-                : null,
-            style: ref.watch(previewTxButtonStateProvider.state).state
-                ? Theme.of(context)
-                    .extension<StackColors>()!
-                    .getPrimaryEnabledButtonStyle(context)
-                : Theme.of(context)
-                    .extension<StackColors>()!
-                    .getPrimaryDisabledButtonStyle(context),
-            child: Text(
-              "Create config",
-              style: STextStyles.button(context),
-            ),
-          ),
-          const SizedBox(
-            height: 16,
+              Column(
+                children: [
+                  for (int i = 0; i < recipientWidgetIndexes.length; i++)
+                    ConditionalParent(
+                      condition: recipientWidgetIndexes.length > 1,
+                      builder: (child) => Padding(
+                        padding: const EdgeInsets.only(top: 8),
+                        child: child,
+                      ),
+                      child: Recipient(
+                        key: Key(
+                          "recipientKey_${recipientWidgetIndexes[i]}",
+                        ),
+                        index: recipientWidgetIndexes[i],
+                        coin: coin,
+                        onChanged: () {
+                          _validateRecipientFormStates();
+                        },
+                        remove: i == 0 && recipientWidgetIndexes.length == 1
+                            ? null
+                            : () {
+                                recipientWidgetIndexes.removeAt(i);
+                                setState(() {});
+                              },
+                      ),
+                    ),
+                ],
+              ),
+              if (showCoinControl)
+                const SizedBox(
+                  height: 8,
+                ),
+              if (showCoinControl)
+                RoundedWhiteContainer(
+                  child: Row(
+                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                    children: [
+                      Text(
+                        "Coin control",
+                        style: STextStyles.w500_14(context).copyWith(
+                          color: Theme.of(context)
+                              .extension<StackColors>()!
+                              .textSubtitle1,
+                        ),
+                      ),
+                      CustomTextButton(
+                        text: selectedUTXOs.isEmpty
+                            ? "Select coins"
+                            : "Selected coins (${selectedUTXOs.length})",
+                        onTap: () async {
+                          if (FocusScope.of(context).hasFocus) {
+                            FocusScope.of(context).unfocus();
+                            await Future<void>.delayed(
+                              const Duration(milliseconds: 100),
+                            );
+                          }
+
+                          if (mounted) {
+                            // finally spendable = ref
+                            //     .read(walletsChangeNotifierProvider)
+                            //     .getManager(widget.walletId)
+                            //     .balance
+                            //     .spendable;
+
+                            // TODO: [prio=high] make sure this coincontrol works correctly
+
+                            Amount? amount;
+
+                            final result =
+                                await Navigator.of(context).pushNamed(
+                              CoinControlView.routeName,
+                              arguments: Tuple4(
+                                walletId,
+                                CoinControlViewType.use,
+                                amount,
+                                selectedUTXOs,
+                              ),
+                            );
+
+                            if (result is Set<UTXO>) {
+                              setState(() {
+                                selectedUTXOs = result;
+                              });
+                            }
+                          }
+                        },
+                      ),
+                    ],
+                  ),
+                ),
+              const SizedBox(
+                height: 12,
+              ),
+              Text(
+                "Note (optional)",
+                style: STextStyles.smallMed12(context),
+                textAlign: TextAlign.left,
+              ),
+              const SizedBox(
+                height: 8,
+              ),
+              ClipRRect(
+                borderRadius: BorderRadius.circular(
+                  Constants.size.circularBorderRadius,
+                ),
+                child: TextField(
+                  autocorrect: Util.isDesktop ? false : true,
+                  enableSuggestions: Util.isDesktop ? false : true,
+                  controller: noteController,
+                  focusNode: _noteFocusNode,
+                  style: STextStyles.field(context),
+                  onChanged: (_) => setState(() {}),
+                  decoration: standardInputDecoration(
+                    "Type something...",
+                    _noteFocusNode,
+                    context,
+                  ).copyWith(
+                    suffixIcon: noteController.text.isNotEmpty
+                        ? Padding(
+                            padding: const EdgeInsets.only(right: 0),
+                            child: UnconstrainedBox(
+                              child: Row(
+                                children: [
+                                  TextFieldIconButton(
+                                    child: const XIcon(),
+                                    onTap: () async {
+                                      setState(() {
+                                        noteController.text = "";
+                                      });
+                                    },
+                                  ),
+                                ],
+                              ),
+                            ),
+                          )
+                        : null,
+                  ),
+                ),
+              ),
+              const SizedBox(
+                height: 12,
+              ),
+              Padding(
+                padding: const EdgeInsets.only(
+                  bottom: 12,
+                  top: 16,
+                ),
+                child: FeeSlider(
+                  coin: coin,
+                  onSatVByteChanged: (rate) {
+                    customFeeRate = rate;
+                  },
+                ),
+              ),
+              Util.isDesktop
+                  ? const SizedBox(
+                      height: 12,
+                    )
+                  : const Spacer(),
+              const SizedBox(
+                height: 12,
+              ),
+              TextButton(
+                onPressed: ref.watch(previewTxButtonStateProvider.state).state
+                    ? _createSignConfig
+                    : null,
+                style: ref.watch(previewTxButtonStateProvider.state).state
+                    ? Theme.of(context)
+                        .extension<StackColors>()!
+                        .getPrimaryEnabledButtonStyle(context)
+                    : Theme.of(context)
+                        .extension<StackColors>()!
+                        .getPrimaryDisabledButtonStyle(context),
+                child: Text(
+                  "Create config",
+                  style: STextStyles.button(context),
+                ),
+              ),
+              const SizedBox(
+                height: 16,
+              ),
+            ]),
           ),
         ],
       ),

From 77f1f346d632598e970c44db57704536bcfc13c7 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Thu, 25 Jan 2024 19:04:07 -0600
Subject: [PATCH 12/57] override recipient input(s) padding

---
 lib/pages/send_view/frost_ms/recipient.dart | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/pages/send_view/frost_ms/recipient.dart b/lib/pages/send_view/frost_ms/recipient.dart
index e59d3e9ad..89121d065 100644
--- a/lib/pages/send_view/frost_ms/recipient.dart
+++ b/lib/pages/send_view/frost_ms/recipient.dart
@@ -149,6 +149,7 @@ class _RecipientState extends ConsumerState<Recipient> {
     );
 
     return RoundedWhiteContainer(
+      padding: const EdgeInsets.all(0),
       child: Column(
         mainAxisSize: MainAxisSize.min,
         crossAxisAlignment: CrossAxisAlignment.start,

From a100e6a15c17582e7950500b2471db368ffca4ed Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Mon, 29 Jan 2024 17:31:41 -0600
Subject: [PATCH 13/57] only show frost-related config buttons for frost coins

---
 .../name_your_wallet_view/name_your_wallet_view.dart            | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart b/lib/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart
index ed91d265e..7ddaaba3a 100644
--- a/lib/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart
+++ b/lib/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart
@@ -399,7 +399,7 @@ class _NameYourWalletViewState extends ConsumerState<NameYourWalletView> {
                   );
                 },
               ),
-          if (widget.addWalletType == AddWalletType.New)
+          if (widget.coin.isFrost && widget.addWalletType == AddWalletType.New)
             Column(
               children: [
                 PrimaryButton(

From cce94676a69b996a6c7a4f2219651caa03b3112a Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Mon, 29 Jan 2024 23:29:52 -0600
Subject: [PATCH 14/57] fix bitcoin frost wallet restoration

---
 .../frost_ms/restore/restore_frost_ms_wallet_view.dart    | 4 +++-
 lib/wallets/wallet/impl/bitcoin_frost_wallet.dart         | 8 +++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart b/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart
index e316f22c8..c9c174ab0 100644
--- a/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart
+++ b/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart
@@ -97,7 +97,9 @@ class _RestoreFrostMsWalletViewState
       ),
     );
 
-    await ref.read(mainDBProvider).isar.frostWalletInfo.put(frostInfo);
+    await ref.read(mainDBProvider).isar.writeTxn(() async {
+      await ref.read(mainDBProvider).isar.frostWalletInfo.put(frostInfo);
+    });
 
     await (wallet as BitcoinFrostWallet).recover(
       serializedKeys: keys,
diff --git a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
index be3b7b821..aacad77e4 100644
--- a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
+++ b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
@@ -718,8 +718,9 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
           if (knownSalts.contains(salt)) {
             throw Exception("Known frost multisig salt found!");
           }
-          knownSalts.add(salt);
-          await _updateKnownSalts(knownSalts);
+          List<String> updatedKnownSalts = List<String>.from(knownSalts);
+          updatedKnownSalts.add(salt);
+          await _updateKnownSalts(updatedKnownSalts);
         } else {
           // clear cache
           await electrumXCachedClient.clearSharedTransactionCache(coin: coin);
@@ -1001,8 +1002,9 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
       .findFirstSync()!;
 
   Future<void> _updateKnownSalts(List<String> knownSalts) async {
+    final info = frostInfo;
+
     await mainDB.isar.writeTxn(() async {
-      final info = frostInfo;
       await mainDB.isar.frostWalletInfo.delete(info.id);
       await mainDB.isar.frostWalletInfo.put(
         info.copyWith(knownSalts: knownSalts),

From 0f73f762162f9a18627135868013377eba91a9b4 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Tue, 30 Jan 2024 11:43:09 -0600
Subject: [PATCH 15/57] refactor _multisigConfig to getMultisigConfig for SWB
 purposes

---
 lib/wallets/wallet/impl/bitcoin_frost_wallet.dart | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
index aacad77e4..851c41eed 100644
--- a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
+++ b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
@@ -930,7 +930,8 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
         key: "{$walletId}_serializedFROSTKeysPrevGen",
       );
 
-  Future<String?> _multisigConfig() async => await secureStorageInterface.read(
+  Future<String?> getMultisigConfig() async =>
+      await secureStorageInterface.read(
         key: "{$walletId}_multisigConfig",
       );
 
@@ -942,7 +943,7 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
   Future<void> _saveMultisigConfig(
     String multisigConfig,
   ) async {
-    final current = await _multisigConfig();
+    final current = await getMultisigConfig();
 
     if (current == null) {
       // do nothing

From 8ba98d573c463bbbe9e0f99f128ad80272ae5ddb Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Tue, 30 Jan 2024 11:43:40 -0600
Subject: [PATCH 16/57] save frost keys and config in otherDataJsonString
 during SWB creation

---
 .../helpers/restore_create_backup.dart                | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart
index 9891148d7..222a2f948 100644
--- a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart
+++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart
@@ -42,6 +42,7 @@ import 'package:stackwallet/utilities/logger.dart';
 import 'package:stackwallet/utilities/prefs.dart';
 import 'package:stackwallet/utilities/util.dart';
 import 'package:stackwallet/wallets/isar/models/wallet_info.dart';
+import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
 import 'package:stackwallet/wallets/wallet/impl/epiccash_wallet.dart';
 import 'package:stackwallet/wallets/wallet/wallet.dart';
 import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/cw_based_interface.dart';
@@ -302,6 +303,16 @@ abstract class SWB {
               await wallet.getMnemonicPassphrase();
         } else if (wallet is PrivateKeyInterface) {
           backupWallet['privateKey'] = await wallet.getPrivateKey();
+        } else if (wallet is BitcoinFrostWallet) {
+          String? keys = await wallet.getSerializedKeys();
+          String? config = await wallet.getMultisigConfig();
+          // TODO handle case in which either keys or config is null.
+
+          // Format keys and config as a JSON string and set otherDataJsonString.
+          Map<String, dynamic> otherData = {};
+          otherData["keys"] = keys;
+          otherData["config"] = config;
+          backupWallet['otherDataJsonString'] = jsonEncode(otherData);
         }
         backupWallet['coinName'] = wallet.info.coin.name;
         backupWallet['storedChainHeight'] = wallet.info.cachedChainHeight;

From 79fedf46e55dd588d4ee3c0792a91182b9033cba Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Tue, 30 Jan 2024 11:48:50 -0600
Subject: [PATCH 17/57] throw err if keys or config are null

---
 .../helpers/restore_create_backup.dart                 | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart
index 222a2f948..11254181a 100644
--- a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart
+++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart
@@ -306,9 +306,15 @@ abstract class SWB {
         } else if (wallet is BitcoinFrostWallet) {
           String? keys = await wallet.getSerializedKeys();
           String? config = await wallet.getMultisigConfig();
-          // TODO handle case in which either keys or config is null.
+          if (keys == null || config == null) {
+            String err = "${wallet.info.coin.name} wallet ${wallet.info.name} "
+                "has null keys or config";
+            Logging.instance.log(err, level: LogLevel.Fatal);
+            throw Exception(err);
+          }
+          // TODO [prio=low]: solve case in which either keys or config is null.
 
-          // Format keys and config as a JSON string and set otherDataJsonString.
+          // Format keys & config as a JSON string and set otherDataJsonString.
           Map<String, dynamic> otherData = {};
           otherData["keys"] = keys;
           otherData["config"] = config;

From a17a551a2b21c76e2ef9c7020c1951c4b3228791 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Tue, 30 Jan 2024 12:25:39 -0600
Subject: [PATCH 18/57] add myName to saved frost info

---
 .../stack_backup_views/helpers/restore_create_backup.dart       | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart
index 11254181a..01cc9f65e 100644
--- a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart
+++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart
@@ -306,6 +306,7 @@ abstract class SWB {
         } else if (wallet is BitcoinFrostWallet) {
           String? keys = await wallet.getSerializedKeys();
           String? config = await wallet.getMultisigConfig();
+          String myName = wallet.frostInfo.myName;
           if (keys == null || config == null) {
             String err = "${wallet.info.coin.name} wallet ${wallet.info.name} "
                 "has null keys or config";
@@ -318,6 +319,7 @@ abstract class SWB {
           Map<String, dynamic> otherData = {};
           otherData["keys"] = keys;
           otherData["config"] = config;
+          otherData["myName"] = myName;
           backupWallet['otherDataJsonString'] = jsonEncode(otherData);
         }
         backupWallet['coinName'] = wallet.info.coin.name;

From 8cbca16a3a67bfd34bc5fa54b116d9565f0518e1 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Tue, 30 Jan 2024 12:41:37 -0600
Subject: [PATCH 19/57] WIP first attempt at Frost wallet restoration from
 backup

---
 .../helpers/restore_create_backup.dart        | 99 +++++++++++++++++--
 1 file changed, 89 insertions(+), 10 deletions(-)

diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart
index 01cc9f65e..c47630279 100644
--- a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart
+++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart
@@ -10,9 +10,11 @@
 
 import 'dart:async';
 import 'dart:convert';
+import 'dart:ffi';
 import 'dart:io';
 import 'dart:typed_data';
 
+import 'package:frostdart/frostdart_bindings_generated.dart';
 import 'package:isar/isar.dart';
 import 'package:stack_wallet_backup/stack_wallet_backup.dart';
 import 'package:stackwallet/db/hive/db.dart';
@@ -26,6 +28,7 @@ import 'package:stackwallet/models/stack_restoring_ui_state.dart';
 import 'package:stackwallet/models/trade_wallet_lookup.dart';
 import 'package:stackwallet/models/wallet_restore_state.dart';
 import 'package:stackwallet/services/address_book_service.dart';
+import 'package:stackwallet/services/frost.dart';
 import 'package:stackwallet/services/node_service.dart';
 import 'package:stackwallet/services/trade_notes_service.dart';
 import 'package:stackwallet/services/trade_sent_from_stack_service.dart';
@@ -425,16 +428,92 @@ abstract class SWB {
     );
 
     try {
-      final wallet = await Wallet.create(
-        walletInfo: info,
-        mainDB: MainDB.instance,
-        secureStorageInterface: secureStorageInterface,
-        nodeService: nodeService,
-        prefs: prefs,
-        mnemonic: mnemonic,
-        mnemonicPassphrase: mnemonicPassphrase,
-        privateKey: privateKey,
-      );
+      final Wallet wallet;
+
+      if (info.coin == Coin.bitcoinFrost ||
+          info.coin == Coin.bitcoinFrostTestNet) {
+        // Decode info.otherDataJsonString for Frost recovery info.
+        final otherData = jsonDecode(info.otherDataJsonString!);
+        final String serializedKeys = otherData["keys"] as String;
+        final String multisigConfig = otherData["config"] as String;
+        final String myName = otherData["myName"] as String;
+
+        // Start Frost key generation.
+        final frostStartKeyGenData = Frost.startKeyGeneration(
+          multisigConfig: multisigConfig,
+          myName: myName,
+        );
+
+        // Generate shares.
+        final ({
+          Pointer<SecretSharesRes> secretSharesResPtr,
+          String share
+        }) frostSecretSharesData;
+        try {
+          frostSecretSharesData = Frost.generateSecretShares(
+            multisigConfigWithNamePtr:
+                frostStartKeyGenData.multisigConfigWithNamePtr,
+            mySeed: frostStartKeyGenData.seed,
+            secretShareMachineWrapperPtr:
+                frostStartKeyGenData.secretShareMachineWrapperPtr,
+            commitments: [frostStartKeyGenData.commitments],
+          );
+        } catch (e, s) {
+          Logging.instance.log(
+            "$e\n$s",
+            level: LogLevel.Fatal,
+          );
+
+          throw Error();
+        }
+
+        // Get shares.
+        final shares = [
+          frostSecretSharesData.share,
+        ];
+
+        // Complete Frost key generation.
+        final frostCompleteKeyGenData = Frost.completeKeyGeneration(
+          multisigConfigWithNamePtr:
+              frostStartKeyGenData.multisigConfigWithNamePtr,
+          secretSharesResPtr: frostSecretSharesData.secretSharesResPtr,
+          shares: [frostSecretSharesData.share], // TODO [prio=high]: verify.
+        );
+
+        wallet = await Wallet.create(
+          walletInfo: info,
+          mainDB: MainDB.instance,
+          secureStorageInterface: secureStorageInterface,
+          nodeService: nodeService,
+          prefs: prefs,
+        );
+
+        await (wallet as BitcoinFrostWallet).initializeNewFrost(
+          mnemonic: frostStartKeyGenData.seed,
+          multisigConfig: multisigConfig,
+          recoveryString: frostCompleteKeyGenData.recoveryString,
+          serializedKeys: serializedKeys,
+          multisigId: frostCompleteKeyGenData.multisigId,
+          myName: myName,
+          participants: Frost.getParticipants(
+            multisigConfig: multisigConfig,
+          ),
+          threshold: Frost.getThreshold(
+            multisigConfig: multisigConfig,
+          ),
+        );
+      } else {
+        wallet = await Wallet.create(
+          walletInfo: info,
+          mainDB: MainDB.instance,
+          secureStorageInterface: secureStorageInterface,
+          nodeService: nodeService,
+          prefs: prefs,
+          mnemonic: mnemonic,
+          mnemonicPassphrase: mnemonicPassphrase,
+          privateKey: privateKey,
+        );
+      }
 
       await wallet.init();
 

From 2e6ac40e205724541beb479356b85d9cf7f66e1c Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Tue, 30 Jan 2024 12:45:39 -0600
Subject: [PATCH 20/57] fix 'cannot cast Null to String'

---
 .../stack_backup_views/helpers/restore_create_backup.dart     | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart
index c47630279..4dec9dac7 100644
--- a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart
+++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart
@@ -406,7 +406,9 @@ abstract class SWB {
 
     if (walletbackup['mnemonic'] == null) {
       // probably private key based
-      privateKey = walletbackup['privateKey'] as String;
+      if (walletbackup['privateKey'] != null) {
+        privateKey = walletbackup['privateKey'] as String;
+      }
     } else {
       if (walletbackup['mnemonic'] is List) {
         List<String> mnemonicList = (walletbackup['mnemonic'] as List<dynamic>)

From 0d3ef1bfc4b3a76573e0afb5efbc1c64c67dfde2 Mon Sep 17 00:00:00 2001
From: julian <julian@cypherstack.com>
Date: Tue, 30 Jan 2024 18:08:31 -0600
Subject: [PATCH 21/57] frost swb integration fixes

---
 .../helpers/restore_create_backup.dart        | 137 +++++++-----------
 1 file changed, 50 insertions(+), 87 deletions(-)

diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart
index 4dec9dac7..f6491cf1d 100644
--- a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart
+++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart
@@ -10,11 +10,10 @@
 
 import 'dart:async';
 import 'dart:convert';
-import 'dart:ffi';
 import 'dart:io';
 import 'dart:typed_data';
 
-import 'package:frostdart/frostdart_bindings_generated.dart';
+import 'package:frostdart/frostdart.dart' as frost;
 import 'package:isar/isar.dart';
 import 'package:stack_wallet_backup/stack_wallet_backup.dart';
 import 'package:stackwallet/db/hive/db.dart';
@@ -44,6 +43,7 @@ import 'package:stackwallet/utilities/format.dart';
 import 'package:stackwallet/utilities/logger.dart';
 import 'package:stackwallet/utilities/prefs.dart';
 import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart';
 import 'package:stackwallet/wallets/isar/models/wallet_info.dart';
 import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
 import 'package:stackwallet/wallets/wallet/impl/epiccash_wallet.dart';
@@ -309,21 +309,21 @@ abstract class SWB {
         } else if (wallet is BitcoinFrostWallet) {
           String? keys = await wallet.getSerializedKeys();
           String? config = await wallet.getMultisigConfig();
-          String myName = wallet.frostInfo.myName;
           if (keys == null || config == null) {
             String err = "${wallet.info.coin.name} wallet ${wallet.info.name} "
                 "has null keys or config";
             Logging.instance.log(err, level: LogLevel.Fatal);
             throw Exception(err);
           }
+          //This case should never actually happen in practice unless the whole
+          // wallet is somehow corrupt
           // TODO [prio=low]: solve case in which either keys or config is null.
 
           // Format keys & config as a JSON string and set otherDataJsonString.
-          Map<String, dynamic> otherData = {};
-          otherData["keys"] = keys;
-          otherData["config"] = config;
-          otherData["myName"] = myName;
-          backupWallet['otherDataJsonString'] = jsonEncode(otherData);
+          Map<String, dynamic> frostData = {};
+          frostData["keys"] = keys;
+          frostData["config"] = config;
+          backupWallet['frostWalletData'] = jsonEncode(frostData);
         }
         backupWallet['coinName'] = wallet.info.coin.name;
         backupWallet['storedChainHeight'] = wallet.info.cachedChainHeight;
@@ -430,93 +430,48 @@ abstract class SWB {
     );
 
     try {
-      final Wallet wallet;
-
-      if (info.coin == Coin.bitcoinFrost ||
-          info.coin == Coin.bitcoinFrostTestNet) {
+      String? serializedKeys;
+      String? multisigConfig;
+      if (info.coin.isFrost) {
         // Decode info.otherDataJsonString for Frost recovery info.
-        final otherData = jsonDecode(info.otherDataJsonString!);
-        final String serializedKeys = otherData["keys"] as String;
-        final String multisigConfig = otherData["config"] as String;
-        final String myName = otherData["myName"] as String;
+        final frostData = jsonDecode(walletbackup["frostWalletData"] as String);
+        serializedKeys = frostData["keys"] as String;
+        multisigConfig = frostData["config"] as String;
 
-        // Start Frost key generation.
-        final frostStartKeyGenData = Frost.startKeyGeneration(
-          multisigConfig: multisigConfig,
-          myName: myName,
-        );
-
-        // Generate shares.
-        final ({
-          Pointer<SecretSharesRes> secretSharesResPtr,
-          String share
-        }) frostSecretSharesData;
-        try {
-          frostSecretSharesData = Frost.generateSecretShares(
-            multisigConfigWithNamePtr:
-                frostStartKeyGenData.multisigConfigWithNamePtr,
-            mySeed: frostStartKeyGenData.seed,
-            secretShareMachineWrapperPtr:
-                frostStartKeyGenData.secretShareMachineWrapperPtr,
-            commitments: [frostStartKeyGenData.commitments],
-          );
-        } catch (e, s) {
-          Logging.instance.log(
-            "$e\n$s",
-            level: LogLevel.Fatal,
-          );
-
-          throw Error();
-        }
-
-        // Get shares.
-        final shares = [
-          frostSecretSharesData.share,
-        ];
-
-        // Complete Frost key generation.
-        final frostCompleteKeyGenData = Frost.completeKeyGeneration(
-          multisigConfigWithNamePtr:
-              frostStartKeyGenData.multisigConfigWithNamePtr,
-          secretSharesResPtr: frostSecretSharesData.secretSharesResPtr,
-          shares: [frostSecretSharesData.share], // TODO [prio=high]: verify.
-        );
-
-        wallet = await Wallet.create(
-          walletInfo: info,
-          mainDB: MainDB.instance,
-          secureStorageInterface: secureStorageInterface,
-          nodeService: nodeService,
-          prefs: prefs,
-        );
-
-        await (wallet as BitcoinFrostWallet).initializeNewFrost(
-          mnemonic: frostStartKeyGenData.seed,
-          multisigConfig: multisigConfig,
-          recoveryString: frostCompleteKeyGenData.recoveryString,
+        final myNameIndex = frost.getParticipantIndexFromKeys(
           serializedKeys: serializedKeys,
-          multisigId: frostCompleteKeyGenData.multisigId,
+        );
+        final participants = Frost.getParticipants(
+          multisigConfig: multisigConfig,
+        );
+        final myName = participants[myNameIndex];
+
+        final frostInfo = FrostWalletInfo(
+          walletId: info.walletId,
+          knownSalts: [],
+          participants: participants,
           myName: myName,
-          participants: Frost.getParticipants(
-            multisigConfig: multisigConfig,
-          ),
-          threshold: Frost.getThreshold(
+          threshold: frost.multisigThreshold(
             multisigConfig: multisigConfig,
           ),
         );
-      } else {
-        wallet = await Wallet.create(
-          walletInfo: info,
-          mainDB: MainDB.instance,
-          secureStorageInterface: secureStorageInterface,
-          nodeService: nodeService,
-          prefs: prefs,
-          mnemonic: mnemonic,
-          mnemonicPassphrase: mnemonicPassphrase,
-          privateKey: privateKey,
-        );
+
+        await MainDB.instance.isar.writeTxn(() async {
+          await MainDB.instance.isar.frostWalletInfo.put(frostInfo);
+        });
       }
 
+      final wallet = await Wallet.create(
+        walletInfo: info,
+        mainDB: MainDB.instance,
+        secureStorageInterface: secureStorageInterface,
+        nodeService: nodeService,
+        prefs: prefs,
+        mnemonic: mnemonic,
+        mnemonicPassphrase: mnemonicPassphrase,
+        privateKey: privateKey,
+      );
+
       await wallet.init();
 
       int restoreHeight = walletbackup['restoreHeight'] as int? ?? 0;
@@ -527,7 +482,15 @@ abstract class SWB {
       Future<void>? restoringFuture;
 
       if (!(wallet is CwBasedInterface || wallet is EpiccashWallet)) {
-        restoringFuture = wallet.recover(isRescan: false);
+        if (wallet is BitcoinFrostWallet) {
+          restoringFuture = wallet.recover(
+            isRescan: false,
+            multisigConfig: multisigConfig!,
+            serializedKeys: serializedKeys!,
+          );
+        } else {
+          restoringFuture = wallet.recover(isRescan: false);
+        }
       }
 
       uiState?.update(

From ccf1e3437776da374a57caad2a78605bc58587f6 Mon Sep 17 00:00:00 2001
From: julian <julian@cypherstack.com>
Date: Tue, 30 Jan 2024 19:50:55 -0600
Subject: [PATCH 22/57] port of frost backup keys ui from stack frost

---
 .../wallet_backup_view.dart                   | 391 ++++++++++++------
 .../wallet_settings_view.dart                 | 105 +++--
 .../firo_rescan_recovery_error_dialog.dart    |   7 +-
 .../unlock_wallet_keys_desktop.dart           |  43 +-
 .../wallet_keys_desktop_popup.dart            | 216 ++++++----
 lib/route_generator.dart                      |  35 +-
 .../wallet/impl/bitcoin_frost_wallet.dart     |   4 +-
 7 files changed, 550 insertions(+), 251 deletions(-)

diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_backup_views/wallet_backup_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_backup_views/wallet_backup_view.dart
index 8c2873d0d..5b1548514 100644
--- a/lib/pages/settings_views/wallet_settings_view/wallet_backup_views/wallet_backup_view.dart
+++ b/lib/pages/settings_views/wallet_settings_view/wallet_backup_views/wallet_backup_view.dart
@@ -23,16 +23,23 @@ import 'package:stackwallet/utilities/assets.dart';
 import 'package:stackwallet/utilities/clipboard_interface.dart';
 import 'package:stackwallet/utilities/constants.dart';
 import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
 import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart';
 import 'package:stackwallet/widgets/background.dart';
 import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
+import 'package:stackwallet/widgets/detail_item.dart';
+import 'package:stackwallet/widgets/rounded_white_container.dart';
 import 'package:stackwallet/widgets/stack_dialog.dart';
 
+import '../../../wallet_view/transaction_views/transaction_details_view.dart';
+
 class WalletBackupView extends ConsumerWidget {
   const WalletBackupView({
     Key? key,
     required this.walletId,
     required this.mnemonic,
+    this.frostWalletData,
     this.clipboardInterface = const ClipboardWrapper(),
   }) : super(key: key);
 
@@ -40,11 +47,21 @@ class WalletBackupView extends ConsumerWidget {
 
   final String walletId;
   final List<String> mnemonic;
+  final ({
+    String myName,
+    String config,
+    String keys,
+    ({String config, String keys})? prevGen,
+  })? frostWalletData;
   final ClipboardInterface clipboardInterface;
 
   @override
   Widget build(BuildContext context, WidgetRef ref) {
     debugPrint("BUILD: $runtimeType");
+
+    final bool frost = frostWalletData != null;
+    final prevGen = frostWalletData?.prevGen != null;
+
     return Background(
       child: Scaffold(
         backgroundColor: Theme.of(context).extension<StackColors>()!.background,
@@ -91,139 +108,261 @@ class WalletBackupView extends ConsumerWidget {
         ),
         body: Padding(
           padding: const EdgeInsets.all(16),
-          child: Column(
-            crossAxisAlignment: CrossAxisAlignment.stretch,
-            children: [
-              const SizedBox(
-                height: 4,
-              ),
-              Text(
-                ref.watch(pWalletName(walletId)),
-                textAlign: TextAlign.center,
-                style: STextStyles.label(context).copyWith(
-                  fontSize: 12,
-                ),
-              ),
-              const SizedBox(
-                height: 4,
-              ),
-              Text(
-                "Recovery Phrase",
-                textAlign: TextAlign.center,
-                style: STextStyles.pageTitleH1(context),
-              ),
-              const SizedBox(
-                height: 16,
-              ),
-              Container(
-                decoration: BoxDecoration(
-                  color: Theme.of(context).extension<StackColors>()!.popupBG,
-                  borderRadius: BorderRadius.circular(
-                      Constants.size.circularBorderRadius),
-                ),
-                child: Padding(
-                  padding: const EdgeInsets.all(12),
-                  child: Text(
-                    "Please write down your backup key. Keep it safe and never share it with anyone. Your backup key is the only way you can access your funds if you forget your PIN, lose your phone, etc.\n\nStack Wallet does not keep nor is able to restore your backup key. Only you have access to your wallet.",
-                    style: STextStyles.label(context),
-                  ),
-                ),
-              ),
-              const SizedBox(
-                height: 8,
-              ),
-              Expanded(
-                child: SingleChildScrollView(
-                  child: MnemonicTable(
-                    words: mnemonic,
-                    isDesktop: false,
-                  ),
-                ),
-              ),
-              const SizedBox(
-                height: 12,
-              ),
-              TextButton(
-                style: Theme.of(context)
-                    .extension<StackColors>()!
-                    .getPrimaryEnabledButtonStyle(context),
-                onPressed: () {
-                  String data = AddressUtils.encodeQRSeedData(mnemonic);
-
-                  showDialog<dynamic>(
-                    context: context,
-                    useSafeArea: false,
-                    barrierDismissible: true,
-                    builder: (_) {
-                      final width = MediaQuery.of(context).size.width / 2;
-                      return StackDialogBase(
-                        child: Column(
-                          crossAxisAlignment: CrossAxisAlignment.stretch,
-                          children: [
-                            Center(
-                              child: Text(
-                                "Recovery phrase QR code",
-                                style: STextStyles.pageTitleH2(context),
-                              ),
-                            ),
-                            const SizedBox(
-                              height: 12,
-                            ),
-                            Center(
-                              child: RepaintBoundary(
-                                // key: _qrKey,
-                                child: SizedBox(
-                                  width: width + 20,
-                                  height: width + 20,
-                                  child: QrImageView(
-                                      data: data,
-                                      size: width,
-                                      backgroundColor: Theme.of(context)
-                                          .extension<StackColors>()!
-                                          .popupBG,
-                                      foregroundColor: Theme.of(context)
-                                          .extension<StackColors>()!
-                                          .accentColorDark),
+          child: frost
+              ? LayoutBuilder(
+                  builder: (builderContext, constraints) {
+                    return SingleChildScrollView(
+                      child: ConstrainedBox(
+                        constraints: BoxConstraints(
+                          minHeight: constraints.maxHeight - 24,
+                        ),
+                        child: IntrinsicHeight(
+                          child: Column(
+                            crossAxisAlignment: CrossAxisAlignment.stretch,
+                            children: [
+                              RoundedWhiteContainer(
+                                child: Text(
+                                  "Please write down your backup data. Keep it safe and "
+                                  "never share it with anyone. "
+                                  "Your backup data is the only way you can access your "
+                                  "funds if you forget your PIN, lose your phone, etc."
+                                  "\n\n"
+                                  "Stack Wallet does not keep nor is able to restore "
+                                  "your backup data. "
+                                  "Only you have access to your wallet.",
+                                  style: STextStyles.label(context),
                                 ),
                               ),
-                            ),
-                            const SizedBox(
-                              height: 12,
-                            ),
-                            Center(
-                              child: SizedBox(
-                                width: width,
-                                child: TextButton(
-                                  onPressed: () async {
-                                    // await _capturePng(true);
-                                    Navigator.of(context).pop();
-                                  },
-                                  style: Theme.of(context)
-                                      .extension<StackColors>()!
-                                      .getSecondaryEnabledButtonStyle(context),
+                              const SizedBox(
+                                height: 24,
+                              ),
+                              // DetailItem(
+                              //   title: "My name",
+                              //   detail: frostWalletData!.myName,
+                              //   button: Util.isDesktop
+                              //       ? IconCopyButton(
+                              //           data: frostWalletData!.myName,
+                              //         )
+                              //       : SimpleCopyButton(
+                              //           data: frostWalletData!.myName,
+                              //         ),
+                              // ),
+                              // const SizedBox(
+                              //   height: 16,
+                              // ),
+                              DetailItem(
+                                title: "Multisig config",
+                                detail: frostWalletData!.config,
+                                button: Util.isDesktop
+                                    ? IconCopyButton(
+                                        data: frostWalletData!.config,
+                                      )
+                                    : SimpleCopyButton(
+                                        data: frostWalletData!.config,
+                                      ),
+                              ),
+                              const SizedBox(
+                                height: 16,
+                              ),
+                              DetailItem(
+                                title: "Keys",
+                                detail: frostWalletData!.keys,
+                                button: Util.isDesktop
+                                    ? IconCopyButton(
+                                        data: frostWalletData!.keys,
+                                      )
+                                    : SimpleCopyButton(
+                                        data: frostWalletData!.keys,
+                                      ),
+                              ),
+                              if (prevGen)
+                                const SizedBox(
+                                  height: 24,
+                                ),
+                              if (prevGen)
+                                RoundedWhiteContainer(
                                   child: Text(
-                                    "Cancel",
-                                    style: STextStyles.button(context).copyWith(
-                                        color: Theme.of(context)
-                                            .extension<StackColors>()!
-                                            .accentColorDark),
+                                    "Previous generation info",
+                                    style: STextStyles.label(context),
                                   ),
                                 ),
-                              ),
-                            ),
-                          ],
+                              if (prevGen)
+                                const SizedBox(
+                                  height: 12,
+                                ),
+                              if (prevGen)
+                                DetailItem(
+                                  title: "Previous multisig config",
+                                  detail: frostWalletData!.prevGen!.config,
+                                  button: Util.isDesktop
+                                      ? IconCopyButton(
+                                          data:
+                                              frostWalletData!.prevGen!.config,
+                                        )
+                                      : SimpleCopyButton(
+                                          data:
+                                              frostWalletData!.prevGen!.config,
+                                        ),
+                                ),
+                              if (prevGen)
+                                const SizedBox(
+                                  height: 16,
+                                ),
+                              if (prevGen)
+                                DetailItem(
+                                  title: "Previous keys",
+                                  detail: frostWalletData!.prevGen!.keys,
+                                  button: Util.isDesktop
+                                      ? IconCopyButton(
+                                          data: frostWalletData!.prevGen!.keys,
+                                        )
+                                      : SimpleCopyButton(
+                                          data: frostWalletData!.prevGen!.keys,
+                                        ),
+                                ),
+                            ],
+                          ),
                         ),
-                      );
-                    },
-                  );
-                },
-                child: Text(
-                  "Show QR Code",
-                  style: STextStyles.button(context),
+                      ),
+                    );
+                  },
+                )
+              : Column(
+                  crossAxisAlignment: CrossAxisAlignment.stretch,
+                  children: [
+                    const SizedBox(
+                      height: 4,
+                    ),
+                    Text(
+                      ref.watch(pWalletName(walletId)),
+                      textAlign: TextAlign.center,
+                      style: STextStyles.label(context).copyWith(
+                        fontSize: 12,
+                      ),
+                    ),
+                    const SizedBox(
+                      height: 4,
+                    ),
+                    Text(
+                      "Recovery Phrase",
+                      textAlign: TextAlign.center,
+                      style: STextStyles.pageTitleH1(context),
+                    ),
+                    const SizedBox(
+                      height: 16,
+                    ),
+                    Container(
+                      decoration: BoxDecoration(
+                        color:
+                            Theme.of(context).extension<StackColors>()!.popupBG,
+                        borderRadius: BorderRadius.circular(
+                            Constants.size.circularBorderRadius),
+                      ),
+                      child: Padding(
+                        padding: const EdgeInsets.all(12),
+                        child: Text(
+                          "Please write down your backup key. Keep it safe and never share it with anyone. Your backup key is the only way you can access your funds if you forget your PIN, lose your phone, etc.\n\nStack Wallet does not keep nor is able to restore your backup key. Only you have access to your wallet.",
+                          style: STextStyles.label(context),
+                        ),
+                      ),
+                    ),
+                    const SizedBox(
+                      height: 8,
+                    ),
+                    Expanded(
+                      child: SingleChildScrollView(
+                        child: MnemonicTable(
+                          words: mnemonic,
+                          isDesktop: false,
+                        ),
+                      ),
+                    ),
+                    const SizedBox(
+                      height: 12,
+                    ),
+                    TextButton(
+                      style: Theme.of(context)
+                          .extension<StackColors>()!
+                          .getPrimaryEnabledButtonStyle(context),
+                      onPressed: () {
+                        String data = AddressUtils.encodeQRSeedData(mnemonic);
+
+                        showDialog<dynamic>(
+                          context: context,
+                          useSafeArea: false,
+                          barrierDismissible: true,
+                          builder: (_) {
+                            final width = MediaQuery.of(context).size.width / 2;
+                            return StackDialogBase(
+                              child: Column(
+                                crossAxisAlignment: CrossAxisAlignment.stretch,
+                                children: [
+                                  Center(
+                                    child: Text(
+                                      "Recovery phrase QR code",
+                                      style: STextStyles.pageTitleH2(context),
+                                    ),
+                                  ),
+                                  const SizedBox(
+                                    height: 12,
+                                  ),
+                                  Center(
+                                    child: RepaintBoundary(
+                                      // key: _qrKey,
+                                      child: SizedBox(
+                                        width: width + 20,
+                                        height: width + 20,
+                                        child: QrImageView(
+                                            data: data,
+                                            size: width,
+                                            backgroundColor: Theme.of(context)
+                                                .extension<StackColors>()!
+                                                .popupBG,
+                                            foregroundColor: Theme.of(context)
+                                                .extension<StackColors>()!
+                                                .accentColorDark),
+                                      ),
+                                    ),
+                                  ),
+                                  const SizedBox(
+                                    height: 12,
+                                  ),
+                                  Center(
+                                    child: SizedBox(
+                                      width: width,
+                                      child: TextButton(
+                                        onPressed: () async {
+                                          // await _capturePng(true);
+                                          Navigator.of(context).pop();
+                                        },
+                                        style: Theme.of(context)
+                                            .extension<StackColors>()!
+                                            .getSecondaryEnabledButtonStyle(
+                                                context),
+                                        child: Text(
+                                          "Cancel",
+                                          style: STextStyles.button(context)
+                                              .copyWith(
+                                                  color: Theme.of(context)
+                                                      .extension<StackColors>()!
+                                                      .accentColorDark),
+                                        ),
+                                      ),
+                                    ),
+                                  ),
+                                ],
+                              ),
+                            );
+                          },
+                        );
+                      },
+                      child: Text(
+                        "Show QR Code",
+                        style: STextStyles.button(context),
+                      ),
+                    ),
+                  ],
                 ),
-              ),
-            ],
-          ),
         ),
       ),
     );
diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart
index 0714528e0..e0b870326 100644
--- a/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart
+++ b/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart
@@ -39,6 +39,7 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart';
 import 'package:stackwallet/utilities/show_loading.dart';
 import 'package:stackwallet/utilities/text_styles.dart';
 import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
 import 'package:stackwallet/wallets/wallet/impl/epiccash_wallet.dart';
 import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart';
 import 'package:stackwallet/widgets/background.dart';
@@ -235,39 +236,83 @@ class _WalletSettingsViewState extends ConsumerState<WalletSettingsView> {
                                         final wallet = ref
                                             .read(pWallets)
                                             .getWallet(widget.walletId);
-                                        // TODO: [prio=frost] take wallets that don't have a mnemonic into account
-                                        if (wallet is MnemonicInterface) {
-                                          final mnemonic =
-                                              await wallet.getMnemonicAsWords();
 
-                                          if (mounted) {
-                                            await Navigator.push(
-                                              context,
-                                              RouteGenerator.getRoute(
-                                                shouldUseMaterialRoute:
-                                                    RouteGenerator
-                                                        .useMaterialPageRoute,
-                                                builder: (_) => LockscreenView(
-                                                  routeOnSuccessArguments:
-                                                      Tuple2(
-                                                          walletId, mnemonic),
-                                                  showBackButton: true,
-                                                  routeOnSuccess:
-                                                      WalletBackupView
-                                                          .routeName,
-                                                  biometricsCancelButtonString:
-                                                      "CANCEL",
-                                                  biometricsLocalizedReason:
-                                                      "Authenticate to view recovery phrase",
-                                                  biometricsAuthenticationTitle:
-                                                      "View recovery phrase",
-                                                ),
-                                                settings: const RouteSettings(
-                                                    name:
-                                                        "/viewRecoverPhraseLockscreen"),
-                                              ),
+                                        // TODO: [prio=med] take wallets that don't have a mnemonic into account
+
+                                        List<String>? mnemonic;
+                                        ({
+                                          String myName,
+                                          String config,
+                                          String keys,
+                                          ({
+                                            String config,
+                                            String keys
+                                          })? prevGen,
+                                        })? frostWalletData;
+                                        if (wallet is BitcoinFrostWallet) {
+                                          List<Future<dynamic>> futures = [];
+
+                                          futures.addAll(
+                                            [
+                                              wallet.getSerializedKeys(),
+                                              wallet.getMultisigConfig(),
+                                              wallet.getSerializedKeysPrevGen(),
+                                              wallet.getMultisigConfigPrevGen(),
+                                            ],
+                                          );
+
+                                          final results =
+                                              await Future.wait(futures);
+
+                                          if (results.length == 5) {
+                                            frostWalletData = (
+                                              myName: wallet.frostInfo.myName,
+                                              config: results[1],
+                                              keys: results[0],
+                                              prevGen: results[2] == null ||
+                                                      results[3] == null
+                                                  ? null
+                                                  : (
+                                                      config: results[3],
+                                                      keys: results[2],
+                                                    ),
                                             );
                                           }
+                                        } else if (wallet
+                                            is MnemonicInterface) {
+                                          mnemonic =
+                                              await wallet.getMnemonicAsWords();
+                                        }
+
+                                        if (mounted) {
+                                          await Navigator.push(
+                                            context,
+                                            RouteGenerator.getRoute(
+                                              shouldUseMaterialRoute:
+                                                  RouteGenerator
+                                                      .useMaterialPageRoute,
+                                              builder: (_) => LockscreenView(
+                                                routeOnSuccessArguments: (
+                                                  walletId: walletId,
+                                                  mnemonic: mnemonic ?? [],
+                                                  frostWalletData:
+                                                      frostWalletData,
+                                                ),
+                                                showBackButton: true,
+                                                routeOnSuccess:
+                                                    WalletBackupView.routeName,
+                                                biometricsCancelButtonString:
+                                                    "CANCEL",
+                                                biometricsLocalizedReason:
+                                                    "Authenticate to view recovery phrase",
+                                                biometricsAuthenticationTitle:
+                                                    "View recovery phrase",
+                                              ),
+                                              settings: const RouteSettings(
+                                                  name:
+                                                      "/viewRecoverPhraseLockscreen"),
+                                            ),
+                                          );
                                         }
                                       },
                                     );
diff --git a/lib/pages/special/firo_rescan_recovery_error_dialog.dart b/lib/pages/special/firo_rescan_recovery_error_dialog.dart
index d062b62d5..40d8e8d6c 100644
--- a/lib/pages/special/firo_rescan_recovery_error_dialog.dart
+++ b/lib/pages/special/firo_rescan_recovery_error_dialog.dart
@@ -23,7 +23,6 @@ import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
 import 'package:stackwallet/widgets/desktop/primary_button.dart';
 import 'package:stackwallet/widgets/desktop/secondary_button.dart';
 import 'package:stackwallet/widgets/stack_dialog.dart';
-import 'package:tuple/tuple.dart';
 
 enum FiroRescanRecoveryErrorViewOption {
   retry,
@@ -269,8 +268,10 @@ class _FiroRescanRecoveryErrorViewState
                                 shouldUseMaterialRoute:
                                     RouteGenerator.useMaterialPageRoute,
                                 builder: (_) => LockscreenView(
-                                  routeOnSuccessArguments:
-                                      Tuple2(widget.walletId, mnemonic),
+                                  routeOnSuccessArguments: (
+                                    walletId: widget.walletId,
+                                    mnemonic: mnemonic,
+                                  ),
                                   showBackButton: true,
                                   routeOnSuccess: WalletBackupView.routeName,
                                   biometricsCancelButtonString: "CANCEL",
diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/unlock_wallet_keys_desktop.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/unlock_wallet_keys_desktop.dart
index 0a9a5a29e..c621a4030 100644
--- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/unlock_wallet_keys_desktop.dart
+++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/unlock_wallet_keys_desktop.dart
@@ -21,6 +21,7 @@ import 'package:stackwallet/themes/stack_colors.dart';
 import 'package:stackwallet/utilities/assets.dart';
 import 'package:stackwallet/utilities/constants.dart';
 import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
 import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart';
 import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
 import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
@@ -80,19 +81,31 @@ class _UnlockWalletKeysDesktopState
       Navigator.of(context, rootNavigator: true).pop();
 
       final wallet = ref.read(pWallets).getWallet(widget.walletId);
+      ({String keys, String config})? frostData;
+      List<String>? words;
 
-      // TODO: [prio=med] handle wallets that don't have a mnemonic
+      // TODO: [prio=low] handle wallets that don't have a mnemonic
       // All wallets currently are mnemonic based
       if (wallet is! MnemonicInterface) {
-        throw Exception("FIXME ~= see todo in code");
+        if (wallet is BitcoinFrostWallet) {
+          frostData = (
+            keys: (await wallet.getMultisigConfig())!,
+            config: (await wallet.getMultisigConfig())!,
+          );
+        } else {
+          throw Exception("FIXME ~= see todo in code");
+        }
+      } else {
+        words = await wallet.getMnemonicAsWords();
       }
 
-      final words = await wallet.getMnemonicAsWords();
-
       if (mounted) {
         await Navigator.of(context).pushReplacementNamed(
           WalletKeysDesktopPopup.routeName,
-          arguments: words,
+          arguments: (
+            mnemonic: words ?? [],
+            frostData: frostData,
+          ),
         );
       }
     } else {
@@ -301,21 +314,35 @@ class _UnlockWalletKeysDesktopState
                             if (verified) {
                               Navigator.of(context, rootNavigator: true).pop();
 
+                              ({String keys, String config})? frostData;
+                              List<String>? words;
+
                               final wallet =
                                   ref.read(pWallets).getWallet(widget.walletId);
 
                               // TODO: [prio=low] handle wallets that don't have a mnemonic
                               // All wallets currently are mnemonic based
                               if (wallet is! MnemonicInterface) {
-                                throw Exception("FIXME ~= see todo in code");
+                                if (wallet is BitcoinFrostWallet) {
+                                  frostData = (
+                                    keys: (await wallet.getMultisigConfig())!,
+                                    config: (await wallet.getMultisigConfig())!,
+                                  );
+                                } else {
+                                  throw Exception("FIXME ~= see todo in code");
+                                }
+                              } else {
+                                words = await wallet.getMnemonicAsWords();
                               }
 
-                              final words = await wallet.getMnemonicAsWords();
                               if (mounted) {
                                 await Navigator.of(context)
                                     .pushReplacementNamed(
                                   WalletKeysDesktopPopup.routeName,
-                                  arguments: words,
+                                  arguments: (
+                                    mnemonic: words ?? [],
+                                    frostData: frostData,
+                                  ),
                                 );
                               }
                             } else {
diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_keys_desktop_popup.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_keys_desktop_popup.dart
index 14574a083..60f0d2436 100644
--- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_keys_desktop_popup.dart
+++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_keys_desktop_popup.dart
@@ -29,10 +29,12 @@ class WalletKeysDesktopPopup extends StatelessWidget {
   const WalletKeysDesktopPopup({
     Key? key,
     required this.words,
+    this.frostData,
     this.clipboardInterface = const ClipboardWrapper(),
   }) : super(key: key);
 
   final List<String> words;
+  final ({String keys, String config})? frostData;
   final ClipboardInterface clipboardInterface;
 
   static const String routeName = "walletKeysDesktopPopup";
@@ -66,85 +68,145 @@ class WalletKeysDesktopPopup extends StatelessWidget {
           const SizedBox(
             height: 28,
           ),
-          Text(
-            "Recovery phrase",
-            style: STextStyles.desktopTextMedium(context),
-          ),
-          const SizedBox(
-            height: 8,
-          ),
-          Center(
-            child: Padding(
-              padding: const EdgeInsets.symmetric(
-                horizontal: 32,
-              ),
-              child: Text(
-                "Please write down your recovery phrase in the correct order and save it to keep your funds secure. You will also be asked to verify the words on the next screen.",
-                style: STextStyles.desktopTextExtraExtraSmall(context),
-                textAlign: TextAlign.center,
-              ),
-            ),
-          ),
-          const SizedBox(
-            height: 24,
-          ),
-          Padding(
-            padding: const EdgeInsets.symmetric(
-              horizontal: 32,
-            ),
-            child: MnemonicTable(
-              words: words,
-              isDesktop: true,
-              itemBorderColor: Theme.of(context)
-                  .extension<StackColors>()!
-                  .buttonBackSecondary,
-            ),
-          ),
-          const SizedBox(
-            height: 24,
-          ),
-          Padding(
-            padding: const EdgeInsets.symmetric(
-              horizontal: 32,
-            ),
-            child: Row(
-              children: [
-                Expanded(
-                  child: SecondaryButton(
-                    label: "Show QR code",
-                    onPressed: () {
-                      final String value = AddressUtils.encodeQRSeedData(words);
-                      Navigator.of(context).pushNamed(
-                        QRCodeDesktopPopupContent.routeName,
-                        arguments: value,
-                      );
-                    },
-                  ),
-                ),
-                const SizedBox(
-                  width: 16,
-                ),
-                Expanded(
-                  child: PrimaryButton(
-                    label: "Copy",
-                    onPressed: () async {
-                      await clipboardInterface.setData(
-                        ClipboardData(text: words.join(" ")),
-                      );
-                      unawaited(
-                        showFloatingFlushBar(
-                          type: FlushBarType.info,
-                          message: "Copied to clipboard",
-                          iconAsset: Assets.svg.copy,
-                          context: context,
+          frostData != null
+              ? Column(
+                  children: [
+                    Text(
+                      "Keys",
+                      style: STextStyles.desktopTextMedium(context),
+                    ),
+                    const SizedBox(
+                      height: 8,
+                    ),
+                    Center(
+                      child: Padding(
+                        padding: const EdgeInsets.symmetric(
+                          horizontal: 32,
                         ),
-                      );
-                    },
-                  ),
+                        child: SelectableText(
+                          frostData!.keys,
+                          style:
+                              STextStyles.desktopTextExtraExtraSmall(context),
+                          textAlign: TextAlign.center,
+                        ),
+                      ),
+                    ),
+                    const SizedBox(
+                      height: 24,
+                    ),
+                    Text(
+                      "Config",
+                      style: STextStyles.desktopTextMedium(context),
+                    ),
+                    const SizedBox(
+                      height: 8,
+                    ),
+                    Center(
+                      child: Padding(
+                        padding: const EdgeInsets.symmetric(
+                          horizontal: 32,
+                        ),
+                        child: SelectableText(
+                          frostData!.config,
+                          style:
+                              STextStyles.desktopTextExtraExtraSmall(context),
+                          textAlign: TextAlign.center,
+                        ),
+                      ),
+                    ),
+                    const SizedBox(
+                      height: 24,
+                    ),
+                  ],
+                )
+              : Column(
+                  children: [
+                    Text(
+                      "Recovery phrase",
+                      style: STextStyles.desktopTextMedium(context),
+                    ),
+                    const SizedBox(
+                      height: 8,
+                    ),
+                    Center(
+                      child: Padding(
+                        padding: const EdgeInsets.symmetric(
+                          horizontal: 32,
+                        ),
+                        child: Text(
+                          "Please write down your recovery phrase in the correct order and save it to keep your funds secure. You will also be asked to verify the words on the next screen.",
+                          style:
+                              STextStyles.desktopTextExtraExtraSmall(context),
+                          textAlign: TextAlign.center,
+                        ),
+                      ),
+                    ),
+                    const SizedBox(
+                      height: 24,
+                    ),
+                    Padding(
+                      padding: const EdgeInsets.symmetric(
+                        horizontal: 32,
+                      ),
+                      child: MnemonicTable(
+                        words: words,
+                        isDesktop: true,
+                        itemBorderColor: Theme.of(context)
+                            .extension<StackColors>()!
+                            .buttonBackSecondary,
+                      ),
+                    ),
+                    const SizedBox(
+                      height: 24,
+                    ),
+                    Padding(
+                      padding: const EdgeInsets.symmetric(
+                        horizontal: 32,
+                      ),
+                      child: Row(
+                        children: [
+                          Expanded(
+                            child: SecondaryButton(
+                              label: "Show QR code",
+                              onPressed: () {
+                                // TODO: address utils
+                                final String value =
+                                    AddressUtils.encodeQRSeedData(words);
+                                Navigator.of(context).pushNamed(
+                                  QRCodeDesktopPopupContent.routeName,
+                                  arguments: value,
+                                );
+                              },
+                            ),
+                          ),
+                          const SizedBox(
+                            width: 16,
+                          ),
+                          Expanded(
+                            child: PrimaryButton(
+                              label: "Copy",
+                              onPressed: () async {
+                                await clipboardInterface.setData(
+                                  ClipboardData(text: words.join(" ")),
+                                );
+                                if (context.mounted) {
+                                  unawaited(
+                                    showFloatingFlushBar(
+                                      type: FlushBarType.info,
+                                      message: "Copied to clipboard",
+                                      iconAsset: Assets.svg.copy,
+                                      context: context,
+                                    ),
+                                  );
+                                }
+                              },
+                            ),
+                          ),
+                        ],
+                      ),
+                    ),
+                  ],
                 ),
-              ],
-            ),
-          ),
           const SizedBox(
             height: 32,
           ),
diff --git a/lib/route_generator.dart b/lib/route_generator.dart
index 26e24653c..3afd3e5dc 100644
--- a/lib/route_generator.dart
+++ b/lib/route_generator.dart
@@ -1403,12 +1403,33 @@ class RouteGenerator {
         return _routeError("${settings.name} invalid args: ${args.toString()}");
 
       case WalletBackupView.routeName:
-        if (args is Tuple2<String, List<String>>) {
+        if (args is ({String walletId, List<String> mnemonic})) {
           return getRoute(
             shouldUseMaterialRoute: useMaterialPageRoute,
             builder: (_) => WalletBackupView(
-              walletId: args.item1,
-              mnemonic: args.item2,
+              walletId: args.walletId,
+              mnemonic: args.mnemonic,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        } else if (args is ({
+          String walletId,
+          List<String> mnemonic,
+          ({
+            String myName,
+            String config,
+            String keys,
+            ({String config, String keys})? prevGen,
+          })? frostWalletData,
+        })) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => WalletBackupView(
+              walletId: args.walletId,
+              mnemonic: args.mnemonic,
+              frostWalletData: args.frostWalletData,
             ),
             settings: RouteSettings(
               name: settings.name,
@@ -2313,10 +2334,14 @@ class RouteGenerator {
             settings: RouteSettings(name: settings.name));
 
       case WalletKeysDesktopPopup.routeName:
-        if (args is List<String>) {
+        if (args is ({
+          List<String> mnemonic,
+          ({String keys, String config})? frostData
+        })) {
           return FadePageRoute(
             WalletKeysDesktopPopup(
-              words: args,
+              words: args.mnemonic,
+              frostData: args.frostData,
             ),
             RouteSettings(
               name: settings.name,
diff --git a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
index 851c41eed..2a50f20b6 100644
--- a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
+++ b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
@@ -925,7 +925,7 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
     );
   }
 
-  Future<String?> _getSerializedKeysPrevGen() async =>
+  Future<String?> getSerializedKeysPrevGen() async =>
       await secureStorageInterface.read(
         key: "{$walletId}_serializedFROSTKeysPrevGen",
       );
@@ -935,7 +935,7 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
         key: "{$walletId}_multisigConfig",
       );
 
-  Future<String?> _multisigConfigPrevGen() async =>
+  Future<String?> getMultisigConfigPrevGen() async =>
       await secureStorageInterface.read(
         key: "{$walletId}_multisigConfigPrevGen",
       );

From 73276ba676d3a6edee43db6924632b78bdc66220 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Fri, 23 Feb 2024 17:46:34 -0600
Subject: [PATCH 23/57] update frost wallet for electrum_adapter functionality

pulled from electrumx_interface, might consider using those methods instead
---
 .../wallet/impl/bitcoin_frost_wallet.dart     | 60 +++++++++++++++++++
 1 file changed, 60 insertions(+)

diff --git a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
index 2a50f20b6..097769260 100644
--- a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
+++ b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
@@ -1,6 +1,8 @@
 import 'dart:async';
 import 'dart:ffi';
 
+import 'package:electrum_adapter/electrum_adapter.dart' as electrum_adapter;
+import 'package:electrum_adapter/electrum_adapter.dart';
 import 'package:flutter/foundation.dart';
 import 'package:frostdart/frostdart.dart' as frost;
 import 'package:frostdart/frostdart_bindings_generated.dart';
@@ -18,15 +20,19 @@ import 'package:stackwallet/models/paymint/fee_object_model.dart';
 import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
 import 'package:stackwallet/services/event_bus/global_event_bus.dart';
 import 'package:stackwallet/services/frost.dart';
+import 'package:stackwallet/services/tor_service.dart';
 import 'package:stackwallet/utilities/amount/amount.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
 import 'package:stackwallet/utilities/extensions/extensions.dart';
 import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/prefs.dart';
 import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin_frost.dart';
 import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
 import 'package:stackwallet/wallets/crypto_currency/intermediate/private_key_currency.dart';
 import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart';
 import 'package:stackwallet/wallets/models/tx_data.dart';
 import 'package:stackwallet/wallets/wallet/wallet.dart';
+import 'package:stream_channel/stream_channel.dart';
 
 class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
   BitcoinFrostWallet(CryptoCurrencyNetwork network)
@@ -38,6 +44,8 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
       .findFirstSync()!;
 
   late ElectrumXClient electrumXClient;
+  late StreamChannel electrumAdapterChannel;
+  late ElectrumClient electrumAdapterClient;
   late CachedElectrumXClient electrumXCachedClient;
 
   Future<void> initializeNewFrost({
@@ -1075,6 +1083,7 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
     );
   }
 
+  // TODO [prio=low]: Use ElectrumXInterface method.
   Future<void> _updateElectrumX() async {
     final failovers = nodeService
         .failoverNodesFor(coin: cryptoCurrency.coin)
@@ -1088,16 +1097,67 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
         .toList();
 
     final newNode = await _getCurrentElectrumXNode();
+    try {
+      await electrumXClient.electrumAdapterClient?.close();
+    } catch (e, s) {
+      if (e.toString().contains("initialized")) {
+        // Ignore.  This should happen every first time the wallet is opened.
+      } else {
+        Logging.instance
+            .log("Error closing electrumXClient: $e", level: LogLevel.Error);
+      }
+    }
     electrumXClient = ElectrumXClient.from(
       node: newNode,
       prefs: prefs,
       failovers: failovers,
+      coin: cryptoCurrency.coin,
     );
+    electrumAdapterChannel = await electrum_adapter.connect(
+      newNode.address,
+      port: newNode.port,
+      acceptUnverified: true,
+      useSSL: newNode.useSSL,
+      proxyInfo: Prefs.instance.useTor
+          ? TorService.sharedInstance.getProxyInfo()
+          : null,
+    );
+    if (electrumXClient.coin == Coin.firo ||
+        electrumXClient.coin == Coin.firoTestNet) {
+      electrumAdapterClient = FiroElectrumClient(
+          electrumAdapterChannel,
+          newNode.address,
+          newNode.port,
+          newNode.useSSL,
+          Prefs.instance.useTor
+              ? TorService.sharedInstance.getProxyInfo()
+              : null);
+    } else {
+      electrumAdapterClient = ElectrumClient(
+          electrumAdapterChannel,
+          newNode.address,
+          newNode.port,
+          newNode.useSSL,
+          Prefs.instance.useTor
+              ? TorService.sharedInstance.getProxyInfo()
+              : null);
+    }
     electrumXCachedClient = CachedElectrumXClient.from(
       electrumXClient: electrumXClient,
+      electrumAdapterClient: electrumAdapterClient,
+      electrumAdapterUpdateCallback: updateClient,
     );
   }
 
+  // TODO [prio=low]: Use ElectrumXInterface method.
+  Future<ElectrumClient> updateClient() async {
+    Logging.instance.log(
+        "Updating electrum node and ElectrumAdapterClient from Frost wallet.",
+        level: LogLevel.Info);
+    await updateNode();
+    return electrumAdapterClient;
+  }
+
   bool _duplicateTxCheck(
       List<Map<String, dynamic>> allTransactions, String txid) {
     for (int i = 0; i < allTransactions.length; i++) {

From bbfb152bd741cd7a16bb24319ad517df9ea43619 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Fri, 23 Feb 2024 17:48:45 -0600
Subject: [PATCH 24/57] add bitcoin frost cases to validation switch

i'd like to do this more elegantly and just use each wallet impl's validateAddress

but this will do for now
---
 lib/utilities/address_utils.dart | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/lib/utilities/address_utils.dart b/lib/utilities/address_utils.dart
index 0e766d28e..563ca69fd 100644
--- a/lib/utilities/address_utils.dart
+++ b/lib/utilities/address_utils.dart
@@ -14,10 +14,9 @@ import 'package:bitcoindart/bitcoindart.dart';
 import 'package:crypto/crypto.dart';
 import 'package:stackwallet/utilities/enums/coin_enum.dart';
 import 'package:stackwallet/utilities/logger.dart';
-import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin.dart';
-import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
-
 import 'package:stackwallet/wallets/crypto_currency/coins/banano.dart';
+import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin.dart';
+import 'package:stackwallet/wallets/crypto_currency/coins/bitcoin_frost.dart';
 import 'package:stackwallet/wallets/crypto_currency/coins/bitcoincash.dart';
 import 'package:stackwallet/wallets/crypto_currency/coins/dogecoin.dart';
 import 'package:stackwallet/wallets/crypto_currency/coins/ecash.dart';
@@ -32,6 +31,7 @@ import 'package:stackwallet/wallets/crypto_currency/coins/particl.dart';
 import 'package:stackwallet/wallets/crypto_currency/coins/stellar.dart';
 import 'package:stackwallet/wallets/crypto_currency/coins/tezos.dart';
 import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart';
+import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
 
 class AddressUtils {
   static String condenseAddress(String address) {
@@ -72,6 +72,9 @@ class AddressUtils {
     switch (coin) {
       case Coin.bitcoin:
         return Bitcoin(CryptoCurrencyNetwork.main).validateAddress(address);
+      case Coin.bitcoinFrost:
+        return BitcoinFrost(CryptoCurrencyNetwork.main)
+            .validateAddress(address);
       case Coin.litecoin:
         return Litecoin(CryptoCurrencyNetwork.main).validateAddress(address);
       case Coin.bitcoincash:
@@ -104,6 +107,9 @@ class AddressUtils {
         return Tezos(CryptoCurrencyNetwork.main).validateAddress(address);
       case Coin.bitcoinTestNet:
         return Bitcoin(CryptoCurrencyNetwork.test).validateAddress(address);
+      case Coin.bitcoinFrostTestNet:
+        return BitcoinFrost(CryptoCurrencyNetwork.test)
+            .validateAddress(address);
       case Coin.litecoinTestNet:
         return Litecoin(CryptoCurrencyNetwork.test).validateAddress(address);
       case Coin.bitcoincashTestnet:

From 26b4b4b888e2544f6b99c7f49d2825b136edfdc4 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Mon, 4 Mar 2024 16:33:26 -0600
Subject: [PATCH 25/57] flutter_libepiccash: make sure to cd to build dir after
 building openssl

---
 crypto_plugins/flutter_libepiccash | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/crypto_plugins/flutter_libepiccash b/crypto_plugins/flutter_libepiccash
index cef5d3aa8..eea3d7674 160000
--- a/crypto_plugins/flutter_libepiccash
+++ b/crypto_plugins/flutter_libepiccash
@@ -1 +1 @@
-Subproject commit cef5d3aa8c74c8dc9a466f803c964b243ad653a3
+Subproject commit eea3d76740f7b036451850c937c3c013e5724294

From 445fc832a3ab6fda088f0ed7dc69661077b2a305 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Wed, 6 Mar 2024 10:16:51 -0600
Subject: [PATCH 26/57] center "import sign config" button

---
 .../wallet_view/sub_widgets/my_wallet.dart    | 28 +++++++++++--------
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/my_wallet.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/my_wallet.dart
index 01ff6801f..5b0cac5f7 100644
--- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/my_wallet.dart
+++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/my_wallet.dart
@@ -76,19 +76,23 @@ class _MyWalletState extends ConsumerState<MyWallet> {
                       ? Column(
                           children: [
                             Row(
-                              mainAxisAlignment: MainAxisAlignment.end,
+                              mainAxisAlignment: MainAxisAlignment.center,
                               children: [
-                                SecondaryButton(
-                                  width: 200,
-                                  buttonHeight: ButtonHeight.l,
-                                  label: "Import sign config",
-                                  onPressed: () {
-                                    Navigator.of(context).pushNamed(
-                                      FrostImportSignConfigView.routeName,
-                                      arguments: widget.walletId,
-                                    );
-                                  },
-                                ),
+                                Padding(
+                                  padding:
+                                      const EdgeInsets.fromLTRB(0, 20, 0, 0),
+                                  child: SecondaryButton(
+                                    width: 200,
+                                    buttonHeight: ButtonHeight.l,
+                                    label: "Import sign config",
+                                    onPressed: () {
+                                      Navigator.of(context).pushNamed(
+                                        FrostImportSignConfigView.routeName,
+                                        arguments: widget.walletId,
+                                      );
+                                    },
+                                  ),
+                                )
                               ],
                             ),
                             FrostSendView(

From 5d1615b72ef363514f99329316cf24a1811d456b Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Wed, 6 Mar 2024 10:55:15 -0600
Subject: [PATCH 27/57] fix keys popup, add copy buttons, and add basic style

and import cleanup
---
 .../wallet_backup_view.dart                   |  3 +-
 .../unlock_wallet_keys_desktop.dart           |  6 +-
 .../wallet_keys_desktop_popup.dart            | 62 ++++++++++++++++---
 3 files changed, 57 insertions(+), 14 deletions(-)

diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_backup_views/wallet_backup_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_backup_views/wallet_backup_view.dart
index 5b1548514..fee8781ff 100644
--- a/lib/pages/settings_views/wallet_settings_view/wallet_backup_views/wallet_backup_view.dart
+++ b/lib/pages/settings_views/wallet_settings_view/wallet_backup_views/wallet_backup_view.dart
@@ -17,6 +17,7 @@ import 'package:flutter_svg/svg.dart';
 import 'package:qr_flutter/qr_flutter.dart';
 import 'package:stackwallet/notifications/show_flush_bar.dart';
 import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart';
+import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
 import 'package:stackwallet/themes/stack_colors.dart';
 import 'package:stackwallet/utilities/address_utils.dart';
 import 'package:stackwallet/utilities/assets.dart';
@@ -32,8 +33,6 @@ import 'package:stackwallet/widgets/detail_item.dart';
 import 'package:stackwallet/widgets/rounded_white_container.dart';
 import 'package:stackwallet/widgets/stack_dialog.dart';
 
-import '../../../wallet_view/transaction_views/transaction_details_view.dart';
-
 class WalletBackupView extends ConsumerWidget {
   const WalletBackupView({
     Key? key,
diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/unlock_wallet_keys_desktop.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/unlock_wallet_keys_desktop.dart
index c621a4030..163052ec0 100644
--- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/unlock_wallet_keys_desktop.dart
+++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/unlock_wallet_keys_desktop.dart
@@ -89,9 +89,11 @@ class _UnlockWalletKeysDesktopState
       if (wallet is! MnemonicInterface) {
         if (wallet is BitcoinFrostWallet) {
           frostData = (
-            keys: (await wallet.getMultisigConfig())!,
+            keys: (await wallet.getSerializedKeys())!,
             config: (await wallet.getMultisigConfig())!,
           );
+          print(1111111);
+          print(frostData);
         } else {
           throw Exception("FIXME ~= see todo in code");
         }
@@ -325,7 +327,7 @@ class _UnlockWalletKeysDesktopState
                               if (wallet is! MnemonicInterface) {
                                 if (wallet is BitcoinFrostWallet) {
                                   frostData = (
-                                    keys: (await wallet.getMultisigConfig())!,
+                                    keys: (await wallet.getSerializedKeys())!,
                                     config: (await wallet.getMultisigConfig())!,
                                   );
                                 } else {
diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_keys_desktop_popup.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_keys_desktop_popup.dart
index 60f0d2436..606ae21f4 100644
--- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_keys_desktop_popup.dart
+++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_keys_desktop_popup.dart
@@ -14,6 +14,7 @@ import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:stackwallet/notifications/show_flush_bar.dart';
 import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart';
+import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
 import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/qr_code_desktop_popup_content.dart';
 import 'package:stackwallet/themes/stack_colors.dart';
 import 'package:stackwallet/utilities/address_utils.dart';
@@ -24,6 +25,7 @@ import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
 import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
 import 'package:stackwallet/widgets/desktop/primary_button.dart';
 import 'package:stackwallet/widgets/desktop/secondary_button.dart';
+import 'package:stackwallet/widgets/rounded_white_container.dart';
 
 class WalletKeysDesktopPopup extends StatelessWidget {
   const WalletKeysDesktopPopup({
@@ -83,11 +85,31 @@ class WalletKeysDesktopPopup extends StatelessWidget {
                         padding: const EdgeInsets.symmetric(
                           horizontal: 32,
                         ),
-                        child: SelectableText(
-                          frostData!.keys,
-                          style:
-                              STextStyles.desktopTextExtraExtraSmall(context),
-                          textAlign: TextAlign.center,
+                        child: RoundedWhiteContainer(
+                          borderColor: Theme.of(context)
+                              .extension<StackColors>()!
+                              .textFieldDefaultBG,
+                          padding: const EdgeInsets.symmetric(
+                              horizontal: 12, vertical: 9),
+                          child: Row(
+                            children: [
+                              Flexible(
+                                child: SelectableText(
+                                  frostData!.keys,
+                                  style: STextStyles.desktopTextExtraExtraSmall(
+                                      context),
+                                  textAlign: TextAlign.center,
+                                ),
+                              ),
+                              const SizedBox(
+                                width: 10,
+                              ),
+                              IconCopyButton(
+                                data: frostData!.keys,
+                              )
+                              // TODO [prio=low: Add QR code button and dialog.
+                            ],
+                          ),
                         ),
                       ),
                     ),
@@ -106,11 +128,31 @@ class WalletKeysDesktopPopup extends StatelessWidget {
                         padding: const EdgeInsets.symmetric(
                           horizontal: 32,
                         ),
-                        child: SelectableText(
-                          frostData!.config,
-                          style:
-                              STextStyles.desktopTextExtraExtraSmall(context),
-                          textAlign: TextAlign.center,
+                        child: RoundedWhiteContainer(
+                          borderColor: Theme.of(context)
+                              .extension<StackColors>()!
+                              .textFieldDefaultBG,
+                          padding: const EdgeInsets.symmetric(
+                              horizontal: 12, vertical: 9),
+                          child: Row(
+                            children: [
+                              Flexible(
+                                child: SelectableText(
+                                  frostData!.config,
+                                  style: STextStyles.desktopTextExtraExtraSmall(
+                                      context),
+                                  textAlign: TextAlign.center,
+                                ),
+                              ),
+                              const SizedBox(
+                                width: 10,
+                              ),
+                              IconCopyButton(
+                                data: frostData!.config,
+                              )
+                              // TODO [prio=low: Add QR code button and dialog.
+                            ],
+                          ),
                         ),
                       ),
                     ),

From d59be57667067b34ce82c03ab79892229b8de55e Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Wed, 6 Mar 2024 11:17:19 -0600
Subject: [PATCH 28/57] update flutter_libepiccash build script

---
 crypto_plugins/flutter_libepiccash | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/crypto_plugins/flutter_libepiccash b/crypto_plugins/flutter_libepiccash
index eea3d7674..72b6ce405 160000
--- a/crypto_plugins/flutter_libepiccash
+++ b/crypto_plugins/flutter_libepiccash
@@ -1 +1 @@
-Subproject commit eea3d76740f7b036451850c937c3c013e5724294
+Subproject commit 72b6ce405a956f163ffb25d458de28a8458223f4

From f558703253116b4b13e775210bdec3629d23d356 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Wed, 6 Mar 2024 18:04:54 -0600
Subject: [PATCH 29/57] DesktopScaffold on desktop

---
 .../frost_ms/frost_ms_options_view.dart       | 52 ++++++++++++++-----
 1 file changed, 38 insertions(+), 14 deletions(-)

diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/frost_ms_options_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/frost_ms_options_view.dart
index 169a96b64..7fc7236a4 100644
--- a/lib/pages/settings_views/wallet_settings_view/frost_ms/frost_ms_options_view.dart
+++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/frost_ms_options_view.dart
@@ -13,14 +13,19 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/frost_participants_view.dart';
 import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/begin_reshare_config_view.dart';
 import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1b/import_reshare_config_view.dart';
+import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
 import 'package:stackwallet/providers/db/main_db_provider.dart';
 import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
 import 'package:stackwallet/themes/stack_colors.dart';
 import 'package:stackwallet/utilities/constants.dart';
 import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
 import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart';
 import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
 import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
 import 'package:stackwallet/widgets/rounded_white_container.dart';
 
 class FrostMSWalletOptionsView extends ConsumerWidget {
@@ -35,21 +40,40 @@ class FrostMSWalletOptionsView extends ConsumerWidget {
 
   @override
   Widget build(BuildContext context, WidgetRef ref) {
-    return Background(
-      child: Scaffold(
-        backgroundColor: Theme.of(context).extension<StackColors>()!.background,
-        appBar: AppBar(
-          leading: AppBarBackButton(
-            onPressed: () {
-              Navigator.of(context).pop();
-            },
-          ),
-          title: Text(
-            "Multisig settings",
-            style: STextStyles.navBarTitle(context),
-          ),
+    return ConditionalParent(
+      condition: Util.isDesktop,
+      builder: (child) => DesktopScaffold(
+        background: Theme.of(context).extension<StackColors>()!.background,
+        appBar: const DesktopAppBar(
+          isCompactHeight: false,
+          leading: AppBarBackButton(),
+          trailing: ExitToMyStackButton(),
         ),
-        body: Padding(
+        body: SizedBox(
+          width: 480,
+          child: child,
+        ),
+      ),
+      child: ConditionalParent(
+        condition: !Util.isDesktop,
+        builder: (child) => Background(
+          child: Scaffold(
+              backgroundColor:
+                  Theme.of(context).extension<StackColors>()!.background,
+              appBar: AppBar(
+                leading: AppBarBackButton(
+                  onPressed: () {
+                    Navigator.of(context).pop();
+                  },
+                ),
+                title: Text(
+                  "FROST Multisig options",
+                  style: STextStyles.navBarTitle(context),
+                ),
+              ),
+              body: child),
+        ),
+        child: Padding(
           padding: const EdgeInsets.only(
             top: 12,
             left: 16,

From 809cbe6195e4d944563745d2f87381c6a98f41b8 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Wed, 6 Mar 2024 18:09:38 -0600
Subject: [PATCH 30/57] FROST Multisig settings buttons mobile and desktop

---
 .../wallet_settings_view.dart                 | 16 +++++
 .../sub_widgets/wallet_options_button.dart    | 60 ++++++++++++++++++-
 2 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart
index e0b870326..04de48cb4 100644
--- a/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart
+++ b/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart
@@ -22,6 +22,7 @@ import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart';
 import 'package:stackwallet/pages/settings_views/global_settings_view/advanced_views/debug_view.dart';
 import 'package:stackwallet/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_preferences_view.dart';
 import 'package:stackwallet/pages/settings_views/sub_widgets/settings_list_button.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/frost_ms_options_view.dart';
 import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_backup_views/wallet_backup_view.dart';
 import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart';
 import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/change_representative_view.dart';
@@ -194,6 +195,21 @@ class _WalletSettingsViewState extends ConsumerState<WalletSettingsView> {
                             padding: const EdgeInsets.all(4),
                             child: Column(
                               children: [
+                                if (coin == Coin.bitcoinFrost ||
+                                    coin == Coin.bitcoinFrostTestNet)
+                                  if (coin == Coin.bitcoinFrost ||
+                                      coin == Coin.bitcoinFrostTestNet)
+                                    SettingsListButton(
+                                      iconAssetName: Assets.svg.addressBook2,
+                                      iconSize: 16,
+                                      title: "FROST Multisig settings",
+                                      onPressed: () {
+                                        Navigator.of(context).pushNamed(
+                                          FrostMSWalletOptionsView.routeName,
+                                          arguments: walletId,
+                                        );
+                                      },
+                                    ),
                                 SettingsListButton(
                                   iconAssetName: Assets.svg.addressBook,
                                   iconSize: 16,
diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart
index f495475db..c27b7855d 100644
--- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart
+++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart
@@ -14,6 +14,7 @@ import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:flutter_svg/svg.dart';
+import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/frost_ms_options_view.dart';
 import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/change_representative_view.dart';
 import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/xpub_view.dart';
 import 'package:stackwallet/pages_desktop_specific/addresses/desktop_wallet_addresses_view.dart';
@@ -34,7 +35,8 @@ enum _WalletOptions {
   changeRepresentative,
   showXpub,
   lelantusCoins,
-  sparkCoins;
+  sparkCoins,
+  frostOptions;
 
   String get prettyName {
     switch (this) {
@@ -50,6 +52,8 @@ enum _WalletOptions {
         return "Lelantus Coins";
       case _WalletOptions.sparkCoins:
         return "Spark Coins";
+      case _WalletOptions.frostOptions:
+        return "FROST settings";
     }
   }
 }
@@ -96,6 +100,9 @@ class WalletOptionsButton extends StatelessWidget {
               onFiroShowSparkCoins: () async {
                 Navigator.of(context).pop(_WalletOptions.sparkCoins);
               },
+              onFrostMSWalletOptionsPressed: () async {
+                Navigator.of(context).pop(_WalletOptions.frostOptions);
+              },
               walletId: walletId,
             );
           },
@@ -207,6 +214,15 @@ class WalletOptionsButton extends StatelessWidget {
                 ),
               );
               break;
+
+            case _WalletOptions.frostOptions:
+              unawaited(
+                Navigator.of(context).pushNamed(
+                  FrostMSWalletOptionsView.routeName,
+                  arguments: walletId,
+                ),
+              );
+              break;
           }
         }
       },
@@ -241,6 +257,7 @@ class WalletOptionsPopupMenu extends ConsumerWidget {
     required this.onChangeRepPressed,
     required this.onFiroShowLelantusCoins,
     required this.onFiroShowSparkCoins,
+    required this.onFrostMSWalletOptionsPressed,
     required this.walletId,
   }) : super(key: key);
 
@@ -250,6 +267,7 @@ class WalletOptionsPopupMenu extends ConsumerWidget {
   final VoidCallback onChangeRepPressed;
   final VoidCallback onFiroShowLelantusCoins;
   final VoidCallback onFiroShowSparkCoins;
+  final VoidCallback onFrostMSWalletOptionsPressed;
   final String walletId;
 
   @override
@@ -265,6 +283,9 @@ class WalletOptionsPopupMenu extends ConsumerWidget {
 
     final bool canChangeRep = coin == Coin.nano || coin == Coin.banano;
 
+    final bool isFrost =
+        coin == Coin.bitcoinFrost || coin == Coin.bitcoinFrostTestNet;
+
     return Stack(
       children: [
         Positioned(
@@ -429,6 +450,43 @@ class WalletOptionsPopupMenu extends ConsumerWidget {
                         ),
                       ),
                     ),
+                  if (isFrost)
+                    const SizedBox(
+                      height: 8,
+                    ),
+                  if (isFrost)
+                    TransparentButton(
+                      onPressed: onFrostMSWalletOptionsPressed,
+                      child: Padding(
+                        padding: const EdgeInsets.all(8),
+                        child: Row(
+                          mainAxisAlignment: MainAxisAlignment.start,
+                          children: [
+                            SvgPicture.asset(
+                              Assets.svg.addressBookDesktop,
+                              width: 20,
+                              height: 20,
+                              color: Theme.of(context)
+                                  .extension<StackColors>()!
+                                  .textFieldActiveSearchIconLeft,
+                            ),
+                            const SizedBox(width: 14),
+                            Expanded(
+                              child: Text(
+                                _WalletOptions.frostOptions.prettyName,
+                                style: STextStyles.desktopTextExtraExtraSmall(
+                                        context)
+                                    .copyWith(
+                                  color: Theme.of(context)
+                                      .extension<StackColors>()!
+                                      .textDark,
+                                ),
+                              ),
+                            ),
+                          ],
+                        ),
+                      ),
+                    ),
                   if (xpubEnabled)
                     const SizedBox(
                       height: 8,

From bfdcfcec1aeb734d26f5396d22c89f764978186a Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Wed, 6 Mar 2024 18:13:39 -0600
Subject: [PATCH 31/57] resolve "can't add to fixed length list" exception

---
 .../involved/step_1a/complete_reshare_config_view.dart      | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/complete_reshare_config_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/complete_reshare_config_view.dart
index 0e2e1e111..74cfaee17 100644
--- a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/complete_reshare_config_view.dart
+++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_1a/complete_reshare_config_view.dart
@@ -93,14 +93,14 @@ class _CompleteReshareConfigViewState
           ),
         );
       } else {
-        final salts = frostInfo.knownSalts;
-        salts.add(salt);
+        final salts = frostInfo.knownSalts; // Fixed length list.
+        final newSalts = List<String>.from(salts)..add(salt);
         final mainDB = ref.read(mainDBProvider);
         await mainDB.isar.writeTxn(() async {
           final info = frostInfo;
           await mainDB.isar.frostWalletInfo.delete(info.id);
           await mainDB.isar.frostWalletInfo.put(
-            info.copyWith(knownSalts: salts),
+            info.copyWith(knownSalts: newSalts),
           );
         });
       }

From 88afa95b52801d05a7b568f680ee1f61928d8844 Mon Sep 17 00:00:00 2001
From: likho <likhojiba@gmail.com>
Date: Mon, 11 Mar 2024 14:32:40 +0200
Subject: [PATCH 32/57] Update to latest epic

---
 crypto_plugins/flutter_libepiccash | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/crypto_plugins/flutter_libepiccash b/crypto_plugins/flutter_libepiccash
index cef5d3aa8..aab6a4676 160000
--- a/crypto_plugins/flutter_libepiccash
+++ b/crypto_plugins/flutter_libepiccash
@@ -1 +1 @@
-Subproject commit cef5d3aa8c74c8dc9a466f803c964b243ad653a3
+Subproject commit aab6a4676188901fbe158d8f1feeb1fc0ea247f8

From 09bbdb536847011a7cf0ef7f041adb60808e8e31 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Mon, 11 Mar 2024 11:20:41 -0500
Subject: [PATCH 33/57] add missing frost routes

---
 lib/route_generator.dart | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/lib/route_generator.dart b/lib/route_generator.dart
index 3afd3e5dc..6f298a7c0 100644
--- a/lib/route_generator.dart
+++ b/lib/route_generator.dart
@@ -83,6 +83,8 @@ import 'package:stackwallet/pages/receive_view/addresses/wallet_addresses_view.d
 import 'package:stackwallet/pages/receive_view/generate_receiving_uri_qr_code_view.dart';
 import 'package:stackwallet/pages/receive_view/receive_view.dart';
 import 'package:stackwallet/pages/send_view/confirm_transaction_view.dart';
+import 'package:stackwallet/pages/send_view/frost_ms/frost_attempt_sign_config_view.dart';
+import 'package:stackwallet/pages/send_view/frost_ms/frost_create_sign_config_view.dart';
 import 'package:stackwallet/pages/send_view/frost_ms/frost_send_view.dart';
 import 'package:stackwallet/pages/send_view/send_view.dart';
 import 'package:stackwallet/pages/send_view/token_send_view.dart';
@@ -775,6 +777,34 @@ class RouteGenerator {
         }
         return _routeError("${settings.name} invalid args: ${args.toString()}");
 
+      case FrostCreateSignConfigView.routeName:
+        if (args is String) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => FrostCreateSignConfigView(
+              walletId: args,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+      case FrostAttemptSignConfigView.routeName:
+        if (args is String) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => FrostAttemptSignConfigView(
+              walletId: args,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
       // case MonkeyLoadedView.routeName:
       //   if (args is Tuple2<String, ChangeNotifierProvider<Manager>>) {
       //     return getRoute(

From 10233550b187c7a3a879f4c09d2358551c4c8ce1 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Mon, 11 Mar 2024 11:21:19 -0500
Subject: [PATCH 34/57] fix issue with modifying fixed-length list

---
 .../send_view/frost_ms/frost_attempt_sign_config_view.dart      | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/pages/send_view/frost_ms/frost_attempt_sign_config_view.dart b/lib/pages/send_view/frost_ms/frost_attempt_sign_config_view.dart
index 7cdf4a69b..149eb61d3 100644
--- a/lib/pages/send_view/frost_ms/frost_attempt_sign_config_view.dart
+++ b/lib/pages/send_view/frost_ms/frost_attempt_sign_config_view.dart
@@ -78,7 +78,7 @@ class _FrostAttemptSignConfigViewState
 
     myName = frostInfo.myName;
     threshold = frostInfo.threshold;
-    participantsWithoutMe = frostInfo.participants;
+    participantsWithoutMe = List.from(frostInfo.participants); // Copy so it isn't fixed-length.
     myIndex = participantsWithoutMe.indexOf(frostInfo.myName);
     myPreprocess = ref.read(pFrostAttemptSignData.state).state!.preprocess;
 

From 181ec5e5398d94f60b32397d53f0a899171e4799 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Mon, 11 Mar 2024 23:05:55 -0500
Subject: [PATCH 35/57] Revert "wrap send view content in padding"

This reverts commit 2aa3bebf78280f56650c3f0f7be5e7bf7a8964cf.
---
 .../send_view/frost_ms/frost_send_view.dart   | 384 +++++++++---------
 1 file changed, 188 insertions(+), 196 deletions(-)

diff --git a/lib/pages/send_view/frost_ms/frost_send_view.dart b/lib/pages/send_view/frost_ms/frost_send_view.dart
index 95d45cb95..1865556b7 100644
--- a/lib/pages/send_view/frost_ms/frost_send_view.dart
+++ b/lib/pages/send_view/frost_ms/frost_send_view.dart
@@ -391,215 +391,207 @@ class _FrostSendViewState extends ConsumerState<FrostSendView> {
           const SizedBox(
             height: 16,
           ),
-          Padding(
-            padding: const EdgeInsets.symmetric(
-              horizontal: 20,
+          Row(
+            mainAxisAlignment: MainAxisAlignment.spaceBetween,
+            children: [
+              Text(
+                "Recipients",
+                style: STextStyles.smallMed12(context),
+                textAlign: TextAlign.left,
+              ),
+              CustomTextButton(
+                text: "Add",
+                onTap: () {
+                  // used for tracking recipient forms
+                  _greatestWidgetIndex++;
+                  recipientWidgetIndexes.add(_greatestWidgetIndex);
+                  setState(() {});
+                },
+              ),
+            ],
+          ),
+          const SizedBox(
+            height: 8,
+          ),
+          Column(
+            children: [
+              for (int i = 0; i < recipientWidgetIndexes.length; i++)
+                ConditionalParent(
+                  condition: recipientWidgetIndexes.length > 1,
+                  builder: (child) => Padding(
+                    padding: const EdgeInsets.only(top: 8),
+                    child: child,
+                  ),
+                  child: Recipient(
+                    key: Key(
+                      "recipientKey_${recipientWidgetIndexes[i]}",
+                    ),
+                    index: recipientWidgetIndexes[i],
+                    coin: coin,
+                    onChanged: () {
+                      _validateRecipientFormStates();
+                    },
+                    remove: i == 0 && recipientWidgetIndexes.length == 1
+                        ? null
+                        : () {
+                            recipientWidgetIndexes.removeAt(i);
+                            setState(() {});
+                          },
+                  ),
+                ),
+            ],
+          ),
+          if (showCoinControl)
+            const SizedBox(
+              height: 8,
             ),
-            child: Column(children: [
-              Row(
+          if (showCoinControl)
+            RoundedWhiteContainer(
+              child: Row(
                 mainAxisAlignment: MainAxisAlignment.spaceBetween,
                 children: [
                   Text(
-                    "Recipients",
-                    style: STextStyles.smallMed12(context),
-                    textAlign: TextAlign.left,
+                    "Coin control",
+                    style: STextStyles.w500_14(context).copyWith(
+                      color: Theme.of(context)
+                          .extension<StackColors>()!
+                          .textSubtitle1,
+                    ),
                   ),
                   CustomTextButton(
-                    text: "Add",
-                    onTap: () {
-                      // used for tracking recipient forms
-                      _greatestWidgetIndex++;
-                      recipientWidgetIndexes.add(_greatestWidgetIndex);
-                      setState(() {});
+                    text: selectedUTXOs.isEmpty
+                        ? "Select coins"
+                        : "Selected coins (${selectedUTXOs.length})",
+                    onTap: () async {
+                      if (FocusScope.of(context).hasFocus) {
+                        FocusScope.of(context).unfocus();
+                        await Future<void>.delayed(
+                          const Duration(milliseconds: 100),
+                        );
+                      }
+
+                      if (mounted) {
+                        // finally spendable = ref
+                        //     .read(walletsChangeNotifierProvider)
+                        //     .getManager(widget.walletId)
+                        //     .balance
+                        //     .spendable;
+
+                        // TODO: [prio=high] make sure this coincontrol works correctly
+
+                        Amount? amount;
+
+                        final result = await Navigator.of(context).pushNamed(
+                          CoinControlView.routeName,
+                          arguments: Tuple4(
+                            walletId,
+                            CoinControlViewType.use,
+                            amount,
+                            selectedUTXOs,
+                          ),
+                        );
+
+                        if (result is Set<UTXO>) {
+                          setState(() {
+                            selectedUTXOs = result;
+                          });
+                        }
+                      }
                     },
                   ),
                 ],
               ),
-              const SizedBox(
-                height: 8,
-              ),
-              Column(
-                children: [
-                  for (int i = 0; i < recipientWidgetIndexes.length; i++)
-                    ConditionalParent(
-                      condition: recipientWidgetIndexes.length > 1,
-                      builder: (child) => Padding(
-                        padding: const EdgeInsets.only(top: 8),
-                        child: child,
-                      ),
-                      child: Recipient(
-                        key: Key(
-                          "recipientKey_${recipientWidgetIndexes[i]}",
-                        ),
-                        index: recipientWidgetIndexes[i],
-                        coin: coin,
-                        onChanged: () {
-                          _validateRecipientFormStates();
-                        },
-                        remove: i == 0 && recipientWidgetIndexes.length == 1
-                            ? null
-                            : () {
-                                recipientWidgetIndexes.removeAt(i);
-                                setState(() {});
-                              },
-                      ),
-                    ),
-                ],
-              ),
-              if (showCoinControl)
-                const SizedBox(
-                  height: 8,
-                ),
-              if (showCoinControl)
-                RoundedWhiteContainer(
-                  child: Row(
-                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                    children: [
-                      Text(
-                        "Coin control",
-                        style: STextStyles.w500_14(context).copyWith(
-                          color: Theme.of(context)
-                              .extension<StackColors>()!
-                              .textSubtitle1,
-                        ),
-                      ),
-                      CustomTextButton(
-                        text: selectedUTXOs.isEmpty
-                            ? "Select coins"
-                            : "Selected coins (${selectedUTXOs.length})",
-                        onTap: () async {
-                          if (FocusScope.of(context).hasFocus) {
-                            FocusScope.of(context).unfocus();
-                            await Future<void>.delayed(
-                              const Duration(milliseconds: 100),
-                            );
-                          }
-
-                          if (mounted) {
-                            // finally spendable = ref
-                            //     .read(walletsChangeNotifierProvider)
-                            //     .getManager(widget.walletId)
-                            //     .balance
-                            //     .spendable;
-
-                            // TODO: [prio=high] make sure this coincontrol works correctly
-
-                            Amount? amount;
-
-                            final result =
-                                await Navigator.of(context).pushNamed(
-                              CoinControlView.routeName,
-                              arguments: Tuple4(
-                                walletId,
-                                CoinControlViewType.use,
-                                amount,
-                                selectedUTXOs,
+            ),
+          const SizedBox(
+            height: 12,
+          ),
+          Text(
+            "Note (optional)",
+            style: STextStyles.smallMed12(context),
+            textAlign: TextAlign.left,
+          ),
+          const SizedBox(
+            height: 8,
+          ),
+          ClipRRect(
+            borderRadius: BorderRadius.circular(
+              Constants.size.circularBorderRadius,
+            ),
+            child: TextField(
+              autocorrect: Util.isDesktop ? false : true,
+              enableSuggestions: Util.isDesktop ? false : true,
+              controller: noteController,
+              focusNode: _noteFocusNode,
+              style: STextStyles.field(context),
+              onChanged: (_) => setState(() {}),
+              decoration: standardInputDecoration(
+                "Type something...",
+                _noteFocusNode,
+                context,
+              ).copyWith(
+                suffixIcon: noteController.text.isNotEmpty
+                    ? Padding(
+                        padding: const EdgeInsets.only(right: 0),
+                        child: UnconstrainedBox(
+                          child: Row(
+                            children: [
+                              TextFieldIconButton(
+                                child: const XIcon(),
+                                onTap: () async {
+                                  setState(() {
+                                    noteController.text = "";
+                                  });
+                                },
                               ),
-                            );
-
-                            if (result is Set<UTXO>) {
-                              setState(() {
-                                selectedUTXOs = result;
-                              });
-                            }
-                          }
-                        },
-                      ),
-                    ],
-                  ),
-                ),
-              const SizedBox(
-                height: 12,
-              ),
-              Text(
-                "Note (optional)",
-                style: STextStyles.smallMed12(context),
-                textAlign: TextAlign.left,
-              ),
-              const SizedBox(
-                height: 8,
-              ),
-              ClipRRect(
-                borderRadius: BorderRadius.circular(
-                  Constants.size.circularBorderRadius,
-                ),
-                child: TextField(
-                  autocorrect: Util.isDesktop ? false : true,
-                  enableSuggestions: Util.isDesktop ? false : true,
-                  controller: noteController,
-                  focusNode: _noteFocusNode,
-                  style: STextStyles.field(context),
-                  onChanged: (_) => setState(() {}),
-                  decoration: standardInputDecoration(
-                    "Type something...",
-                    _noteFocusNode,
-                    context,
-                  ).copyWith(
-                    suffixIcon: noteController.text.isNotEmpty
-                        ? Padding(
-                            padding: const EdgeInsets.only(right: 0),
-                            child: UnconstrainedBox(
-                              child: Row(
-                                children: [
-                                  TextFieldIconButton(
-                                    child: const XIcon(),
-                                    onTap: () async {
-                                      setState(() {
-                                        noteController.text = "";
-                                      });
-                                    },
-                                  ),
-                                ],
-                              ),
-                            ),
-                          )
-                        : null,
-                  ),
-                ),
-              ),
-              const SizedBox(
-                height: 12,
-              ),
-              Padding(
-                padding: const EdgeInsets.only(
-                  bottom: 12,
-                  top: 16,
-                ),
-                child: FeeSlider(
-                  coin: coin,
-                  onSatVByteChanged: (rate) {
-                    customFeeRate = rate;
-                  },
-                ),
-              ),
-              Util.isDesktop
-                  ? const SizedBox(
-                      height: 12,
-                    )
-                  : const Spacer(),
-              const SizedBox(
-                height: 12,
-              ),
-              TextButton(
-                onPressed: ref.watch(previewTxButtonStateProvider.state).state
-                    ? _createSignConfig
+                            ],
+                          ),
+                        ),
+                      )
                     : null,
-                style: ref.watch(previewTxButtonStateProvider.state).state
-                    ? Theme.of(context)
-                        .extension<StackColors>()!
-                        .getPrimaryEnabledButtonStyle(context)
-                    : Theme.of(context)
-                        .extension<StackColors>()!
-                        .getPrimaryDisabledButtonStyle(context),
-                child: Text(
-                  "Create config",
-                  style: STextStyles.button(context),
-                ),
               ),
-              const SizedBox(
-                height: 16,
-              ),
-            ]),
+            ),
+          ),
+          const SizedBox(
+            height: 12,
+          ),
+          Padding(
+            padding: const EdgeInsets.only(
+              bottom: 12,
+              top: 16,
+            ),
+            child: FeeSlider(
+              coin: coin,
+              onSatVByteChanged: (rate) {
+                customFeeRate = rate;
+              },
+            ),
+          ),
+          Util.isDesktop
+              ? const SizedBox(
+                  height: 12,
+                )
+              : const Spacer(),
+          const SizedBox(
+            height: 12,
+          ),
+          TextButton(
+            onPressed: ref.watch(previewTxButtonStateProvider.state).state
+                ? _createSignConfig
+                : null,
+            style: ref.watch(previewTxButtonStateProvider.state).state
+                ? Theme.of(context)
+                    .extension<StackColors>()!
+                    .getPrimaryEnabledButtonStyle(context)
+                : Theme.of(context)
+                    .extension<StackColors>()!
+                    .getPrimaryDisabledButtonStyle(context),
+            child: Text(
+              "Create config",
+              style: STextStyles.button(context),
+            ),
+          ),
+          const SizedBox(
+            height: 16,
           ),
         ],
       ),

From 0fe16638b04a8047f14caac94745bb565e6b5869 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Tue, 12 Mar 2024 06:45:26 -0500
Subject: [PATCH 36/57] pad desktop send view with ConditionalParent

---
 .../send_view/frost_ms/frost_send_view.dart   | 595 +++++++++---------
 1 file changed, 303 insertions(+), 292 deletions(-)

diff --git a/lib/pages/send_view/frost_ms/frost_send_view.dart b/lib/pages/send_view/frost_ms/frost_send_view.dart
index 1865556b7..5f04bb346 100644
--- a/lib/pages/send_view/frost_ms/frost_send_view.dart
+++ b/lib/pages/send_view/frost_ms/frost_send_view.dart
@@ -287,313 +287,324 @@ class _FrostSendViewState extends ConsumerState<FrostSendView> {
           ),
         ),
       ),
-      child: Column(
-        crossAxisAlignment: CrossAxisAlignment.stretch,
-        children: [
-          if (!Util.isDesktop)
-            Container(
-              decoration: BoxDecoration(
-                color: Theme.of(context).extension<StackColors>()!.popupBG,
-                borderRadius: BorderRadius.circular(
-                  Constants.size.circularBorderRadius,
-                ),
-              ),
-              child: Padding(
-                padding: const EdgeInsets.all(12.0),
-                child: Row(
-                  children: [
-                    SvgPicture.file(
-                      File(
-                        ref.watch(
-                          coinIconProvider(coin),
-                        ),
-                      ),
-                      width: 22,
-                      height: 22,
-                    ),
-                    const SizedBox(
-                      width: 6,
-                    ),
-                    Column(
-                      crossAxisAlignment: CrossAxisAlignment.start,
-                      children: [
-                        Text(
-                          ref.watch(pWalletName(walletId)),
-                          style: STextStyles.titleBold12(context)
-                              .copyWith(fontSize: 14),
-                          overflow: TextOverflow.ellipsis,
-                          maxLines: 1,
-                        ),
-                        // const SizedBox(
-                        //   height: 2,
-                        // ),
-                        Text(
-                          "Available balance",
-                          style:
-                              STextStyles.label(context).copyWith(fontSize: 10),
-                        ),
-                      ],
-                    ),
-                    Util.isDesktop
-                        ? const SizedBox(
-                            height: 24,
-                          )
-                        : const Spacer(),
-                    GestureDetector(
-                      onTap: () {
-                        // cryptoAmountController.text = ref
-                        //     .read(pAmountFormatter(coin))
-                        //     .format(
-                        //       _cachedBalance!,
-                        //       withUnitName: false,
-                        //     );
-                      },
-                      child: Container(
-                        color: Colors.transparent,
-                        child: Column(
-                          crossAxisAlignment: CrossAxisAlignment.end,
-                          children: [
-                            Text(
-                              ref.watch(pAmountFormatter(coin)).format(ref
-                                  .watch(pWalletBalance(walletId))
-                                  .spendable),
-                              style: STextStyles.titleBold12(context).copyWith(
-                                fontSize: 10,
-                              ),
-                              textAlign: TextAlign.right,
-                            ),
-                            // Text(
-                            //   "${(manager.balance.spendable.decimal * ref.watch(
-                            //             priceAnd24hChangeNotifierProvider.select(
-                            //               (value) => value.getPrice(coin).item1,
-                            //             ),
-                            //           )).toAmount(
-                            //         fractionDigits: 2,
-                            //       ).fiatString(
-                            //         locale: locale,
-                            //       )} ${ref.watch(
-                            //     prefsChangeNotifierProvider
-                            //         .select((value) => value.currency),
-                            //   )}",
-                            //   style: STextStyles.subtitle(context).copyWith(
-                            //     fontSize: 8,
-                            //   ),
-                            //   textAlign: TextAlign.right,
-                            // )
-                          ],
-                        ),
-                      ),
-                    )
-                  ],
-                ),
-              ),
-            ),
-          const SizedBox(
-            height: 16,
+      child: ConditionalParent(
+        condition: Util.isDesktop,
+        builder: (child) => Padding(
+          padding: const EdgeInsets.symmetric(
+            horizontal: 20,
+            vertical: 14,
           ),
-          Row(
-            mainAxisAlignment: MainAxisAlignment.spaceBetween,
-            children: [
-              Text(
-                "Recipients",
-                style: STextStyles.smallMed12(context),
-                textAlign: TextAlign.left,
-              ),
-              CustomTextButton(
-                text: "Add",
-                onTap: () {
-                  // used for tracking recipient forms
-                  _greatestWidgetIndex++;
-                  recipientWidgetIndexes.add(_greatestWidgetIndex);
-                  setState(() {});
-                },
-              ),
-            ],
-          ),
-          const SizedBox(
-            height: 8,
-          ),
-          Column(
-            children: [
-              for (int i = 0; i < recipientWidgetIndexes.length; i++)
-                ConditionalParent(
-                  condition: recipientWidgetIndexes.length > 1,
-                  builder: (child) => Padding(
-                    padding: const EdgeInsets.only(top: 8),
-                    child: child,
-                  ),
-                  child: Recipient(
-                    key: Key(
-                      "recipientKey_${recipientWidgetIndexes[i]}",
-                    ),
-                    index: recipientWidgetIndexes[i],
-                    coin: coin,
-                    onChanged: () {
-                      _validateRecipientFormStates();
-                    },
-                    remove: i == 0 && recipientWidgetIndexes.length == 1
-                        ? null
-                        : () {
-                            recipientWidgetIndexes.removeAt(i);
-                            setState(() {});
-                          },
+          child: child,
+        ),
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.stretch,
+          children: [
+            if (!Util.isDesktop)
+              Container(
+                decoration: BoxDecoration(
+                  color: Theme.of(context).extension<StackColors>()!.popupBG,
+                  borderRadius: BorderRadius.circular(
+                    Constants.size.circularBorderRadius,
                   ),
                 ),
-            ],
-          ),
-          if (showCoinControl)
-            const SizedBox(
-              height: 8,
-            ),
-          if (showCoinControl)
-            RoundedWhiteContainer(
-              child: Row(
-                mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                children: [
-                  Text(
-                    "Coin control",
-                    style: STextStyles.w500_14(context).copyWith(
-                      color: Theme.of(context)
-                          .extension<StackColors>()!
-                          .textSubtitle1,
-                    ),
-                  ),
-                  CustomTextButton(
-                    text: selectedUTXOs.isEmpty
-                        ? "Select coins"
-                        : "Selected coins (${selectedUTXOs.length})",
-                    onTap: () async {
-                      if (FocusScope.of(context).hasFocus) {
-                        FocusScope.of(context).unfocus();
-                        await Future<void>.delayed(
-                          const Duration(milliseconds: 100),
-                        );
-                      }
-
-                      if (mounted) {
-                        // finally spendable = ref
-                        //     .read(walletsChangeNotifierProvider)
-                        //     .getManager(widget.walletId)
-                        //     .balance
-                        //     .spendable;
-
-                        // TODO: [prio=high] make sure this coincontrol works correctly
-
-                        Amount? amount;
-
-                        final result = await Navigator.of(context).pushNamed(
-                          CoinControlView.routeName,
-                          arguments: Tuple4(
-                            walletId,
-                            CoinControlViewType.use,
-                            amount,
-                            selectedUTXOs,
+                child: Padding(
+                  padding: const EdgeInsets.all(12.0),
+                  child: Row(
+                    children: [
+                      SvgPicture.file(
+                        File(
+                          ref.watch(
+                            coinIconProvider(coin),
                           ),
-                        );
-
-                        if (result is Set<UTXO>) {
-                          setState(() {
-                            selectedUTXOs = result;
-                          });
-                        }
-                      }
-                    },
-                  ),
-                ],
-              ),
-            ),
-          const SizedBox(
-            height: 12,
-          ),
-          Text(
-            "Note (optional)",
-            style: STextStyles.smallMed12(context),
-            textAlign: TextAlign.left,
-          ),
-          const SizedBox(
-            height: 8,
-          ),
-          ClipRRect(
-            borderRadius: BorderRadius.circular(
-              Constants.size.circularBorderRadius,
-            ),
-            child: TextField(
-              autocorrect: Util.isDesktop ? false : true,
-              enableSuggestions: Util.isDesktop ? false : true,
-              controller: noteController,
-              focusNode: _noteFocusNode,
-              style: STextStyles.field(context),
-              onChanged: (_) => setState(() {}),
-              decoration: standardInputDecoration(
-                "Type something...",
-                _noteFocusNode,
-                context,
-              ).copyWith(
-                suffixIcon: noteController.text.isNotEmpty
-                    ? Padding(
-                        padding: const EdgeInsets.only(right: 0),
-                        child: UnconstrainedBox(
-                          child: Row(
+                        ),
+                        width: 22,
+                        height: 22,
+                      ),
+                      const SizedBox(
+                        width: 6,
+                      ),
+                      Column(
+                        crossAxisAlignment: CrossAxisAlignment.start,
+                        children: [
+                          Text(
+                            ref.watch(pWalletName(walletId)),
+                            style: STextStyles.titleBold12(context)
+                                .copyWith(fontSize: 14),
+                            overflow: TextOverflow.ellipsis,
+                            maxLines: 1,
+                          ),
+                          // const SizedBox(
+                          //   height: 2,
+                          // ),
+                          Text(
+                            "Available balance",
+                            style: STextStyles.label(context)
+                                .copyWith(fontSize: 10),
+                          ),
+                        ],
+                      ),
+                      Util.isDesktop
+                          ? const SizedBox(
+                              height: 24,
+                            )
+                          : const Spacer(),
+                      GestureDetector(
+                        onTap: () {
+                          // cryptoAmountController.text = ref
+                          //     .read(pAmountFormatter(coin))
+                          //     .format(
+                          //       _cachedBalance!,
+                          //       withUnitName: false,
+                          //     );
+                        },
+                        child: Container(
+                          color: Colors.transparent,
+                          child: Column(
+                            crossAxisAlignment: CrossAxisAlignment.end,
                             children: [
-                              TextFieldIconButton(
-                                child: const XIcon(),
-                                onTap: () async {
-                                  setState(() {
-                                    noteController.text = "";
-                                  });
-                                },
+                              Text(
+                                ref.watch(pAmountFormatter(coin)).format(ref
+                                    .watch(pWalletBalance(walletId))
+                                    .spendable),
+                                style:
+                                    STextStyles.titleBold12(context).copyWith(
+                                  fontSize: 10,
+                                ),
+                                textAlign: TextAlign.right,
                               ),
+                              // Text(
+                              //   "${(manager.balance.spendable.decimal * ref.watch(
+                              //             priceAnd24hChangeNotifierProvider.select(
+                              //               (value) => value.getPrice(coin).item1,
+                              //             ),
+                              //           )).toAmount(
+                              //         fractionDigits: 2,
+                              //       ).fiatString(
+                              //         locale: locale,
+                              //       )} ${ref.watch(
+                              //     prefsChangeNotifierProvider
+                              //         .select((value) => value.currency),
+                              //   )}",
+                              //   style: STextStyles.subtitle(context).copyWith(
+                              //     fontSize: 8,
+                              //   ),
+                              //   textAlign: TextAlign.right,
+                              // )
                             ],
                           ),
                         ),
                       )
-                    : null,
+                    ],
+                  ),
+                ),
+              ),
+            const SizedBox(
+              height: 16,
+            ),
+            Row(
+              mainAxisAlignment: MainAxisAlignment.spaceBetween,
+              children: [
+                Text(
+                  "Recipients",
+                  style: STextStyles.smallMed12(context),
+                  textAlign: TextAlign.left,
+                ),
+                CustomTextButton(
+                  text: "Add",
+                  onTap: () {
+                    // used for tracking recipient forms
+                    _greatestWidgetIndex++;
+                    recipientWidgetIndexes.add(_greatestWidgetIndex);
+                    setState(() {});
+                  },
+                ),
+              ],
+            ),
+            const SizedBox(
+              height: 8,
+            ),
+            Column(
+              children: [
+                for (int i = 0; i < recipientWidgetIndexes.length; i++)
+                  ConditionalParent(
+                    condition: recipientWidgetIndexes.length > 1,
+                    builder: (child) => Padding(
+                      padding: const EdgeInsets.only(top: 8),
+                      child: child,
+                    ),
+                    child: Recipient(
+                      key: Key(
+                        "recipientKey_${recipientWidgetIndexes[i]}",
+                      ),
+                      index: recipientWidgetIndexes[i],
+                      coin: coin,
+                      onChanged: () {
+                        _validateRecipientFormStates();
+                      },
+                      remove: i == 0 && recipientWidgetIndexes.length == 1
+                          ? null
+                          : () {
+                              recipientWidgetIndexes.removeAt(i);
+                              setState(() {});
+                            },
+                    ),
+                  ),
+              ],
+            ),
+            if (showCoinControl)
+              const SizedBox(
+                height: 8,
+              ),
+            if (showCoinControl)
+              RoundedWhiteContainer(
+                child: Row(
+                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                  children: [
+                    Text(
+                      "Coin control",
+                      style: STextStyles.w500_14(context).copyWith(
+                        color: Theme.of(context)
+                            .extension<StackColors>()!
+                            .textSubtitle1,
+                      ),
+                    ),
+                    CustomTextButton(
+                      text: selectedUTXOs.isEmpty
+                          ? "Select coins"
+                          : "Selected coins (${selectedUTXOs.length})",
+                      onTap: () async {
+                        if (FocusScope.of(context).hasFocus) {
+                          FocusScope.of(context).unfocus();
+                          await Future<void>.delayed(
+                            const Duration(milliseconds: 100),
+                          );
+                        }
+
+                        if (mounted) {
+                          // finally spendable = ref
+                          //     .read(walletsChangeNotifierProvider)
+                          //     .getManager(widget.walletId)
+                          //     .balance
+                          //     .spendable;
+
+                          // TODO: [prio=high] make sure this coincontrol works correctly
+
+                          Amount? amount;
+
+                          final result = await Navigator.of(context).pushNamed(
+                            CoinControlView.routeName,
+                            arguments: Tuple4(
+                              walletId,
+                              CoinControlViewType.use,
+                              amount,
+                              selectedUTXOs,
+                            ),
+                          );
+
+                          if (result is Set<UTXO>) {
+                            setState(() {
+                              selectedUTXOs = result;
+                            });
+                          }
+                        }
+                      },
+                    ),
+                  ],
+                ),
+              ),
+            const SizedBox(
+              height: 12,
+            ),
+            Text(
+              "Note (optional)",
+              style: STextStyles.smallMed12(context),
+              textAlign: TextAlign.left,
+            ),
+            const SizedBox(
+              height: 8,
+            ),
+            ClipRRect(
+              borderRadius: BorderRadius.circular(
+                Constants.size.circularBorderRadius,
+              ),
+              child: TextField(
+                autocorrect: Util.isDesktop ? false : true,
+                enableSuggestions: Util.isDesktop ? false : true,
+                controller: noteController,
+                focusNode: _noteFocusNode,
+                style: STextStyles.field(context),
+                onChanged: (_) => setState(() {}),
+                decoration: standardInputDecoration(
+                  "Type something...",
+                  _noteFocusNode,
+                  context,
+                ).copyWith(
+                  suffixIcon: noteController.text.isNotEmpty
+                      ? Padding(
+                          padding: const EdgeInsets.only(right: 0),
+                          child: UnconstrainedBox(
+                            child: Row(
+                              children: [
+                                TextFieldIconButton(
+                                  child: const XIcon(),
+                                  onTap: () async {
+                                    setState(() {
+                                      noteController.text = "";
+                                    });
+                                  },
+                                ),
+                              ],
+                            ),
+                          ),
+                        )
+                      : null,
+                ),
               ),
             ),
-          ),
-          const SizedBox(
-            height: 12,
-          ),
-          Padding(
-            padding: const EdgeInsets.only(
-              bottom: 12,
-              top: 16,
+            const SizedBox(
+              height: 12,
             ),
-            child: FeeSlider(
-              coin: coin,
-              onSatVByteChanged: (rate) {
-                customFeeRate = rate;
-              },
+            Padding(
+              padding: const EdgeInsets.only(
+                bottom: 12,
+                top: 16,
+              ),
+              child: FeeSlider(
+                coin: coin,
+                onSatVByteChanged: (rate) {
+                  customFeeRate = rate;
+                },
+              ),
             ),
-          ),
-          Util.isDesktop
-              ? const SizedBox(
-                  height: 12,
-                )
-              : const Spacer(),
-          const SizedBox(
-            height: 12,
-          ),
-          TextButton(
-            onPressed: ref.watch(previewTxButtonStateProvider.state).state
-                ? _createSignConfig
-                : null,
-            style: ref.watch(previewTxButtonStateProvider.state).state
-                ? Theme.of(context)
-                    .extension<StackColors>()!
-                    .getPrimaryEnabledButtonStyle(context)
-                : Theme.of(context)
-                    .extension<StackColors>()!
-                    .getPrimaryDisabledButtonStyle(context),
-            child: Text(
-              "Create config",
-              style: STextStyles.button(context),
+            Util.isDesktop
+                ? const SizedBox(
+                    height: 12,
+                  )
+                : const Spacer(),
+            const SizedBox(
+              height: 12,
             ),
-          ),
-          const SizedBox(
-            height: 16,
-          ),
-        ],
+            TextButton(
+              onPressed: ref.watch(previewTxButtonStateProvider.state).state
+                  ? _createSignConfig
+                  : null,
+              style: ref.watch(previewTxButtonStateProvider.state).state
+                  ? Theme.of(context)
+                      .extension<StackColors>()!
+                      .getPrimaryEnabledButtonStyle(context)
+                  : Theme.of(context)
+                      .extension<StackColors>()!
+                      .getPrimaryDisabledButtonStyle(context),
+              child: Text(
+                "Create config",
+                style: STextStyles.button(context),
+              ),
+            ),
+            const SizedBox(
+              height: 16,
+            ),
+          ],
+        ),
       ),
     );
   }

From 778795139a8fbd3a813fbcc1d7074f229661c004 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Tue, 12 Mar 2024 06:48:01 -0500
Subject: [PATCH 37/57] add import sign config route

---
 lib/route_generator.dart | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/lib/route_generator.dart b/lib/route_generator.dart
index 6f298a7c0..4eb906b8a 100644
--- a/lib/route_generator.dart
+++ b/lib/route_generator.dart
@@ -85,6 +85,7 @@ import 'package:stackwallet/pages/receive_view/receive_view.dart';
 import 'package:stackwallet/pages/send_view/confirm_transaction_view.dart';
 import 'package:stackwallet/pages/send_view/frost_ms/frost_attempt_sign_config_view.dart';
 import 'package:stackwallet/pages/send_view/frost_ms/frost_create_sign_config_view.dart';
+import 'package:stackwallet/pages/send_view/frost_ms/frost_import_sign_config_view.dart';
 import 'package:stackwallet/pages/send_view/frost_ms/frost_send_view.dart';
 import 'package:stackwallet/pages/send_view/send_view.dart';
 import 'package:stackwallet/pages/send_view/token_send_view.dart';
@@ -777,6 +778,20 @@ class RouteGenerator {
         }
         return _routeError("${settings.name} invalid args: ${args.toString()}");
 
+      case FrostImportSignConfigView.routeName:
+        if (args is String) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => FrostImportSignConfigView(
+              walletId: args,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
+        }
+        return _routeError("${settings.name} invalid args: ${args.toString()}");
+
       case FrostCreateSignConfigView.routeName:
         if (args is String) {
           return getRoute(

From 64b0f23910807fe7134188028b1263fee84ff887 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Tue, 12 Mar 2024 07:05:05 -0500
Subject: [PATCH 38/57] desktop create sign tweaks

making things wider and scrollable but the qr code not overflowingly wide
---
 .../frost_create_sign_config_view.dart        | 23 +++++++++++--------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/lib/pages/send_view/frost_ms/frost_create_sign_config_view.dart b/lib/pages/send_view/frost_ms/frost_create_sign_config_view.dart
index 104160a76..bb2c129ca 100644
--- a/lib/pages/send_view/frost_ms/frost_create_sign_config_view.dart
+++ b/lib/pages/send_view/frost_ms/frost_create_sign_config_view.dart
@@ -71,6 +71,8 @@ class _FrostCreateSignConfigViewState
 
   @override
   Widget build(BuildContext context) {
+    double qrImageSize =
+        Util.isDesktop ? 360 : MediaQuery.of(context).size.width - 32;
     return ConditionalParent(
       condition: Util.isDesktop,
       builder: (child) => DesktopScaffold(
@@ -79,9 +81,11 @@ class _FrostCreateSignConfigViewState
           isCompactHeight: false,
           leading: AppBarBackButton(),
         ),
-        body: SizedBox(
-          width: 480,
-          child: child,
+        body: SingleChildScrollView(
+          child: SizedBox(
+            width: 600, // Was 480, may look better but overflows the bottom.
+            child: child,
+          ),
         ),
       ),
       child: ConditionalParent(
@@ -126,13 +130,13 @@ class _FrostCreateSignConfigViewState
           children: [
             if (!Util.isDesktop) const Spacer(),
             SizedBox(
-              height: MediaQuery.of(context).size.width - 32,
+              height: qrImageSize,
               child: Row(
                 mainAxisAlignment: MainAxisAlignment.center,
                 children: [
                   QrImageView(
                     data: ref.watch(pFrostTxData.state).state!.frostMSConfig!,
-                    size: MediaQuery.of(context).size.width - 32,
+                    size: qrImageSize,
                     backgroundColor:
                         Theme.of(context).extension<StackColors>()!.background,
                     foregroundColor: Theme.of(context)
@@ -142,9 +146,10 @@ class _FrostCreateSignConfigViewState
                 ],
               ),
             ),
-            const SizedBox(
-              height: 32,
-            ),
+            if (!Util.isDesktop)
+              const SizedBox(
+                height: 32,
+              ),
             DetailItem(
               title: "Encoded config",
               detail: ref.watch(pFrostTxData.state).state!.frostMSConfig!,
@@ -157,7 +162,7 @@ class _FrostCreateSignConfigViewState
                     ),
             ),
             SizedBox(
-              height: Util.isDesktop ? 64 : 16,
+              height: Util.isDesktop ? 20 : 16,
             ),
             if (!Util.isDesktop)
               const Spacer(

From 95bb47aaf8c3bf2553eb4421b1e8e0d907fdb236 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Tue, 12 Mar 2024 07:45:49 -0500
Subject: [PATCH 39/57] fix rescans

---
 .../wallet/impl/bitcoin_frost_wallet.dart     | 20 +++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
index 097769260..fdefac4e9 100644
--- a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
+++ b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart
@@ -698,10 +698,14 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
     String? multisigConfig,
   }) async {
     if (serializedKeys == null || multisigConfig == null) {
-      throw Exception(
-        "Failed to recover $runtimeType: "
-        "Missing serializedKeys and/or multisigConfig.",
-      );
+      serializedKeys = await getSerializedKeys();
+      multisigConfig = await getMultisigConfig();
+    }
+    if (serializedKeys == null || multisigConfig == null) {
+      String err = "${info.coinName} wallet ${info.walletId} had null keys/cfg";
+      Logging.instance.log(err, level: LogLevel.Fatal);
+      throw Exception(err);
+      // TODO [prio=low]: handle null keys or config.  This should not happen.
     }
 
     final coin = info.coin;
@@ -719,7 +723,7 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
         if (!isRescan) {
           final salt = frost
               .multisigSalt(
-                multisigConfig: multisigConfig,
+                multisigConfig: multisigConfig!,
               )
               .toHex;
           final knownSalts = _getKnownSalts();
@@ -735,9 +739,9 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T> {
           await mainDB.deleteWalletBlockchainData(walletId);
         }
 
-        final keys = frost.deserializeKeys(keys: serializedKeys);
-        await _saveSerializedKeys(serializedKeys);
-        await _saveMultisigConfig(multisigConfig);
+        final keys = frost.deserializeKeys(keys: serializedKeys!);
+        await _saveSerializedKeys(serializedKeys!);
+        await _saveMultisigConfig(multisigConfig!);
 
         final addressString = frost.addressForKeys(
           network: cryptoCurrency.network == CryptoCurrencyNetwork.main

From f68c0f4839f8867ba302cf0cef218bc4cf0ef3a0 Mon Sep 17 00:00:00 2001
From: Diego Salazar <diego@cypherstack.com>
Date: Tue, 12 Mar 2024 16:55:01 -0600
Subject: [PATCH 40/57] Update version (v1.10.3, build 215)

---
 pubspec.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pubspec.yaml b/pubspec.yaml
index 58b5c7008..fd19a216e 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.10.2+214
+version: 1.10.3+215
 
 environment:
   sdk: ">=3.0.2 <4.0.0"

From ec51f954496bd8ae1610cfcacc7c6415c5bfdf9c Mon Sep 17 00:00:00 2001
From: likho <likhojiba@gmail.com>
Date: Thu, 14 Mar 2024 20:23:41 +0200
Subject: [PATCH 41/57] WIP: Add frost mascot

---
 assets/images/mascot.png                      | Bin 0 -> 222983 bytes
 lib/pages/FrostMascot.dart                    |  49 ++++++++++++++++++
 ...irm_new_frost_ms_wallet_creation_view.dart |  14 +----
 .../new/create_new_frost_ms_wallet_view.dart  |   4 +-
 .../new/frost_share_commitments_view.dart     |  14 +----
 .../frost_ms/new/frost_share_shares_view.dart |  13 +----
 .../new/share_new_multisig_config_view.dart   |   4 +-
 lib/utilities/assets.dart                     |   1 +
 8 files changed, 60 insertions(+), 39 deletions(-)
 create mode 100644 assets/images/mascot.png
 create mode 100644 lib/pages/FrostMascot.dart

diff --git a/assets/images/mascot.png b/assets/images/mascot.png
new file mode 100644
index 0000000000000000000000000000000000000000..9c05490a43350fd0e0e17b5b456f38b466e94ce3
GIT binary patch
literal 222983
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
D-%Nhp

literal 0
HcmV?d00001

diff --git a/lib/pages/FrostMascot.dart b/lib/pages/FrostMascot.dart
new file mode 100644
index 000000000..92058d2b9
--- /dev/null
+++ b/lib/pages/FrostMascot.dart
@@ -0,0 +1,49 @@
+/*
+ * This file is part of Stack Wallet.
+ *
+ * Copyright (c) 2023 Cypher Stack
+ * All Rights Reserved.
+ * The code is distributed under GPLv3 license, see LICENSE file for details.
+ * Generated by Cypher Stack on 2023-05-26
+ *
+ */
+
+import 'package:flutter/material.dart';
+import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/assets.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+
+import 'add_wallet_views/new_wallet_recovery_phrase_warning_view/recovery_phrase_explanation_dialog.dart';
+
+class FrostMascot extends StatelessWidget {
+  const FrostMascot({
+    Key? key,
+    this.onPressed,
+  }) : super(key: key);
+
+  final VoidCallback? onPressed;
+
+  @override
+  Widget build(BuildContext context) {
+    return Padding(
+      padding: const EdgeInsets.only(
+        right: 24,
+      ),
+      child: GestureDetector(
+        onTap: () async {
+          await showDialog<void>(
+            context: context,
+            builder: (context) =>
+            const RecoveryPhraseExplanationDialog(),
+          );
+        },
+        child: Image(
+          image: AssetImage(
+            Assets.png.mascot,
+          ),
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/pages/add_wallet_views/frost_ms/new/confirm_new_frost_ms_wallet_creation_view.dart b/lib/pages/add_wallet_views/frost_ms/new/confirm_new_frost_ms_wallet_creation_view.dart
index 08018b43c..c1797cd6e 100644
--- a/lib/pages/add_wallet_views/frost_ms/new/confirm_new_frost_ms_wallet_creation_view.dart
+++ b/lib/pages/add_wallet_views/frost_ms/new/confirm_new_frost_ms_wallet_creation_view.dart
@@ -4,10 +4,10 @@ import 'dart:typed_data';
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:stackwallet/notifications/show_flush_bar.dart';
+import 'package:stackwallet/pages/FrostMascot.dart';
 import 'package:stackwallet/pages/home_view/home_view.dart';
 import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
 import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
-import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
 import 'package:stackwallet/providers/db/main_db_provider.dart';
 import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
 import 'package:stackwallet/providers/global/node_service_provider.dart';
@@ -103,17 +103,7 @@ class _ConfirmNewFrostMSWalletCreationViewState
                 );
               },
             ),
-            trailing: ExitToMyStackButton(
-              onPressed: () async {
-                await showDialog<void>(
-                  context: context,
-                  builder: (_) => const FrostInterruptionDialog(
-                    type: FrostInterruptionDialogType.walletCreation,
-                    popUntilOnYesRouteName: DesktopHomeView.routeName,
-                  ),
-                );
-              },
-            ),
+            trailing: const FrostMascot(),
           ),
           body: SizedBox(
             width: 480,
diff --git a/lib/pages/add_wallet_views/frost_ms/new/create_new_frost_ms_wallet_view.dart b/lib/pages/add_wallet_views/frost_ms/new/create_new_frost_ms_wallet_view.dart
index b408b61ef..d1799bc5e 100644
--- a/lib/pages/add_wallet_views/frost_ms/new/create_new_frost_ms_wallet_view.dart
+++ b/lib/pages/add_wallet_views/frost_ms/new/create_new_frost_ms_wallet_view.dart
@@ -1,8 +1,8 @@
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:stackwallet/pages/FrostMascot.dart';
 import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/share_new_multisig_config_view.dart';
-import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
 import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
 import 'package:stackwallet/services/frost.dart';
 import 'package:stackwallet/themes/stack_colors.dart';
@@ -121,7 +121,7 @@ class _NewFrostMsWalletViewState
         appBar: const DesktopAppBar(
           isCompactHeight: false,
           leading: AppBarBackButton(),
-          trailing: ExitToMyStackButton(),
+          trailing: FrostMascot(),
         ),
         body: SizedBox(
           width: 480,
diff --git a/lib/pages/add_wallet_views/frost_ms/new/frost_share_commitments_view.dart b/lib/pages/add_wallet_views/frost_ms/new/frost_share_commitments_view.dart
index bf3649a37..282f1716c 100644
--- a/lib/pages/add_wallet_views/frost_ms/new/frost_share_commitments_view.dart
+++ b/lib/pages/add_wallet_views/frost_ms/new/frost_share_commitments_view.dart
@@ -3,11 +3,11 @@ import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:qr_flutter/qr_flutter.dart';
+import 'package:stackwallet/pages/FrostMascot.dart';
 import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/frost_share_shares_view.dart';
 import 'package:stackwallet/pages/home_view/home_view.dart';
 import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
 import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
-import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
 import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
 import 'package:stackwallet/services/frost.dart';
 import 'package:stackwallet/themes/stack_colors.dart';
@@ -121,17 +121,7 @@ class _FrostShareCommitmentsViewState
                 );
               },
             ),
-            trailing: ExitToMyStackButton(
-              onPressed: () async {
-                await showDialog<void>(
-                  context: context,
-                  builder: (_) => const FrostInterruptionDialog(
-                    type: FrostInterruptionDialogType.walletCreation,
-                    popUntilOnYesRouteName: DesktopHomeView.routeName,
-                  ),
-                );
-              },
-            ),
+            trailing: const FrostMascot(),
           ),
           body: SizedBox(
             width: 480,
diff --git a/lib/pages/add_wallet_views/frost_ms/new/frost_share_shares_view.dart b/lib/pages/add_wallet_views/frost_ms/new/frost_share_shares_view.dart
index 0f5e70ee7..33fdcefcf 100644
--- a/lib/pages/add_wallet_views/frost_ms/new/frost_share_shares_view.dart
+++ b/lib/pages/add_wallet_views/frost_ms/new/frost_share_shares_view.dart
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:qr_flutter/qr_flutter.dart';
+import 'package:stackwallet/pages/FrostMascot.dart';
 import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/confirm_new_frost_ms_wallet_creation_view.dart';
 import 'package:stackwallet/pages/home_view/home_view.dart';
 import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
@@ -120,17 +121,7 @@ class _FrostShareSharesViewState extends ConsumerState<FrostShareSharesView> {
                 );
               },
             ),
-            trailing: ExitToMyStackButton(
-              onPressed: () async {
-                await showDialog<void>(
-                  context: context,
-                  builder: (_) => const FrostInterruptionDialog(
-                    type: FrostInterruptionDialogType.walletCreation,
-                    popUntilOnYesRouteName: DesktopHomeView.routeName,
-                  ),
-                );
-              },
-            ),
+            trailing: const FrostMascot(),
           ),
           body: SizedBox(
             width: 480,
diff --git a/lib/pages/add_wallet_views/frost_ms/new/share_new_multisig_config_view.dart b/lib/pages/add_wallet_views/frost_ms/new/share_new_multisig_config_view.dart
index 4afb4c0c5..aa5a3d7bf 100644
--- a/lib/pages/add_wallet_views/frost_ms/new/share_new_multisig_config_view.dart
+++ b/lib/pages/add_wallet_views/frost_ms/new/share_new_multisig_config_view.dart
@@ -1,9 +1,9 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:qr_flutter/qr_flutter.dart';
+import 'package:stackwallet/pages/FrostMascot.dart';
 import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/frost_share_commitments_view.dart';
 import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
-import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
 import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
 import 'package:stackwallet/services/frost.dart';
 import 'package:stackwallet/themes/stack_colors.dart';
@@ -47,7 +47,7 @@ class _ShareNewMultisigConfigViewState
         appBar: const DesktopAppBar(
           isCompactHeight: false,
           leading: AppBarBackButton(),
-          trailing: ExitToMyStackButton(),
+          trailing: FrostMascot(),
         ),
         body: SizedBox(
           width: 480,
diff --git a/lib/utilities/assets.dart b/lib/utilities/assets.dart
index ecd170f6c..ff385a44d 100644
--- a/lib/utilities/assets.dart
+++ b/lib/utilities/assets.dart
@@ -257,6 +257,7 @@ class _PNG {
 
   String get glasses => "assets/images/glasses.png";
   String get glassesHidden => "assets/images/glasses-hidden.png";
+  String get mascot => "assets/images/mascot.png";
 }
 
 class _ANIMATIONS {

From d8e5b8e3052790300eee5c2468fd44669c0fe776 Mon Sep 17 00:00:00 2001
From: likho <likhojiba@gmail.com>
Date: Fri, 15 Mar 2024 13:26:50 +0200
Subject: [PATCH 42/57] Add frost mascot and dialog

---
 .../frost_step_explanation_dialog.dart        | 65 +++++++++++++++++++
 ...irm_new_frost_ms_wallet_creation_view.dart |  9 ++-
 .../new/create_new_frost_ms_wallet_view.dart  |  9 ++-
 .../new/frost_share_commitments_view.dart     |  7 +-
 .../frost_ms/new/frost_share_shares_view.dart |  8 ++-
 .../new/import_new_frost_ms_wallet_view.dart  | 10 ++-
 .../new/share_new_multisig_config_view.dart   |  9 ++-
 .../restore/restore_frost_ms_wallet_view.dart |  9 ++-
 .../{FrostMascot.dart => frost_mascot.dart}   | 18 +++--
 .../resharing/finish_resharing_view.dart      | 10 ++-
 .../new/new_continue_sharing_view.dart        | 16 ++---
 .../new/new_import_resharer_config_view.dart  |  9 ++-
 .../new/new_start_resharing_view.dart         | 16 ++---
 13 files changed, 139 insertions(+), 56 deletions(-)
 create mode 100644 lib/pages/add_wallet_views/frost_ms/frost_step_explanation_dialog.dart
 rename lib/pages/{FrostMascot.dart => frost_mascot.dart} (66%)

diff --git a/lib/pages/add_wallet_views/frost_ms/frost_step_explanation_dialog.dart b/lib/pages/add_wallet_views/frost_ms/frost_step_explanation_dialog.dart
new file mode 100644
index 000000000..102bab1e5
--- /dev/null
+++ b/lib/pages/add_wallet_views/frost_ms/frost_step_explanation_dialog.dart
@@ -0,0 +1,65 @@
+/*
+ * This file is part of Stack Wallet.
+ *
+ * Copyright (c) 2023 Cypher Stack
+ * All Rights Reserved.
+ * The code is distributed under GPLv3 license, see LICENSE file for details.
+ * Generated by Cypher Stack on 2023-05-26
+ *
+ */
+
+import 'package:flutter/material.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/widgets/desktop/secondary_button.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+
+class FrostStepExplanationDialog extends StatelessWidget {
+  final String title;
+  final String body;
+  const FrostStepExplanationDialog({super.key, required this.title, required this.body});
+
+  @override
+  Widget build(BuildContext context) {
+    return StackDialogBase(
+      child: Column(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          SizedBox(
+            child: SingleChildScrollView(
+              child: Column(
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  Text(
+                    title,
+                    style: STextStyles.titleBold12(context),
+                  ),
+                  const SizedBox(
+                    height: 12,
+                  ),
+                  Text(
+                    body,
+                    style: STextStyles.baseXS(context),
+                  ),
+                ],
+              ),
+            ),
+          ),
+          const SizedBox(
+            height: 24,
+          ),
+          Row(
+            children: [
+              const Spacer(),
+              Expanded(
+                child: SecondaryButton(
+                  label: "Close",
+                  onPressed: Navigator.of(context).pop,
+                ),
+              ),
+            ],
+          ),
+        ],
+      ),
+    );
+  }
+}
diff --git a/lib/pages/add_wallet_views/frost_ms/new/confirm_new_frost_ms_wallet_creation_view.dart b/lib/pages/add_wallet_views/frost_ms/new/confirm_new_frost_ms_wallet_creation_view.dart
index c1797cd6e..ffd1127b6 100644
--- a/lib/pages/add_wallet_views/frost_ms/new/confirm_new_frost_ms_wallet_creation_view.dart
+++ b/lib/pages/add_wallet_views/frost_ms/new/confirm_new_frost_ms_wallet_creation_view.dart
@@ -4,7 +4,7 @@ import 'dart:typed_data';
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:stackwallet/notifications/show_flush_bar.dart';
-import 'package:stackwallet/pages/FrostMascot.dart';
+import 'package:stackwallet/pages/frost_mascot.dart';
 import 'package:stackwallet/pages/home_view/home_view.dart';
 import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
 import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
@@ -34,7 +34,7 @@ import 'package:stackwallet/widgets/detail_item.dart';
 import 'package:stackwallet/widgets/dialogs/frost_interruption_dialog.dart';
 import 'package:stackwallet/widgets/loading_indicator.dart';
 
-import '../../../../wallets/isar/models/wallet_info.dart';
+import 'package:stackwallet/wallets/isar/models/wallet_info.dart';
 
 class ConfirmNewFrostMSWalletCreationView extends ConsumerStatefulWidget {
   const ConfirmNewFrostMSWalletCreationView({
@@ -103,7 +103,10 @@ class _ConfirmNewFrostMSWalletCreationViewState
                 );
               },
             ),
-            trailing: const FrostMascot(),
+            trailing: FrostMascot(
+              title: 'Lorem ipsum',
+              body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam est justo, ',
+            ),
           ),
           body: SizedBox(
             width: 480,
diff --git a/lib/pages/add_wallet_views/frost_ms/new/create_new_frost_ms_wallet_view.dart b/lib/pages/add_wallet_views/frost_ms/new/create_new_frost_ms_wallet_view.dart
index d1799bc5e..9f42a3fa6 100644
--- a/lib/pages/add_wallet_views/frost_ms/new/create_new_frost_ms_wallet_view.dart
+++ b/lib/pages/add_wallet_views/frost_ms/new/create_new_frost_ms_wallet_view.dart
@@ -1,7 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:stackwallet/pages/FrostMascot.dart';
+import 'package:stackwallet/pages/frost_mascot.dart';
 import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/share_new_multisig_config_view.dart';
 import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
 import 'package:stackwallet/services/frost.dart';
@@ -118,10 +118,13 @@ class _NewFrostMsWalletViewState
       condition: Util.isDesktop,
       builder: (child) => DesktopScaffold(
         background: Theme.of(context).extension<StackColors>()!.background,
-        appBar: const DesktopAppBar(
+        appBar: DesktopAppBar(
           isCompactHeight: false,
           leading: AppBarBackButton(),
-          trailing: FrostMascot(),
+          trailing: FrostMascot(
+            title: 'Lorem ipsum',
+            body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam est justo, ',
+          ),
         ),
         body: SizedBox(
           width: 480,
diff --git a/lib/pages/add_wallet_views/frost_ms/new/frost_share_commitments_view.dart b/lib/pages/add_wallet_views/frost_ms/new/frost_share_commitments_view.dart
index 282f1716c..1234dbf8a 100644
--- a/lib/pages/add_wallet_views/frost_ms/new/frost_share_commitments_view.dart
+++ b/lib/pages/add_wallet_views/frost_ms/new/frost_share_commitments_view.dart
@@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:qr_flutter/qr_flutter.dart';
-import 'package:stackwallet/pages/FrostMascot.dart';
+import 'package:stackwallet/pages/frost_mascot.dart';
 import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/frost_share_shares_view.dart';
 import 'package:stackwallet/pages/home_view/home_view.dart';
 import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
@@ -121,7 +121,10 @@ class _FrostShareCommitmentsViewState
                 );
               },
             ),
-            trailing: const FrostMascot(),
+            trailing: FrostMascot(
+              title: 'Lorem ipsum',
+              body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam est justo, ',
+            ),
           ),
           body: SizedBox(
             width: 480,
diff --git a/lib/pages/add_wallet_views/frost_ms/new/frost_share_shares_view.dart b/lib/pages/add_wallet_views/frost_ms/new/frost_share_shares_view.dart
index 33fdcefcf..20ac39c03 100644
--- a/lib/pages/add_wallet_views/frost_ms/new/frost_share_shares_view.dart
+++ b/lib/pages/add_wallet_views/frost_ms/new/frost_share_shares_view.dart
@@ -3,12 +3,11 @@ import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:qr_flutter/qr_flutter.dart';
-import 'package:stackwallet/pages/FrostMascot.dart';
+import 'package:stackwallet/pages/frost_mascot.dart';
 import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/confirm_new_frost_ms_wallet_creation_view.dart';
 import 'package:stackwallet/pages/home_view/home_view.dart';
 import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
 import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
-import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
 import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
 import 'package:stackwallet/services/frost.dart';
 import 'package:stackwallet/themes/stack_colors.dart';
@@ -121,7 +120,10 @@ class _FrostShareSharesViewState extends ConsumerState<FrostShareSharesView> {
                 );
               },
             ),
-            trailing: const FrostMascot(),
+            trailing: FrostMascot(
+              title: 'Lorem ipsum',
+              body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam est justo, ',
+            ),
           ),
           body: SizedBox(
             width: 480,
diff --git a/lib/pages/add_wallet_views/frost_ms/new/import_new_frost_ms_wallet_view.dart b/lib/pages/add_wallet_views/frost_ms/new/import_new_frost_ms_wallet_view.dart
index 1b08b045d..4eeb3a045 100644
--- a/lib/pages/add_wallet_views/frost_ms/new/import_new_frost_ms_wallet_view.dart
+++ b/lib/pages/add_wallet_views/frost_ms/new/import_new_frost_ms_wallet_view.dart
@@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/frost_share_commitments_view.dart';
-import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
 import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
 import 'package:stackwallet/services/frost.dart';
 import 'package:stackwallet/themes/stack_colors.dart';
@@ -25,6 +24,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 'package:stackwallet/pages/frost_mascot.dart';
+
 class ImportNewFrostMsWalletView extends ConsumerStatefulWidget {
   const ImportNewFrostMsWalletView({
     super.key,
@@ -73,10 +74,13 @@ class _ImportNewFrostMsWalletViewState
       condition: Util.isDesktop,
       builder: (child) => DesktopScaffold(
         background: Theme.of(context).extension<StackColors>()!.background,
-        appBar: const DesktopAppBar(
+        appBar: DesktopAppBar(
           isCompactHeight: false,
           leading: AppBarBackButton(),
-          trailing: ExitToMyStackButton(),
+          trailing: FrostMascot(
+            title: 'Lorem ipsum',
+            body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam est justo, ',
+          ),
         ),
         body: SizedBox(
           width: 480,
diff --git a/lib/pages/add_wallet_views/frost_ms/new/share_new_multisig_config_view.dart b/lib/pages/add_wallet_views/frost_ms/new/share_new_multisig_config_view.dart
index aa5a3d7bf..7d463c4ca 100644
--- a/lib/pages/add_wallet_views/frost_ms/new/share_new_multisig_config_view.dart
+++ b/lib/pages/add_wallet_views/frost_ms/new/share_new_multisig_config_view.dart
@@ -1,7 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:qr_flutter/qr_flutter.dart';
-import 'package:stackwallet/pages/FrostMascot.dart';
+import 'package:stackwallet/pages/frost_mascot.dart';
 import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/frost_share_commitments_view.dart';
 import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
 import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
@@ -44,10 +44,13 @@ class _ShareNewMultisigConfigViewState
       condition: Util.isDesktop,
       builder: (child) => DesktopScaffold(
         background: Theme.of(context).extension<StackColors>()!.background,
-        appBar: const DesktopAppBar(
+        appBar: DesktopAppBar(
           isCompactHeight: false,
           leading: AppBarBackButton(),
-          trailing: FrostMascot(),
+          trailing: FrostMascot(
+            title: 'Lorem ipsum',
+            body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam est justo, ',
+          ),
         ),
         body: SizedBox(
           width: 480,
diff --git a/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart b/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart
index c9c174ab0..08f36ebde 100644
--- a/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart
+++ b/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart
@@ -40,6 +40,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 'package:stackwallet/pages/frost_mascot.dart';
+
 class RestoreFrostMsWalletView extends ConsumerStatefulWidget {
   const RestoreFrostMsWalletView({
     super.key,
@@ -212,10 +214,13 @@ class _RestoreFrostMsWalletViewState
       condition: Util.isDesktop,
       builder: (child) => DesktopScaffold(
         background: Theme.of(context).extension<StackColors>()!.background,
-        appBar: const DesktopAppBar(
+        appBar: DesktopAppBar(
           isCompactHeight: false,
           leading: AppBarBackButton(),
-          trailing: ExitToMyStackButton(),
+          trailing: FrostMascot(
+            title: 'Lorem ipsum',
+            body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam est justo, ',
+          )
         ),
         body: SizedBox(
           width: 480,
diff --git a/lib/pages/FrostMascot.dart b/lib/pages/frost_mascot.dart
similarity index 66%
rename from lib/pages/FrostMascot.dart
rename to lib/pages/frost_mascot.dart
index 92058d2b9..3f6c0562d 100644
--- a/lib/pages/FrostMascot.dart
+++ b/lib/pages/frost_mascot.dart
@@ -9,18 +9,16 @@
  */
 
 import 'package:flutter/material.dart';
-import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
-import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/pages/add_wallet_views/frost_ms/frost_step_explanation_dialog.dart';
 import 'package:stackwallet/utilities/assets.dart';
-import 'package:stackwallet/utilities/text_styles.dart';
-
-import 'add_wallet_views/new_wallet_recovery_phrase_warning_view/recovery_phrase_explanation_dialog.dart';
 
 class FrostMascot extends StatelessWidget {
-  const FrostMascot({
-    Key? key,
-    this.onPressed,
-  }) : super(key: key);
+  final String title;
+  final String body;
+  FrostMascot({
+    super.key,
+    this.onPressed, required this.title, required this.body,
+  });
 
   final VoidCallback? onPressed;
 
@@ -35,7 +33,7 @@ class FrostMascot extends StatelessWidget {
           await showDialog<void>(
             context: context,
             builder: (context) =>
-            const RecoveryPhraseExplanationDialog(),
+            FrostStepExplanationDialog(title: title, body: body),
           );
         },
         child: Image(
diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/finish_resharing_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/finish_resharing_view.dart
index 8d23e9ed4..5ff5c815d 100644
--- a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/finish_resharing_view.dart
+++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/finish_resharing_view.dart
@@ -8,7 +8,6 @@ import 'package:qr_flutter/qr_flutter.dart';
 import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/verify_updated_wallet_view.dart';
 import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
 import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
-import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
 import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart';
 import 'package:stackwallet/providers/db/main_db_provider.dart';
 import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
@@ -34,6 +33,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 'package:stackwallet/pages/frost_mascot.dart';
+
 class FinishResharingView extends ConsumerStatefulWidget {
   const FinishResharingView({
     super.key,
@@ -180,10 +181,13 @@ class _FinishResharingViewState extends ConsumerState<FinishResharingView> {
       condition: Util.isDesktop,
       builder: (child) => DesktopScaffold(
         background: Theme.of(context).extension<StackColors>()!.background,
-        appBar: const DesktopAppBar(
+        appBar: DesktopAppBar(
           isCompactHeight: false,
           leading: AppBarBackButton(),
-          trailing: ExitToMyStackButton(),
+          trailing: FrostMascot(
+            title: 'Lorem ipsum',
+            body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam est justo, ',
+          ),
         ),
         body: SizedBox(
           width: 480,
diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_continue_sharing_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_continue_sharing_view.dart
index 86ff2ebe0..5e4ed4762 100644
--- a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_continue_sharing_view.dart
+++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_continue_sharing_view.dart
@@ -5,7 +5,6 @@ import 'package:stackwallet/pages/home_view/home_view.dart';
 import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/finish_resharing_view.dart';
 import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
 import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
-import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
 import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
 import 'package:stackwallet/themes/stack_colors.dart';
 import 'package:stackwallet/utilities/text_styles.dart';
@@ -20,6 +19,8 @@ import 'package:stackwallet/widgets/desktop/primary_button.dart';
 import 'package:stackwallet/widgets/detail_item.dart';
 import 'package:stackwallet/widgets/dialogs/frost_interruption_dialog.dart';
 
+import 'package:stackwallet/pages/frost_mascot.dart';
+
 class NewContinueSharingView extends ConsumerStatefulWidget {
   const NewContinueSharingView({
     super.key,
@@ -68,16 +69,9 @@ class _NewContinueSharingViewState
                 );
               },
             ),
-            trailing: ExitToMyStackButton(
-              onPressed: () async {
-                await showDialog<void>(
-                  context: context,
-                  builder: (_) => const FrostInterruptionDialog(
-                    type: FrostInterruptionDialogType.resharing,
-                    popUntilOnYesRouteName: DesktopHomeView.routeName,
-                  ),
-                );
-              },
+            trailing: FrostMascot(
+              title: 'Lorem ipsum',
+              body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam est justo, ',
             ),
           ),
           body: SizedBox(
diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_import_resharer_config_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_import_resharer_config_view.dart
index f3ef1ec0b..698363923 100644
--- a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_import_resharer_config_view.dart
+++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_import_resharer_config_view.dart
@@ -27,6 +27,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 'package:stackwallet/pages/frost_mascot.dart';
+
 class NewImportResharerConfigView extends ConsumerStatefulWidget {
   const NewImportResharerConfigView({
     super.key,
@@ -89,10 +91,13 @@ class _NewImportResharerConfigViewState
       condition: Util.isDesktop,
       builder: (child) => DesktopScaffold(
         background: Theme.of(context).extension<StackColors>()!.background,
-        appBar: const DesktopAppBar(
+        appBar: DesktopAppBar(
           isCompactHeight: false,
           leading: AppBarBackButton(),
-          trailing: ExitToMyStackButton(),
+          trailing: FrostMascot(
+            title: 'Lorem ipsum',
+            body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam est justo, ',
+          ),
         ),
         body: SizedBox(
           width: 480,
diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_start_resharing_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_start_resharing_view.dart
index fb6107c2c..7173eff3d 100644
--- a/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_start_resharing_view.dart
+++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_start_resharing_view.dart
@@ -5,7 +5,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:stackwallet/pages/home_view/home_view.dart';
 import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/new/new_continue_sharing_view.dart';
 import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
-import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
 import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
 import 'package:stackwallet/services/frost.dart';
 import 'package:stackwallet/themes/stack_colors.dart';
@@ -27,6 +26,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 'package:stackwallet/pages/frost_mascot.dart';
+
 class NewStartResharingView extends ConsumerStatefulWidget {
   const NewStartResharingView({
     super.key,
@@ -146,16 +147,9 @@ class _NewStartResharingViewState extends ConsumerState<NewStartResharingView> {
                 );
               },
             ),
-            trailing: ExitToMyStackButton(
-              onPressed: () async {
-                await showDialog<void>(
-                  context: context,
-                  builder: (_) => const FrostInterruptionDialog(
-                    type: FrostInterruptionDialogType.resharing,
-                    popUntilOnYesRouteName: DesktopHomeView.routeName,
-                  ),
-                );
-              },
+            trailing: FrostMascot(
+              title: 'Lorem ipsum',
+              body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam est justo, ',
             ),
           ),
           body: SizedBox(

From f6d50756e8b4db841fd922474d1a9cea32271950 Mon Sep 17 00:00:00 2001
From: rehrar <diego@cypherstack.com>
Date: Fri, 15 Mar 2024 11:55:39 -0600
Subject: [PATCH 43/57] Updated XCode podfile

---
 macos/Podfile.lock                            |  8 +++-
 macos/Runner.xcodeproj/project.pbxproj        | 45 ++++++++++++++++++-
 .../xcshareddata/xcschemes/Runner.xcscheme    |  2 +-
 3 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/macos/Podfile.lock b/macos/Podfile.lock
index f76e35a57..ba853d0f9 100644
--- a/macos/Podfile.lock
+++ b/macos/Podfile.lock
@@ -62,6 +62,8 @@ PODS:
   - flutter_secure_storage_macos (6.1.1):
     - FlutterMacOS
   - FlutterMacOS (1.0.0)
+  - frostdart (0.0.1):
+    - FlutterMacOS
   - isar_flutter_libs (1.0.0):
     - FlutterMacOS
   - lelantus (0.0.1):
@@ -98,6 +100,7 @@ DEPENDENCIES:
   - flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`)
   - flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`)
   - FlutterMacOS (from `Flutter/ephemeral`)
+  - frostdart (from `Flutter/ephemeral/.symlinks/plugins/frostdart/macos`)
   - isar_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/isar_flutter_libs/macos`)
   - lelantus (from `Flutter/ephemeral/.symlinks/plugins/lelantus/macos`)
   - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
@@ -140,6 +143,8 @@ EXTERNAL SOURCES:
     :path: Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos
   FlutterMacOS:
     :path: Flutter/ephemeral
+  frostdart:
+    :path: Flutter/ephemeral/.symlinks/plugins/frostdart/macos
   isar_flutter_libs:
     :path: Flutter/ephemeral/.symlinks/plugins/isar_flutter_libs/macos
   lelantus:
@@ -171,10 +176,11 @@ SPEC CHECKSUMS:
   device_info_plus: 5401765fde0b8d062a2f8eb65510fb17e77cf07f
   devicelocale: 9f0f36ac651cabae2c33f32dcff4f32b61c38225
   flutter_libepiccash: be1560a04150c5cc85bcf08d236ec2b3d1f5d8da
-  flutter_libsparkmobile: 8ae86b0ccc7e52c9db6b53e258ee2977deb184ab
+  flutter_libsparkmobile: df2d36af1691379c81249e7be7b68be3c81d388b
   flutter_local_notifications: 3805ca215b2fb7f397d78b66db91f6a747af52e4
   flutter_secure_storage_macos: d56e2d218c1130b262bef8b4a7d64f88d7f9c9ea
   FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
+  frostdart: e6bf3119527ccfbcec1b8767da6ede5bb4c4f716
   isar_flutter_libs: 43385c99864c168fadba7c9adeddc5d38838ca6a
   lelantus: 308e42c5a648598936a07a234471dd8cf8e687a0
   package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce
diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj
index c2c2e62ad..f20cb25e7 100644
--- a/macos/Runner.xcodeproj/project.pbxproj
+++ b/macos/Runner.xcodeproj/project.pbxproj
@@ -31,6 +31,9 @@
 		B98151822A67402A009D013C /* mobileliblelantus.framework in Bundle Framework */ = {isa = PBXBuildFile; fileRef = B98151802A674022009D013C /* mobileliblelantus.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
 		B98151842A674143009D013C /* libsqlite3.0.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = B98151832A674143009D013C /* libsqlite3.0.tbd */; };
 		BFD0376C00E1FFD46376BB9D /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9206484E84CB0AD93E3E68CA /* Pods_RunnerTests.framework */; };
+		F1FA2C4E2BA4B49F00BDA1BB /* frostdart.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F1FA2C4D2BA4B49F00BDA1BB /* frostdart.dylib */; settings = {ATTRIBUTES = (Weak, ); }; };
+		F1FA2C502BA4B4CA00BDA1BB /* frostdart.dylib in Resources */ = {isa = PBXBuildFile; fileRef = F1FA2C4F2BA4B4CA00BDA1BB /* frostdart.dylib */; };
+		F1FA2C512BA4B51E00BDA1BB /* frostdart.dylib in Bundle Framework */ = {isa = PBXBuildFile; fileRef = F1FA2C4D2BA4B49F00BDA1BB /* frostdart.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
 		F653CA022D33E8B60E11A9F3 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E6036BF01BF05EA773C76D22 /* Pods_Runner.framework */; };
 /* End PBXBuildFile section */
 
@@ -58,6 +61,7 @@
 			dstPath = "";
 			dstSubfolderSpec = 10;
 			files = (
+				F1FA2C512BA4B51E00BDA1BB /* frostdart.dylib in Bundle Framework */,
 				B98151822A67402A009D013C /* mobileliblelantus.framework in Bundle Framework */,
 			);
 			name = "Bundle Framework";
@@ -94,6 +98,8 @@
 		B98151832A674143009D013C /* libsqlite3.0.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.0.tbd; path = usr/lib/libsqlite3.0.tbd; sourceTree = SDKROOT; };
 		BF5E76865ACB46314AC27D8F /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
 		E6036BF01BF05EA773C76D22 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		F1FA2C4D2BA4B49F00BDA1BB /* frostdart.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = frostdart.dylib; path = ../crypto_plugins/frostdart/macos/frostdart.dylib; sourceTree = "<group>"; };
+		F1FA2C4F2BA4B4CA00BDA1BB /* frostdart.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = frostdart.dylib; path = ../crypto_plugins/frostdart/macos/frostdart.dylib; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -111,6 +117,7 @@
 			files = (
 				B98151842A674143009D013C /* libsqlite3.0.tbd in Frameworks */,
 				B98151812A674022009D013C /* mobileliblelantus.framework in Frameworks */,
+				F1FA2C4E2BA4B49F00BDA1BB /* frostdart.dylib in Frameworks */,
 				F653CA022D33E8B60E11A9F3 /* Pods_Runner.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -140,6 +147,7 @@
 		33CC10E42044A3C60003C045 = {
 			isa = PBXGroup;
 			children = (
+				F1FA2C4F2BA4B4CA00BDA1BB /* frostdart.dylib */,
 				33FAB671232836740065AC1E /* Runner */,
 				33CEB47122A05771004F2AC0 /* Flutter */,
 				331C80D6294CF71000263BE5 /* RunnerTests */,
@@ -196,6 +204,7 @@
 		D73912EC22F37F3D000D13A0 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				F1FA2C4D2BA4B49F00BDA1BB /* frostdart.dylib */,
 				B98151832A674143009D013C /* libsqlite3.0.tbd */,
 				B98151802A674022009D013C /* mobileliblelantus.framework */,
 				E6036BF01BF05EA773C76D22 /* Pods_Runner.framework */,
@@ -268,7 +277,7 @@
 			isa = PBXProject;
 			attributes = {
 				LastSwiftUpdateCheck = 0920;
-				LastUpgradeCheck = 1300;
+				LastUpgradeCheck = 1430;
 				ORGANIZATIONNAME = "";
 				TargetAttributes = {
 					331C80D4294CF70F00263BE5 = {
@@ -325,6 +334,7 @@
 			files = (
 				33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */,
 				33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,
+				F1FA2C502BA4B4CA00BDA1BB /* frostdart.dylib in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -610,6 +620,17 @@
 					"$(inherited)",
 					"@executable_path/../Frameworks",
 				);
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"\"${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}\"",
+					"\"${PODS_ROOT}/../Flutter/ephemeral/.symlinks/plugins/cw_monero/macos/External/macos/lib\"",
+					"\"${PODS_ROOT}/../Flutter/ephemeral/.symlinks/plugins/cw_shared_external/macos/External/macos/lib\"",
+					"\"${PODS_ROOT}/../Flutter/ephemeral/.symlinks/plugins/cw_wownero/macos/External/macos/lib\"",
+					"\"${PODS_ROOT}/../Flutter/ephemeral/.symlinks/plugins/flutter_libepiccash/macos/libs\"",
+					"\"${PODS_ROOT}/../Flutter/ephemeral/.symlinks/plugins/isar_flutter_libs/macos\"",
+					/usr/lib/swift,
+					"$(PATH)/crypto_plugins/frostdart/macos\n",
+				);
 				PROVISIONING_PROFILE_SPECIFIER = "";
 				SWIFT_VERSION = 5.0;
 			};
@@ -763,6 +784,17 @@
 					"$(inherited)",
 					"@executable_path/../Frameworks",
 				);
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"\"${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}\"",
+					"\"${PODS_ROOT}/../Flutter/ephemeral/.symlinks/plugins/cw_monero/macos/External/macos/lib\"",
+					"\"${PODS_ROOT}/../Flutter/ephemeral/.symlinks/plugins/cw_shared_external/macos/External/macos/lib\"",
+					"\"${PODS_ROOT}/../Flutter/ephemeral/.symlinks/plugins/cw_wownero/macos/External/macos/lib\"",
+					"\"${PODS_ROOT}/../Flutter/ephemeral/.symlinks/plugins/flutter_libepiccash/macos/libs\"",
+					"\"${PODS_ROOT}/../Flutter/ephemeral/.symlinks/plugins/isar_flutter_libs/macos\"",
+					/usr/lib/swift,
+					"$(PATH)/crypto_plugins/frostdart/macos\n",
+				);
 				PROVISIONING_PROFILE_SPECIFIER = "";
 				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
 				SWIFT_VERSION = 5.0;
@@ -807,6 +839,17 @@
 					"$(inherited)",
 					"@executable_path/../Frameworks",
 				);
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"\"${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}\"",
+					"\"${PODS_ROOT}/../Flutter/ephemeral/.symlinks/plugins/cw_monero/macos/External/macos/lib\"",
+					"\"${PODS_ROOT}/../Flutter/ephemeral/.symlinks/plugins/cw_shared_external/macos/External/macos/lib\"",
+					"\"${PODS_ROOT}/../Flutter/ephemeral/.symlinks/plugins/cw_wownero/macos/External/macos/lib\"",
+					"\"${PODS_ROOT}/../Flutter/ephemeral/.symlinks/plugins/flutter_libepiccash/macos/libs\"",
+					"\"${PODS_ROOT}/../Flutter/ephemeral/.symlinks/plugins/isar_flutter_libs/macos\"",
+					/usr/lib/swift,
+					"$(PATH)/crypto_plugins/frostdart/macos\n",
+				);
 				PROVISIONING_PROFILE_SPECIFIER = "";
 				SWIFT_VERSION = 5.0;
 			};
diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index a9d38bc3b..5b6f6cbd1 100644
--- a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1300"
+   LastUpgradeVersion = "1430"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

From 27410b8eadc7c203a09c22e126cb59c2d9b5f3aa Mon Sep 17 00:00:00 2001
From: Likho <likhojiba@gmail.com>
Date: Fri, 15 Mar 2024 20:02:14 +0200
Subject: [PATCH 44/57] Change coin ordering

---
 lib/utilities/enums/coin_enum.dart | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/utilities/enums/coin_enum.dart b/lib/utilities/enums/coin_enum.dart
index 0356c1e7c..abb6985ea 100644
--- a/lib/utilities/enums/coin_enum.dart
+++ b/lib/utilities/enums/coin_enum.dart
@@ -13,10 +13,10 @@ import 'package:stackwallet/utilities/constants.dart';
 
 enum Coin {
   bitcoin,
-  bitcoinFrost,
   monero,
   banano,
   bitcoincash,
+  bitcoinFrost,
   dogecoin,
   eCash,
   epicCash,
@@ -36,8 +36,8 @@ enum Coin {
   ///
 
   bitcoinTestNet,
-  bitcoinFrostTestNet,
   bitcoincashTestnet,
+  bitcoinFrostTestNet,
   dogecoinTestNet,
   firoTestNet,
   litecoinTestNet,

From 1a5e31d046986a508130bb6af1463a26b15ffc81 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Fri, 15 Mar 2024 18:57:30 -0500
Subject: [PATCH 45/57] add missing send view args option

---
 lib/route_generator.dart | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/lib/route_generator.dart b/lib/route_generator.dart
index 4eb906b8a..e4d188cdf 100644
--- a/lib/route_generator.dart
+++ b/lib/route_generator.dart
@@ -1861,7 +1861,19 @@ class RouteGenerator {
               name: settings.name,
             ),
           );
+        } else if (args is ({Coin coin, String walletId})) {
+          return getRoute(
+            shouldUseMaterialRoute: useMaterialPageRoute,
+            builder: (_) => SendView(
+              walletId: args.walletId,
+              coin: args.coin,
+            ),
+            settings: RouteSettings(
+              name: settings.name,
+            ),
+          );
         }
+
         return _routeError("${settings.name} invalid args: ${args.toString()}");
 
       case TokenSendView.routeName:

From c1b9ba085fef6e7a8d343cdc11aee6d55b7b157f Mon Sep 17 00:00:00 2001
From: likho <likhojiba@gmail.com>
Date: Mon, 18 Mar 2024 17:49:11 +0200
Subject: [PATCH 46/57] In the tx list only process txs that are not anon

---
 lib/wallets/wallet/impl/particl_wallet.dart | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/lib/wallets/wallet/impl/particl_wallet.dart b/lib/wallets/wallet/impl/particl_wallet.dart
index 89faa8950..36ab9c83b 100644
--- a/lib/wallets/wallet/impl/particl_wallet.dart
+++ b/lib/wallets/wallet/impl/particl_wallet.dart
@@ -191,10 +191,9 @@ class ParticlWallet extends Bip39HDWallet
         final List<String> addresses = [];
         String valueStringSats = "0";
         OutpointV2? outpoint;
-
         final coinbase = map["coinbase"] as String?;
-
-        if (coinbase == null) {
+        final txType = map['type'] as String?;
+        if (coinbase == null && txType == null) {
           // Not a coinbase (ie a typical input).
           final txid = map["txid"] as String;
           final vout = map["vout"] as int;

From 11136d3d140d6f74c64d892dcca16a5cdd1e70bf Mon Sep 17 00:00:00 2001
From: likho <likhojiba@gmail.com>
Date: Mon, 18 Mar 2024 17:50:04 +0200
Subject: [PATCH 47/57] Revert "In the tx list only process txs that are not
 anon"

This reverts commit c1b9ba085fef6e7a8d343cdc11aee6d55b7b157f.
---
 lib/wallets/wallet/impl/particl_wallet.dart | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/wallets/wallet/impl/particl_wallet.dart b/lib/wallets/wallet/impl/particl_wallet.dart
index 36ab9c83b..89faa8950 100644
--- a/lib/wallets/wallet/impl/particl_wallet.dart
+++ b/lib/wallets/wallet/impl/particl_wallet.dart
@@ -191,9 +191,10 @@ class ParticlWallet extends Bip39HDWallet
         final List<String> addresses = [];
         String valueStringSats = "0";
         OutpointV2? outpoint;
+
         final coinbase = map["coinbase"] as String?;
-        final txType = map['type'] as String?;
-        if (coinbase == null && txType == null) {
+
+        if (coinbase == null) {
           // Not a coinbase (ie a typical input).
           final txid = map["txid"] as String;
           final vout = map["vout"] as int;

From ad4974e0725ad960a81bed330722d12ffa713682 Mon Sep 17 00:00:00 2001
From: likho <likhojiba@gmail.com>
Date: Mon, 18 Mar 2024 17:52:40 +0200
Subject: [PATCH 48/57] Ignore anon type txs when syncing wallet

---
 lib/wallets/wallet/impl/particl_wallet.dart | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/wallets/wallet/impl/particl_wallet.dart b/lib/wallets/wallet/impl/particl_wallet.dart
index 89faa8950..e0d5bc9c2 100644
--- a/lib/wallets/wallet/impl/particl_wallet.dart
+++ b/lib/wallets/wallet/impl/particl_wallet.dart
@@ -193,8 +193,8 @@ class ParticlWallet extends Bip39HDWallet
         OutpointV2? outpoint;
 
         final coinbase = map["coinbase"] as String?;
-
-        if (coinbase == null) {
+        final txType = map['type'] as String?;
+        if (coinbase == null && txType == null) {
           // Not a coinbase (ie a typical input).
           final txid = map["txid"] as String;
           final vout = map["vout"] as int;

From 85cdb0cc096cb9c9437bc27d06227ccdd5cbafeb Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Wed, 20 Mar 2024 15:33:25 -0500
Subject: [PATCH 49/57] Default to using `double.parse` in `electrum_adapter`

`catch` with the(ir custom) original `_parseDouble`
---
 pubspec.lock | 4 ++--
 pubspec.yaml | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/pubspec.lock b/pubspec.lock
index 7b9adb7c9..56a538c7d 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -528,8 +528,8 @@ packages:
     dependency: "direct main"
     description:
       path: "."
-      ref: "2897c6448e131241d4d91fe23fdab83305134225"
-      resolved-ref: "2897c6448e131241d4d91fe23fdab83305134225"
+      ref: "9e9441fc1e9ace8907256fff05fe2c607b0933b6"
+      resolved-ref: "9e9441fc1e9ace8907256fff05fe2c607b0933b6"
       url: "https://github.com/cypherstack/electrum_adapter.git"
     source: git
     version: "3.0.0"
diff --git a/pubspec.yaml b/pubspec.yaml
index fd19a216e..940682650 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -179,7 +179,7 @@ dependencies:
   electrum_adapter:
     git:
       url: https://github.com/cypherstack/electrum_adapter.git
-      ref: 2897c6448e131241d4d91fe23fdab83305134225
+      ref: 9e9441fc1e9ace8907256fff05fe2c607b0933b6
   stream_channel: ^2.1.0
 
 dev_dependencies:

From 5e7c9ad65bd4d6b544e8a6ec5e7ba58282ba353c Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Wed, 20 Mar 2024 16:04:28 -0500
Subject: [PATCH 50/57] add FROST enabled pref

a bool
toggle from hidden settings menu
---
 .../global_settings_view/hidden_settings.dart | 32 ++++++++++++++++++-
 lib/utilities/prefs.dart                      | 22 +++++++++++++
 2 files changed, 53 insertions(+), 1 deletion(-)

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 6cc47a0d4..ec96afde5 100644
--- a/lib/pages/settings_views/global_settings_view/hidden_settings.dart
+++ b/lib/pages/settings_views/global_settings_view/hidden_settings.dart
@@ -10,6 +10,7 @@
 
 import 'dart:async';
 
+import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:flutter_svg/flutter_svg.dart';
@@ -215,7 +216,6 @@ class HiddenSettings extends StatelessWidget {
                             ),
                           );
                         }),
-
                         const SizedBox(
                           height: 12,
                         ),
@@ -252,6 +252,36 @@ class HiddenSettings extends StatelessWidget {
                             }
                           },
                         ),
+                        Consumer(
+                          builder: (_, ref, __) {
+                            return GestureDetector(
+                              onTap: () async {
+                                ref
+                                        .read(prefsChangeNotifierProvider)
+                                        .frostEnabled =
+                                    !(ref
+                                        .read(prefsChangeNotifierProvider)
+                                        .frostEnabled);
+                                if (kDebugMode) {
+                                  print(
+                                      "FROST enabled: ${ref.read(prefsChangeNotifierProvider).frostEnabled}");
+                                }
+                              },
+                              child: RoundedWhiteContainer(
+                                child: Text(
+                                  "Toggle FROST multisig",
+                                  style: STextStyles.button(context).copyWith(
+                                      color: Theme.of(context)
+                                          .extension<StackColors>()!
+                                          .accentColorDark),
+                                ),
+                              ),
+                            );
+                          },
+                        ),
+                        const SizedBox(
+                          height: 12,
+                        ),
                         Consumer(
                           builder: (_, ref, __) {
                             return GestureDetector(
diff --git a/lib/utilities/prefs.dart b/lib/utilities/prefs.dart
index 07726bdf1..8fbbbf069 100644
--- a/lib/utilities/prefs.dart
+++ b/lib/utilities/prefs.dart
@@ -68,6 +68,7 @@ class Prefs extends ChangeNotifier {
       await _setMaxDecimals();
       _useTor = await _getUseTor();
       _fusionServerInfo = await _getFusionServerInfo();
+      _frostEnabled = await _getFrostEnabled();
 
       _initialized = true;
     }
@@ -1008,4 +1009,25 @@ class Prefs extends ChangeNotifier {
 
     return actualMap;
   }
+
+  // FROST multisig
+
+  bool _frostEnabled = false;
+
+  bool get frostEnabled => _frostEnabled;
+
+  set frostEnabled(bool frostEnabled) {
+    if (_frostEnabled != frostEnabled) {
+      DB.instance.put<dynamic>(
+          boxName: DB.boxNamePrefs, key: "frostEnabled", value: frostEnabled);
+      _frostEnabled = frostEnabled;
+      notifyListeners();
+    }
+  }
+
+  Future<bool> _getFrostEnabled() async {
+    return await DB.instance.get<dynamic>(
+            boxName: DB.boxNamePrefs, key: "frostEnabled") as bool? ??
+        false;
+  }
 }

From 0f4fb8378fbbbeeabb5ae963528792acbd31300f Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Wed, 20 Mar 2024 16:08:33 -0500
Subject: [PATCH 51/57] use pref to cull frost things if not enabled

---
 .../add_wallet_view/add_wallet_view.dart                 | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/lib/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart b/lib/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart
index 32e1b618c..3d6c4b8df 100644
--- a/lib/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart
+++ b/lib/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart
@@ -134,9 +134,18 @@ class _AddWalletViewState extends ConsumerState<AddWalletView> {
       _coins.remove(Coin.wownero);
     }
 
+    // Remove FROST from the list of coins based on our frostEnabled preference.
+    if (!ref.read(prefsChangeNotifierProvider).frostEnabled) {
+      _coins.remove(Coin.bitcoinFrost);
+    }
+
     coinEntities.addAll(_coins.map((e) => CoinEntity(e)));
 
     if (ref.read(prefsChangeNotifierProvider).showTestNetCoins) {
+      if (!ref.read(prefsChangeNotifierProvider).frostEnabled) {
+        _coinsTestnet.remove(Coin.bitcoinFrostTestNet);
+      }
+
       coinEntities.addAll(_coinsTestnet.map((e) => CoinEntity(e)));
     }
 

From 96c1976d7874aea35e48a06110b9b412afced255 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Wed, 20 Mar 2024 16:16:44 -0500
Subject: [PATCH 52/57] use same back button widget on mobile as on desktop

---
 .../global_settings_view/hidden_settings.dart | 41 +++++++++----------
 1 file changed, 19 insertions(+), 22 deletions(-)

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 ec96afde5..b8b9a9982 100644
--- a/lib/pages/settings_views/global_settings_view/hidden_settings.dart
+++ b/lib/pages/settings_views/global_settings_view/hidden_settings.dart
@@ -23,7 +23,6 @@ import 'package:stackwallet/themes/stack_colors.dart';
 import 'package:stackwallet/utilities/assets.dart';
 import 'package:stackwallet/utilities/constants.dart';
 import 'package:stackwallet/utilities/text_styles.dart';
-import 'package:stackwallet/utilities/util.dart';
 import 'package:stackwallet/widgets/background.dart';
 import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
 import 'package:stackwallet/widgets/onetime_popups/tor_has_been_add_dialog.dart';
@@ -40,27 +39,25 @@ class HiddenSettings extends StatelessWidget {
       child: Scaffold(
         backgroundColor: Theme.of(context).extension<StackColors>()!.background,
         appBar: AppBar(
-          leading: Util.isDesktop
-              ? Padding(
-                  padding: const EdgeInsets.all(8.0),
-                  child: AppBarIconButton(
-                    size: 32,
-                    color: Theme.of(context)
-                        .extension<StackColors>()!
-                        .textFieldDefaultBG,
-                    shadows: const [],
-                    icon: SvgPicture.asset(
-                      Assets.svg.arrowLeft,
-                      width: 18,
-                      height: 18,
-                      color: Theme.of(context)
-                          .extension<StackColors>()!
-                          .topNavIconPrimary,
-                    ),
-                    onPressed: Navigator.of(context).pop,
-                  ),
-                )
-              : Container(),
+          leading: Padding(
+            padding: const EdgeInsets.all(8.0),
+            child: AppBarIconButton(
+              size: 32,
+              color: Theme.of(context)
+                  .extension<StackColors>()!
+                  .textFieldDefaultBG,
+              shadows: const [],
+              icon: SvgPicture.asset(
+                Assets.svg.arrowLeft,
+                width: 18,
+                height: 18,
+                color: Theme.of(context)
+                    .extension<StackColors>()!
+                    .topNavIconPrimary,
+              ),
+              onPressed: Navigator.of(context).pop,
+            ),
+          ),
           title: Text(
             "Dev options",
             style: STextStyles.navBarTitle(context),

From d9163a2bbd72d1638386737a713b586d49e3f050 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Wed, 20 Mar 2024 16:48:55 -0500
Subject: [PATCH 53/57] hide tor stacy buttons

---
 .../global_settings_view/hidden_settings.dart | 87 +++++++++----------
 1 file changed, 42 insertions(+), 45 deletions(-)

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 b8b9a9982..915d48552 100644
--- a/lib/pages/settings_views/global_settings_view/hidden_settings.dart
+++ b/lib/pages/settings_views/global_settings_view/hidden_settings.dart
@@ -14,8 +14,6 @@ import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:flutter_svg/flutter_svg.dart';
-import 'package:hive_flutter/hive_flutter.dart';
-import 'package:stackwallet/db/hive/db.dart';
 import 'package:stackwallet/notifications/show_flush_bar.dart';
 import 'package:stackwallet/providers/global/debug_service_provider.dart';
 import 'package:stackwallet/providers/providers.dart';
@@ -25,7 +23,6 @@ import 'package:stackwallet/utilities/constants.dart';
 import 'package:stackwallet/utilities/text_styles.dart';
 import 'package:stackwallet/widgets/background.dart';
 import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
-import 'package:stackwallet/widgets/onetime_popups/tor_has_been_add_dialog.dart';
 import 'package:stackwallet/widgets/rounded_white_container.dart';
 
 class HiddenSettings extends StatelessWidget {
@@ -174,48 +171,48 @@ class HiddenSettings extends StatelessWidget {
                         const SizedBox(
                           height: 12,
                         ),
-                        Consumer(builder: (_, ref, __) {
-                          return GestureDetector(
-                            onTap: () async {
-                              await showOneTimeTorHasBeenAddedDialogIfRequired(
-                                context,
-                              );
-                            },
-                            child: RoundedWhiteContainer(
-                              child: Text(
-                                "Test tor stacy popup",
-                                style: STextStyles.button(context).copyWith(
-                                    color: Theme.of(context)
-                                        .extension<StackColors>()!
-                                        .accentColorDark),
-                              ),
-                            ),
-                          );
-                        }),
-                        const SizedBox(
-                          height: 12,
-                        ),
-                        Consumer(builder: (_, ref, __) {
-                          return GestureDetector(
-                            onTap: () async {
-                              final box = await Hive.openBox<bool>(
-                                  DB.boxNameOneTimeDialogsShown);
-                              await box.clear();
-                            },
-                            child: RoundedWhiteContainer(
-                              child: Text(
-                                "Reset tor stacy popup",
-                                style: STextStyles.button(context).copyWith(
-                                    color: Theme.of(context)
-                                        .extension<StackColors>()!
-                                        .accentColorDark),
-                              ),
-                            ),
-                          );
-                        }),
-                        const SizedBox(
-                          height: 12,
-                        ),
+                        // Consumer(builder: (_, ref, __) {
+                        //   return GestureDetector(
+                        //     onTap: () async {
+                        //       await showOneTimeTorHasBeenAddedDialogIfRequired(
+                        //         context,
+                        //       );
+                        //     },
+                        //     child: RoundedWhiteContainer(
+                        //       child: Text(
+                        //         "Test tor stacy popup",
+                        //         style: STextStyles.button(context).copyWith(
+                        //             color: Theme.of(context)
+                        //                 .extension<StackColors>()!
+                        //                 .accentColorDark),
+                        //       ),
+                        //     ),
+                        //   );
+                        // }),
+                        // const SizedBox(
+                        //   height: 12,
+                        // ),
+                        // Consumer(builder: (_, ref, __) {
+                        //   return GestureDetector(
+                        //     onTap: () async {
+                        //       final box = await Hive.openBox<bool>(
+                        //           DB.boxNameOneTimeDialogsShown);
+                        //       await box.clear();
+                        //     },
+                        //     child: RoundedWhiteContainer(
+                        //       child: Text(
+                        //         "Reset tor stacy popup",
+                        //         style: STextStyles.button(context).copyWith(
+                        //             color: Theme.of(context)
+                        //                 .extension<StackColors>()!
+                        //                 .accentColorDark),
+                        //       ),
+                        //     ),
+                        //   );
+                        // }),
+                        // const SizedBox(
+                        //   height: 12,
+                        // ),
                         Consumer(
                           builder: (_, ref, __) {
                             if (ref.watch(prefsChangeNotifierProvider

From e597045db49626f96f233cb7eff27ce8344e803a Mon Sep 17 00:00:00 2001
From: Diego Salazar <diego@cypherstack.com>
Date: Mon, 25 Mar 2024 17:33:53 -0600
Subject: [PATCH 54/57] Update version (v1.10.4, build 216)

---
 pubspec.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pubspec.yaml b/pubspec.yaml
index 940682650..0ddcae808 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.10.3+215
+version: 1.10.4+216
 
 environment:
   sdk: ">=3.0.2 <4.0.0"

From 22504c42a9acb58dd4327e8bec1b6759c68aea62 Mon Sep 17 00:00:00 2001
From: sneurlax <sneurlax@gmail.com>
Date: Thu, 28 Mar 2024 15:54:46 -0500
Subject: [PATCH 55/57] do not change rust version in parallel

---
 scripts/android/build_all.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/android/build_all.sh b/scripts/android/build_all.sh
index f42a6c5d3..28e56acd4 100755
--- a/scripts/android/build_all.sh
+++ b/scripts/android/build_all.sh
@@ -12,7 +12,7 @@ mkdir -p build
 
 (cd ../../crypto_plugins/flutter_liblelantus/scripts/android && ./build_all.sh ) &
 (cd ../../crypto_plugins/flutter_libepiccash/scripts/android && ./install_ndk.sh && ./build_opensll.sh && ./build_all.sh )  &
-(cd ../../crypto_plugins/flutter_libmonero/scripts/android/ && ./build_all.sh  ) &
+(cd ../../crypto_plugins/flutter_libmonero/scripts/android/ && ./build_all.sh  ) &&
 set_rust_to_1720 &
 (cd ../../crypto_plugins/frostdart/scripts/android && ./build_all.sh ) &
 

From 98c8b4dc6ace8141e670c5ce54b706de41d412e1 Mon Sep 17 00:00:00 2001
From: Kronk <49569383+Kronkmeister@users.noreply.github.com>
Date: Mon, 1 Apr 2024 17:29:22 +0200
Subject: [PATCH 56/57] Update block_explorers.dart  (change eCash default
 explorer)

Changed the eCash block explorer from bitcoinabc.org to the default explorer.e.cash.
---
 lib/utilities/block_explorers.dart | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/utilities/block_explorers.dart b/lib/utilities/block_explorers.dart
index 9f3e92c5d..941f7c599 100644
--- a/lib/utilities/block_explorers.dart
+++ b/lib/utilities/block_explorers.dart
@@ -31,7 +31,7 @@ Uri getDefaultBlockExplorerUrlFor({
     case Coin.dogecoin:
       return Uri.parse("https://chain.so/tx/DOGE/$txid");
     case Coin.eCash:
-      return Uri.parse("https://explorer.bitcoinabc.org/tx/$txid");
+      return Uri.parse("https://explorer.e.cash/tx/$txid");
     case Coin.dogecoinTestNet:
       return Uri.parse("https://chain.so/tx/DOGETEST/$txid");
     case Coin.epicCash:

From 9eb6aef23621d37797f68e02b2bc85c055ed70d2 Mon Sep 17 00:00:00 2001
From: Diego Salazar <diego@cypherstack.com>
Date: Tue, 2 Apr 2024 17:47:54 -0600
Subject: [PATCH 57/57] Update version (v1.10.4, build 217)

---
 pubspec.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pubspec.yaml b/pubspec.yaml
index 0ddcae808..0daa6d065 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.10.4+216
+version: 1.10.4+217
 
 environment:
   sdk: ">=3.0.2 <4.0.0"